BLOGShopifyカスタマイズ事例3:一人につき1回しか購入できない商品の実現
POST DATE:2025/01/10
Shopifyカスタマイズ事例3:一人につき1回しか購入できない商品の実現
月商1億円超えを支えたShopifyカスタマイズ事例3
弊社ではShopifyでの制作をはじめ、様々なECサイトの制作のご依頼をいただいています。
月商1億円を超えることを目指したECサイト制作、または月商規模が既に億単位を超えているサイトのShopifyリニューアルにあたり、弊社が実際に行ってきたカスタマイズ事例のTipsを定期的にご紹介します。
事例3:マイページの改善カスタマイズ
カスタマイズの背景
一人につき1回しか購入できない商品販売を行うカスタマイズは、買い占め防止や限定感を高めるために多くのECサイトでニーズが高まっている施策です。
弊社でも、日本酒の数量限定販売や化粧品のサンプル販売、インポート商品の特別販売、アーティストの限定グッズ販売など、在庫や販売数に制限のあるアイテムを扱うショップで複数回の実装経験があります。
複数個のまとめ買いを防ぐだけでなく、新規会員登録必須のフローを組み込むことで、登録ユーザーの獲得にも繋げることができ、今後の成長にもプラスに繋げることができます。
また、月額費用のかかるアプリを導入することなく、弊社ではテーマカスタマイズのみで実現できるケースが多く、毎月のコスト負担を抑えながら運用できます。
カスタマイズ前の課題
- アプリでは英語での設定※が必要かつ安定した挙動が難しく、運用に不安がある。
※開発当時は英語のアプリしかありませんでしたが、現在は同機能に特化した日本語のアプリも存在します - クライアントが以前アプリで設定した際、1時間に注文が集中した場合にアプリ側のサーバーが止まってしまい、大きな問題が起こった。
- 所有するポイントの表示が必要だった。
- 購入時のクレームを防ぐため、安定的な稼働が必要だった。
- 月額費用のアップを抑えたい。
- スタッフでも操作できるようにしたい。
上記の課題から、アプリの機能に頼らず、テーマのliquid開発とShopify FLOWを利用した自動化処理での課題解決に取り組みました。
カスタマイズでの要件
上記要件を受けて、弊社では下記の解決要件を用意し、カスタマイズ実装を行いました。
- アプリを利用せずliquid側の開発で実装
- 該当商品を購入するには会員登録を必須と設定
- 該当商品購入の経歴チェックは顧客タグで制御として設定
- 会員かつ対象商品の購入の履歴がない場合のみ購入ができるよう設定
- 何らかの方法でカート内の該当商品数が1を超えている場合や、購入経験がある該当商品が入っている場合は、チェックアウト遷移を不可にする
カスタマイズでの解決案
上記要件を受けて、弊社では下記の解決案を用意し、カスタマイズ実装を行いました。
- 該当商品を指定できるように設定
- Shopify FLOWを利用して、該当商品を買ったときに顧客にタグを付与
- 顧客が会員登録しているときを判定
- 該当商品について、会員ではないと購入できないようにカートボタンをカスタマイズ
- 会員登録している顧客が特有のタグを持っているときには購入できないように調整
- カート画面の該当商品の数量選択をブロック
- ルール外のカート情報の場合はチェックアウトボタンを非表示
実装方法
具体的に行った実装方法は下記のような方法を利用しています。
※各コードは例であり、各パーツへの機構を組み込むサンプルのため、あくまで機構づくりの参考として記載しています。
「お一人様1回のみ」商品を指定
お一人様1回のみの商品を指定するため、その商品のハンドルを確認します。
下記のコードは商品詳細で利用する場合、カートページで利用する場合の条件分岐の例です。
<!-- 商品詳細ページで利用する場合 -->
{% if product.handle == "the-3p-fulfilled-snowboard" %}
{% comment %}該当商品のページの場合{% endcomment %}
{% else %}
{% comment %}}該当商品のページではない場合{% endcomment %}
{% endif %}
<!-- カートページで利用する場合 -->
{%- assign handle_found = false -%}
{%- for item in cart.items -%}
{%- if item.product.handle == "the-3p-fulfilled-snowboard" -%}
{%- assign handle_found = true -%}
{%- break -%}
{%- endif -%}
{%- endfor -%}
{%- if handle_found -%}
<p>特定の商品(the-3p-fulfilled-snowboard)がカート内にあります。</p>
{%- else -%}
<p>特定の商品はカート内にありません。</p>
{%- endif -%}
FLOWを利用し、該当商品を買ったときに顧客にタグを付与
Shopify FLOWを利用して、注文をトリガーにしたタグ付けルールを作成します。
-
注文をFLOW開始のトリガーに設定
-
注文商品の中にハンドル”the-3p-fulfilled-snowboard”が含まれている場合の条件分岐
-
条件に当てはまる場合、顧客にタグ”注文済み_the-3p-fulfilled-snowboard”を追加
顧客が会員登録しているときを判定
{%- if customer -%}
{% comment %}ログイン中{% endcomment %}
{%- else -%}
{% comment %}未ログイン{% endcomment %}
{%- endif -%}
カートボタンの表示条件を調整
該当商品について、会員登録していないと購入できない分岐を作り、さらに顧客が特有のタグ(1回購入したときに付与されるタグ)を持っているときには購入できないように調整します。
また、カートに入っているときにはカートボタンが表示されないように条件分岐、カートに入れた瞬間にも同様の挙動となるようJavascriptを設置します。
{% if product.handle == "the-3p-fulfilled-snowboard" %}
<style>
/* 数量セレクターを非表示 */
.quantity-input {
display: none;
}
</style>
{%- assign product_in_cart = false -%}
{%- for item in cart.items -%}
{%- if item.product.handle == 'the-3p-fulfilled-snowboard' -%}
{%- assign product_in_cart = true -%}
{%- break -%}
{%- endif -%}
{%- endfor -%}
{%- if product_in_cart == true -%}
<p>すでにカートに入っています。</p>
{%- elsif customer -%}
{%- if customer.tags contains "注文済み_the-3p-fulfilled-snowboard" -%}
<p>この商品はお一人様1回のみ購入できます。<br>一度購入した方は購入することができません。</p>
{%- else -%}
{% comment %}元のコードの購入ボタンのみをカスタマイズ{% endcomment %}
{%- form 'product',
product,
id: product_form_id,
class: 'form AddToCartForm',
novalidate: 'novalidate',
data-type: 'add-to-cart-form'
-%}
・・・
{%- if customer -%}
<button
id = "ProductSubmitButton-{{ section_id }}"
type="submit"
name="add"
class="product-form__submit button AddToCartButton"
{% if product.selected_or_first_available_variant.available == false or quantity_rule_soldout %}
disabled
{% endif %}
>カートに入れる</button>
・・・
{%- endform -%}
<script>
document.addEventListener('DOMContentLoaded', function() {
// すべてのカートフォームを取得
var addToCartForms = document.querySelectorAll('.AddToCartForm');
addToCartForms.forEach(function(form) {
form.addEventListener('submit', function(event) {
var formData = new FormData(form);
// Ajaxリクエストで /cart/add.js にPOST
fetch('/cart/add.js', {
method: 'POST',
body: formData,
credentials: 'same-origin',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(function(response) {
// /cart/add.js が 200 以外の場合はエラー扱い
if (!response.ok) {
throw new Error('Error adding item to cart');
}
return response.json();
})
.then(function(data) {
console.log('Successfully added to cart:', data);
// 成功したら、対応するボタンを非表示にする
var button = form.querySelector('.AddToCartButton');
if (button) {
// ボタンを非表示
button.style.display = 'none';
// ボタンの直後にメッセージを追加
button.insertAdjacentHTML('afterend', '<p>すでにカートに入っています。</p>');
}
})
.catch(function(error) {
console.error('Error:', error);
});
});
});
});
</script>
{%- endif -%}
{%- else -%}
<p>購入にはログインが必要です。</p>
<a href="/account/login" class="login-link">ログイン</a>
{%- endif -%}
{% else %}
{% comment %}}元のコードをそのまま実装{% endcomment %}
{% endif %}
カート画面で数量変更ができないように調整
カート画面では、該当商品のみ数量の選択ができないように数量セレクターを非表示に変更します。
<!-- カート画面で該当商品の数量セレクターを非表示 -->
{%- if item.handle != "the-3p-fulfilled-snowboard" -%}
<quantity-input class="quantity cart-quantity">
・・・
</quantity-input>
{%- endif -%}
カート画面でルール外の状態になっている場合は、チェックアウトへの遷移ができないように調整
カート内の該当商品数が1を超える場合や、顧客に購入済みのタグがついているのにカートに入っている場合に購入に進むことができないよう、チェックアウトボタン表示の判定を付与します。
{%- comment -%}
カート内の the-3p-fulfilled-snowboard 合計数量を算出
{%- endcomment -%}
{%- assign the3p_snowboard_qty = 0 -%}
{%- for item in cart.items -%}
{%- if item.product.handle == "the-3p-fulfilled-snowboard" -%}
{%- assign the3p_snowboard_qty = the3p_snowboard_qty | plus: item.quantity -%}
{%- endif -%}
{%- endfor -%}
{%- comment -%}
以下の2条件のいずれかを満たす場合にチェックアウトボタンを非表示
1) the3p_snowboard_qty >= 2
2) ログイン顧客がタグ「注文済み_the-3p-fulfilled-snowboard」を持っていて
the3p_snowboard_qty >= 1
{%- endcomment -%}
{%- if the3p_snowboard_qty >= 2 or (customer and customer.tags contains "注文済み_the-3p-fulfilled-snowboard" and the3p_snowboard_qty >= 1) -%}
{%- assign the3p_snowboard_check = true -%}
<style>
/* チェックアウトボタンを非表示にする */
.checkout-button {
display: none !important;
}
</style>
<!-- チェックアウト不可メッセージを表示したい場合はここに -->
<p style="color: red;">
購入済みもしくは
</p>
{%- endif -%}
{%- if the3p_snowboard_check != true -%}
<div class="cart__ctas" {{ block.shopify_attributes }}>
<noscript>
<button type="submit" class="cart__update-button button button--secondary" form="cart">
{{ 'sections.cart.update' | t }}
</button>
</noscript>
<button
type="submit"
id="checkout"
class="cart__checkout-button button"
name="checkout"
{% if cart == empty %}
disabled
{% endif %}
form="cart"
>
{{ 'sections.cart.checkout' | t }}
</button>
</div>
{%- if additional_checkout_buttons -%}
<div class="cart__dynamic-checkout-buttons additional-checkout-buttons">
{{ content_for_additional_checkout_buttons }}
</div>
{%- endif -%}
{%- else -%}
<button type="submit" class="cart__update-button button button--secondary" form="cart">
カートをアップデート
</button>
<p><a href="/">トップページへ戻る</a></p>
{%- endif -%}
推奨の追加調整
上記のコード調整・設定により対象商品が1回だけ購入できるルールの実装ができました。
なお本番への実装の際は、さらにカスタマイズ画面で商品を指定したり、該当コレクションの商品それぞれを対象にするような記載を追加して、管理者側が操作しやすいように調整しています。
また、外部ツールを使った不正注文を自動でキャンセルするために、ルール外の注文を自動キャンセルする方法も推奨します。
結果
Shopifyで「お一人様1回のみのご注文」を実現することで、限定品への対応、および活用した様々な施策が、アプリ独自のルールやアプリサーバーのスペックに関わらず安定的に可能となります。特に人気の商品では会員登録数を大幅に増やす結果に繋がるケースも多数あります。
お気軽にお問い合わせください
Shopifyでよく使うカスタムコード集 Ver.1
付録として、Shopifyのカスタマイズでよく利用されるコード集をファイル化いたしました。
サイトのコード改修、機能追加の一助となりましたら幸いです。
下記リンクからダウンロードいただけます。