こんにちは。たかとです。
Shopifyの案件の中で、商品グループAと商品グループBを同時に購入できないようにしたいと言われ、Limitsifyなどの購入制限系のアプリを検討したりしてなんとか実装できたので共有します。
結論から言うと、現状でアプリでそんな感じの機能があるものがなかったので独自言語であるLiquidを使ってカスタマイズしました。実際に書いたコードを載せつつ解説していきます。
やりたいこと
商品グループAと商品グループBを同時に購入できないようにします。
例えばコレクションで「通常商品」と「限定商品」で別れている時に、通常商品同士や限定商品同士であればいくつでも買えるけど、通常商品と限定商品を同時に購入させたくない時などに使えます。
特定の商品の組み合わせ時に購入禁止にする方法
大枠の流れとしては、下記になります。
実際に書いたコード
{%- comment -%}
---------------------------------------------------------------------
同時購入禁止
---------------------------------------------------------------------
{%- endcomment -%}
{%- for item in cart.items -%}
{%- if item.product.type == '商品グループA' -%}
{% assign typeA = true %}
{%- endif -%}
{%- if item.product.type == '商品グループB' -%}
{% assign typeB = true %}
{%- endif -%}
{%- endfor -%}
{%- unless typeA == true and typeB == true -%}
購入ボタン
{%- endunless -%}
商品グループAに属する商品と商品グループBに属する商品が同時にカートにないに存在する時、購入ボタンを表示しないようにしています。商品グループの判別は今回は商品タイプによって行ってます。
ちなみにコードを書いたファイルはDebutの場合、「cart-template.liquid」でした。
コード解説
①カート内の商品を取得
Shopifyにはカート内の情報を取得できるコードがあるのでそれを使って商品情報を取得していきます。
{%- for item in cart.items -%}
この文では「cart.items」で得られる商品情報を「for」で吐き出してます。
ちなみに「cart.items」を使うとline_itemオブジェクトを得られますが、他にも「cart.item_count」を使えばカート内のアイテムの数を、「cart.total_price」を使えばカート内のすべてのアイテムの合計価格を返せるなどできます。
cartオブジェクトに関しては詳しくは下記の公式ドキュメントで解説されています。
②商品の商品タイプを取得
カート内のアイテム一覧を得たら、次はアイテムが属するグループを判定します。
グループ判定に関してはいくつか方法があり、タグを使う方法、コレクションを使う方法、商品タイプを使う方法がありますが、今回は商品タイプで判定していきます。
下記は商品タイプを出力するためのコードになります。
{%- for item in cart.items -%}
{{ item.product.type }}
{%- endfor -%}
実は「cart.items」だけだと取得できるのはline_itemアイテムの情報で、製品自体の情報を取りたい場合「cart.items.product」と繋げる必要があります。これによって製品オブジェクトの属性が使えるようになります。
製品オブジェクトでは商品タイプの他に商品タイトルや説明、価格など様々な値が取れます。
line_itemオブジェクトに関する詳しい情報は下記
製品オブジェクトに関する詳しい情報は下記
③特定の商品タイプが混在しているかどうか判定
商品タイプが取得できたら、特定の商品タイプが混在しているかどうか判定します。
判定のためにループの中でif文で条件分岐して、当てはまってる場合には変数にtrueを入れるというプログラムを書いていきます。
{%- for item in cart.items -%}
{%- if item.product.type == '商品グループA' -%}
{% assign typeA = true %}
{%- endif -%}
{%- if item.product.type == '商品グループB' -%}
{% assign typeB = true %}
{%- endif -%}
{%- endfor -%}
基本的には上記で説明したとおりで、もし「item.product.type」の名前が「商品グループA」なら「typeA」をtrueにするという構文です。
「assign」はLiquid上での変数の定義に使います。
イメージとしてはfor文の中を一個ずつぐるぐる情報が回っていって、if文の条件に当てはまるときだけifの中に入っていって変数を定義するという感じです!
④購入ボタンを非表示にする
最後に条件に当てはまる時に購入ボタンを非表示にするプログラムを書きます。
{%- for item in cart.items -%}
{%- if item.product.type == '商品グループA' -%}
{% assign typeA = true %}
{%- endif -%}
{%- if item.product.type == '商品グループB' -%}
{% assign typeB = true %}
{%- endif -%}
{%- endfor -%}
{%- unless typeA == true and typeB == true -%}
購入ボタン
{%- endunless -%}
肝は下記の部分で、「typeA」と「typeB」どちらもtrueの場合、購入ボタンを表示させないという構文です。
{%- unless typeA == true and typeB == true -%}
購入ボタン
{%- endunless -%}
unlessはifの反対の意味で、当てはまる時は出力しないというツンデレみたいなやつですね。はい。
非表示にするボタン
Debutの場合の解説になりますが、非表示にしたのは下記2つのコードです。
<input type="submit" name="checkout" class="cart__submit btn btn--small-wide" value="{{ 'cart.general.checkout' | t }}">
<div class="additional-checkout-buttons">{{ content_for_additional_checkout_buttons }}</div>
いっぺんにまとめて非表示にすると、不具合が起きるので、それぞれの上下に「unless」をかけていくイメージになります。
忠告文を出力させたい場合
購入ボタンを消すだけでなく忠告文も出したい場合は下記のコードを任意の場所に追加します。
{%- if masuku == true and yoyaku == true -%}
<p>
【注意】〇〇と〇〇を同時に購入することはできません。<br>
お手数ですがカートからどちらかの商品を削除してページを<input class="no-purchase_reload" type="button" value="再読み込み" onclick="window.location.reload();" />してください。
</p>
{%- endif -%}
ちなみに変数定義の文より上に書いても反応しないので注意です。
クラスを与えてCSSでスタイリングしたり、jsを使ってポップアップにしてもいいと思います。
非同期通信でユーザビリティを上げる
今回は商品削除後に一度リロードしてもらうことでカート情報をリセットして購入ボタンを出すかどうかの判定をもう一度行う仕様にしてますが、ユーザーのことを考えたら商品情報が更新されたタイミングで購入ボタンを出すかどうかの判定も行えたほうが良いです。
こちらはAJAXを利用することで実現可能だとは思いますが、僕の実力不足と納期の関係で今回はここまでは実装できませんでした。もしこの記事を読んでくれた方の中でここまでの実装を行えた方がいましたら、コメントかTwitterのDMでやり方を教えていただけると嬉しいです!
余談:商品タイプではなく商品タグで判定する方法
今回の解説では商品タイプで商品のグループ分けを判定しましたが、普通であれば商品タグで判定することのほうが多そうなので、こちらもサクッと解説します。ちなみに実環境で試してないので動かなかったらごめんなさい笑
{%- for item in cart.items -%}
{%- for tag in item.product.tags -%}
{%- if tag == '商品グループA' -%}
{% assign typeA = true %}
{%- endif -%}
{%- if tag == '商品グループB' -%}
{% assign typeB = true %}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
タグやコレクションは複数指定可能な分、一つの商品のタグを取得しても配列で帰ってきます。なのでforループの二重がけをしてタグも一個一個順に回していって、if文で判定する感じになります。
ちなみにコレクションでも同じやり方になります。
これ以下のコードは商品タイプで判定した時と同じになります。
Shopifyのテーマ開発を学ぶ
今回はShopifyのLiquidを使った開発でしたが、よりShopifyについて深く知りたいという場合はテーマの開発を経験してみるのもいいかと思います。一度0から作り上げることでより理解が深まると思います。
おすすめはこちらです。
Shopifyで特定の商品の組み合わせ時に購入禁止にする方法まとめ
今回はShopifyで特定の商品の組み合わせ時に購入禁止にする方法についてまとめていきました。
Shopifyの構築は基本的にやりたいことを聞いて、実現する方法を調べての繰り返しになることが多いですが、今回のこれは得に情報が出てこなくて手こずりました。購入制限系のアプリだと「Limitsify」が有名ですが、こちらにも今回のような機能はなかったので、仕方なくコードを書いた感じです。
コード汚いとか、もっとこうやったほうが良いとか、このアプリでできるなどあれば教えていただけるとありがたいです!ぜひTwitterのDMまで。
コメント