BLOGShopifyカスタマイズ事例6:ショッパーをカートに追加するボタン

POST DATE:2025/04/04
Shopifyカスタマイズ事例6:ショッパーをカートに追加するボタン
ECの利益向上に繋がるShopifyカスタマイズ事例6
弊社ではShopifyでの制作をはじめ、様々なECサイトの制作のご依頼をいただいています。
特に、現在はECサイトの売上をUPしつつ効率的な運用を行いたい、月商を1,000万円以上の規模に成長させたい、月商億円規模のサイトを安全にシステム移管したい等、「利益を上げる知識」と「システム構築の知識」を総合的に持つことで解決できるご要望を、ワンストップで実現することを得意としています。
その現場の中で行ってきたカスタマイズ事例について、解説します。
事例6:ショッパーを追加するボタン
カスタマイズの背景
Shopifyはその開発の柔軟性と堅牢かつ使いやすいシステムであることから、純粋なEC制作にとどまらず、食品のテイクアウト用のシステムなどにも応用して利用することが可能です。今回のカスタマイズでは、食品テイクアウトシステムを作成した際に手渡し用紙袋(ショッパー)を追加購入できる仕組みを設けた際の方法を解説します。
カスタマイズ前の課題
- ショッパーは無料ではなく、価格設定する必要があり、また枚数の指定も必要だった。
- ショッパー自体を在庫管理する必要があり、商品登録する必要があった。
- 商品ページおよび商品一覧ページに、別の商品をカートに入れる機能はデフォルトでは存在しなかった。
- デザインに合わせた実装が必要だったためアプリを利用しない実装が必要だった。
上記の課題から、ショッパーの商品登録とともに、テーマへのLiquid開発での課題解決に取り組みました。
カスタマイズでの要件・解決案
- 商品詳細・商品一覧、どちらにも実装できるように
- 商品一覧で多数の商品が並んでいても、購入する商品に基づいたショッパーであることがわかるように調整
- 数量選択に対応
- サイズ違いのバリエーション選択に対応
- アプリを利用せず、liquidコードで設置
実装方法
具体的に行った実装方法は下記のような方法を利用しています。
※各コードは例であり、機構を組み込むサンプルのため、あくまで機構づくりの参考として記載しています。
全体Liquidコード
このコードを、liquidコードとして用意し、商品一覧・商品詳細などの、商品ループに組み込むことで、ショッパーを数量やバリエーションを選択して追加できるように実装できます。
{%- assign option_product = all_products["shopper-s"] -%} <div id="id_{{product.id}}{{option_product.id}}" class="option_item_box"> <div class="option_item_box_inner"> <div class="option_item_image"> {% if option_product.images.size > 1 %} <div class="swiper option_images"> <div class="swiper-wrapper"> {% for image in option_product.images %} <div class="option_images_item swiper-slide"><img src="{{ image.src | img_url: '600x600' }}" alt="{{ image.alt | escape }}" width="160" height="160"></div> {% endfor %} </div> </div> <div class="mode_item_control mode_item_slider_btn"> <div class="button-prev"><img src="{{ 'p_arrow_prev.svg' | asset_url }}" alt="" width="30"></div> <div class="button-next"><img src="{{ 'p_arrow_next.svg' | asset_url }}" alt="" width="30"></div> </div> {% else %} <img src="{{ option_product.featured_image | img_url: '600x600' }}" loading="lazy"> {% endif %} </div> <div class="option_info"> <div id="op_name_{{ option_product.id }}" class="option_name">{{ option_product.title }}</div> <div class="oc_item_price">{% if option_product.price_varies %}{{option_product.price_min | money}}〜{{option_product.price_max | money}}{% else %}{{option_product.price | money}}{% endif %}<small>(税込)</small></div> <div class="option_selector"> <div class="option_selector_pt1"> <p class="option_selector_name">数量</p> <div class="option_select_wrap"> <select id="op_quantity_{{product.id}}{{ option_product.id }}"> {% for i in (1..5) %} <option value="{{- forloop.index -}}">{{- forloop.index -}}</option> {% endfor %} </select> </div> </div> <div class="option_selector_pt2"> <p class="option_selector_name">サイズ</p> <div class="option_select_wrap"> <select id="op_id_{{product.id}}{{option_product.id}}"> {% for variant in option_product.variants %} <option value="{{variant.id}}">{{variant.title}}({{variant.price | money}})</option> {% endfor %} </select> </div> </div> </div> </div> <div class="option_cart_btn_box"> <button class="add_cart_btn add-to-cart-button add-to-cart-op" onclick="addToCartWithProperties({{ option_product.selected_or_first_available_variant.id }},'#op_quantity_{{product.id}}{{ option_product.id }}','#op_id_{{product.id}}{{ option_product.id }}','{{ product.title }}', this)">カートに入れる</button> </div> </div> </div>
コード解説
1. 関連商品(ショッパー)の呼び出し
{%- assign option_product = all_products["shopper-s"] -%}
Shopifyのall_productsを使い、ハンドル(shopper-s)でShopperの商品オブジェクトを取得しています。
・all_products[“shopper-s”] の “shopper-s”は実際のショッパー商品のハンドルに置き換えてください。
・取得した商品オブジェクトを option_productに代入することで、以降のHTML内で簡単に参照できるようになります。
2. カスタマイズ用のHTML枠とIDの付与
<div id="id_{{product.id}}{{option_product.id}}" class="option_item_box"> <div class="option_item_box_inner"> ... </div> </div>
id=”id_{{product.id}}{{option_product.id}}” という固有のIDを付与するように設定しています。
メイン商品の product.id と追加商品の option_product.id を組み合わせることで、重複しないIDを生成することで、商品一覧(collection)などにおいてもそれぞれの商品で稼働するように設定しています。
class=”option_item_box”はスタイリングのためのクラス名です。CSSでレイアウトを調整できます。
3. 画像表示
{% if option_product.images.size > 1 %} <div class="swiper option_images"> <div class="swiper-wrapper"> {% for image in option_product.images %} <div class="option_images_item swiper-slide"> <img src="{{ image.src | img_url: '600x600' }}" alt="{{ image.alt | escape }}" width="160" height="160"> </div> {% endfor %} </div> </div> <div class="mode_item_control mode_item_slider_btn"> <div class="button-prev"><img src="{{ 'p_arrow_prev.svg' | asset_url }}" alt="" width="30"></div> <div class="button-next"><img src="{{ 'p_arrow_next.svg' | asset_url }}" alt="" width="30"></div> </div> {% else %} <img src="{{ option_product.featured_image | img_url: '600x600' }}" loading="lazy"> {% endif %}
option_product.images.size > 1 で画像が複数ある場合と1枚だけの場合で表示を切り替えています。
複数画像がある場合は、Swiperのライブラリを使って、横スワイプで画像を切り替えられるUIを想定しています。
1枚しかない場合は通常のimgタグで1枚の画像を表示しています。
4. 商品名と価格表示
<div id="op_name_{{ option_product.id }}" class="option_name">{{ option_product.title }}</div> <div class="oc_item_price"> {% if option_product.price_varies %} {{option_product.price_min | money}}〜{{option_product.price_max | money}} {% else %} {{option_product.price | money}} {% endif %} <small>(税込)</small> </div>
ここではショッパーの「商品タイトル」と「価格」を表示しています。
価格がバリエーションによって異なる場合は、price_min と price_max を「〜」で表示し、価格が変わらない場合は、一律の価格を表示するように条件分岐しています。
また、ShopifyのLiquidフィルターmoneyで、通貨フォーマットに変換して表示しています。
5. バリエーション選択(数量 & サイズ)
<div class="option_selector"> <div class="option_selector_pt1"> <p class="option_selector_name">数量</p> <div class="option_select_wrap"> <select id="op_quantity_{{product.id}}{{ option_product.id }}"> {% for i in (1..5) %} <option value="{{- forloop.index -}}">{{- forloop.index -}}</option> {% endfor %} </select> </div> </div> <div class="option_selector_pt2"> <p class="option_selector_name">サイズ</p> <div class="option_select_wrap"> <select id="op_id_{{product.id}}{{option_product.id}}"> {% for variant in option_product.variants %} <option value="{{variant.id}}">{{variant.title}}({{variant.price | money}})</option> {% endfor %} </select> </div> </div> </div>
数量(1〜5)を選択するセレクトボックスと、バリエーション(サイズなど)を選択するセレクトボックスを配置します。
※セレクトボックスにすることで、ショッパーの大量の購入を抑制しています。
id=”op_quantity_{{product.id}}{{ option_product.id }}” と id=”op_id_{{product.id}}{{option_product.id}}” を付与することで、後のJS処理で値を取得しやすくしています。
{% for i in (1..5) %} で 1〜5 までのループを生成して、数量オプションを動的に追加します。
バリエーション部分は、option_product.variants をループすることで、各バリエーションのIDやタイトル、価格を取得しています。
6. カートに追加するボタン
<div class="option_cart_btn_box"> <button class="add_cart_btn add-to-cart-button add-to-cart-op" onclick="addToCartWithProperties({{ option_product.selected_or_first_available_variant.id }},'#op_quantity_{{product.id}}{{ option_product.id }}','#op_id_{{product.id}}{{ option_product.id }}','{{ product.title }}', this)" > カートに入れる </button> </div>
onclick イベントで、addToCartWithProperties() というJavaScript関数を呼び出しています。
- 第一引数には、ショッパー商品の 初期バリエーションID (selected_or_first_available_variant.id) を渡しています。
- 第二・第三引数には、先ほどIDを付与したセレクトボックス(数量・バリエーション)のIDを文字列として渡し、関数内でその値を取得します。
- 第四引数に {{ product.title }} を渡すことで、メイン商品からのアップセルとしての紐付け情報やトラッキングに活用できます。
- this は現在のボタン要素を指し、ボタンのローディング表示切り替えなどを行う際に利用できます。
実際にカート投入するための addToCartWithProperties() 関数は別途JavaScriptとして準備しておき、非同期通信(AJAX)でShopifyの/cart/add.jsにポストする、あるいはフォームを生成してPOSTする、などの実装が必要です。
JavaScript例
// add-to-cart-option function addToCartWithProperties(variantId, quantitySelector, variantSelector, productTitle, button) { // 数量を取得 var quantity = document.querySelector(quantitySelector).value; // バリエーションidを取得 var variant = document.querySelector(variantSelector).value; let formData = { items: [ { id: variant, quantity: parseInt(quantity, 10), // 数量を整数に変換 properties: { '付属対象': productTitle // Line Item Propertyとして商品タイトルを設定 } }, ], }; fetch("/cart/add", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(formData), }) .then(response => { if(response.ok) { updateCartItemCount(); console.log("Item added to cart"); // ボタンのテキストとclassを変更 button.textContent = '追加されています'; button.classList.add('already-in-cart'); // メッセージを追加 var messageElement = document.createElement('p'); messageElement.className = 'op_attention'; messageElement.textContent = 'このオプションは追加済です'; button.insertAdjacentElement('afterend', messageElement); } else { console.error("Response not ok"); } }) .catch((error) => { console.error("Error:", error) }); }
推奨の追加調整
ショッパーの連続購入を防ぐため、カートに追加後は購入ボタンを押せないようにするなどの工夫を入れることで、より実践的な利用が可能です。また、今回のコードではショッパーのハンドルを固定にしていますが、その部分を商品のメタフィールドなどに設定することで、商品それぞれで別のショッパーを付与することも可能となります。
結果
商品のカート追加時にショッパーも購入することができるようになり、ショッパー自体の有料注文と在庫連動が実現できました。また、購入時に枚数を選択できることにより、お持たせ・差し入れなどの用途にも役立っています。
Shopifyでは、LiquidとJavaScriptを組み合わせて柔軟なカスタマイズが可能ですので、ぜひ自社の販促施策に合わせた実装を試してみてください。
お気軽にお問い合わせください
弊社ではECをスタートされる方から、大規模ECの安全なリニューアル、個別のカスタマイズ実装まで幅広く対応可能です。
ご相談がございましたら、お気軽にご連絡ください。