Shopifyで制限用のアプリを使わずにカートに入れる商品点数を制限する

厳密には穴があるものの、比較的簡易に実装できそうなので検討しました。
制限はありますがバリエーションなしならばliquidのみで実装可能な方法です。

前提と実現したいこと

  • Shopifyで構築したストアでDebutテーマが対象
  • 数量セレクタの表示が必須
  • バリエーションのない商品が対象

上記の前提で以下を実現します。

  • 商品ごとにカートに入れる商品点数の制限を行いたい
  • Limits by Limitsなどの購入制限用アプリを使わない

Debutテーマでなくとも数量セレクタさえ表示されていれば恐らく大丈夫かなと思います。
数量セレクタがない時点で購入可能な商品点数は1にしかならないと思いますので制限は必要ないはずです。

注意点

今回の仕組みは以下2点の動作を目的としています。

  • 商品ページで選択できる個数を制限する
  • カート画面表示時に強制的に制限数以下に変更する

上記の使用上、複数回商品画面に移動しJSによってカートが実装されている場合、その時点では制限数以上に入ってしまいます。
この点はCART APIを併用すれば解決できると思いますが、当記事では触れません。

また、バリエーションごとの制限に関してもJSと併用する必要があります。
根幹部分の仕組みは同じではありますが、バリエーション変更に連動して制限数を書き換えます。テーマ内のJSを流用するか自作するかになるかと。

加えて、購入履歴を確認して制限を行なっているわけではないので「お一人様一回限り」という動作でありません。

このように実用には不足する可能性が高いため、条件付きの簡易動作を目的としています。

実装

  • 商品のメタフィールドに商品ごとの制限数を設定する
  • 商品詳細ページの数量セレクタにメタフィールドに設定した制限個数を入れ込む
  • カートの購入数の箇所にもメタフィールドに設定した制限個数を設定し、総数が制限するを超えるなら強制的に最大しまで減らす
  • 数値入力用のinputタグを無効化する

概要は上記のようになります。
メタフィールドに関しては検索いただくか、以下の記事などを参照ください。

サンプルコード

特にどのテーマという前提ではありませんが、各テーマの商品ページ用liquidファイル内で数量設定箇所を探し、以下のようにmax属性を追加します。


{% comment %}
NAMESPACE: myfield
KEY: limit_num
TYPE: integer
VALUE: 3
上記の内容でカスタムフィールドを登録したと仮定。
VALUEは購入制限数の指定。
バリエーションのメタフィールドの値を用いるときは以下を使う
product.selected_or_first_available_variant.metafields.myfield.limit_num
{% endcomment %}

{% assign limit_num = product.metafields.myfield.limit_num %}
{% if limit_num != blank %}
  {%- capture limit_num_code %}max="{{ limit_num | escape }}" disabled{% endcapture -%}
{% endif %}
<input class="quantity__input"
  type="number"
  name="quantity"
  id="Quantity-{{ section.id }}"
  min="1"
  {% if limit_num_code != blank %}{{ limit_num_code }}{% endif %}
  value="1"
  form="{{ product_form_id }}"
>

カートページでも同様にmax属性を追加します。
加えて実際の購入数と制限数を比較し、制限数を超えるなら制限数まで強制的に減らすという動作を追加します。


{% comment %}
カートページでバリエーションのメタフィールドの値を用いるときは以下を使う
item.variant.metafields.myfield.limit_num
{% endcomment %}

{%- liquid
  assign item_quantity = item.quantity
  assign limit_num = item.metafields.myfield.limit_num
-%}
{%- if limit_num != blank and item_quantity > limit_num -%}
   <p>購入制限数を超えているため、上限の{{ limit_num | escape }}に変更されました。</p>
  {%- assign item_quantity = metafield_quantity -%}
  {%- capture limit_num_code %}max="{{ limit_num | escape }}" disabled{% endcapture -%}
{%- endif -%}

<input class="quantity__input"
  type="number"
  name="updates[]"
  value="{{ item_quantity | escape }}"
  {% if limit_num_code != blank %}{{ limit_num_code }}{% endif %}
  min="0"
  aria-label="{{ 'products.product.quantity.input_label' | t: product: item.product.title | escape }}"
  id="Quantity-{{ item.index | plus: 1 }}"
  data-index="{{ item.index | plus: 1 }}"
>

メタフィールドや変数の名称は適当ですが、値を入れて取り出して設定しているだけの単純な構造です。

数値を直接増減された場合の対策

inputタグのmax属性は、数値をキーボードで直接入力する場合には効果がありません。
そのため簡易対応として、対象のinputタグにdisabledを設定するか、以下のCSSを設定する必要があります。


pointer-events : none;

他にはJSで制御する方法もあるかもしれませんが、キーボードによるmaxに指定した数値以上の入力を弾くというのは難しいかもしれません。

動的チェックアウトへの対応

「今すぐ購入」ボタンでしか試していませんが、動的チェックアウトでもこの方法は有効でした。

入力側である数量セレクタに制限をつけているだけなので、ボタン押下後の動作とは無関係になっているためです。

Limits by Limitsifyでは制限が働かないという情報も見ましたので、そうであるなら当記事の手法が有効かもしれません。

メリット・デメリット

実際の動作チェックやシナリオに基づく検証を進めると他にもでてくると思いますが、軽くメリットとデメリットを記載します。

メリット

アプリだけではなくCart APIも使わずliquidのみで実装可能です。
実験できていないので確証はありませんが、APIによる通信が発生しないため、大量のアクセスがあった場合でもスムーズに動作するのではと思います。

デメリット

冒頭で書きましたが、開発者ツールを触れるユーザーであればmaxdisabledも削除可能なので制限を無効化できます。

特に転売目的などで技術を持った悪質な人間に対しては意味がないともいえるため、その点では実用的とは言い難い方法かもしれません。
そのため販売個数に対して厳密な制限をかけたいのであればこの方法は使えません。

スマホで開発者ツールを使えるような方は多くはないと思いますので、スマホアクセスが多い現在であれば一般ユーザーに限ればそれなりに有効ではと思いますが。

また、カートページでは強制的に購入数を制限数まで減らす仕組みのため、ユーザーが想定しない動作となり不安を感じさせる可能性もあります。
JSでカートを実装しているテーマの場合は、JSカートへの対応を検討する必要があり、その場合作業難度は上がります。

バリエーションへの対応

商品にバリエーションがあり、バリエーションごとに制限数が違う場合は、商品ページではバリエーションの変更に応じて制限数を書き換える必要があります。

カートページではバリエーション変更はできないことが多いはずなので、その点では実装が楽になります。

1人1回までの購入制限の検討

  • 顧客にタグをつけて制限する
  • 顧客に購入履歴を確認して制限する

実務での実装経験がないので推測ですが、概ね以下のようになるのではと思います。

顧客にタグをつけて制限する

  • ストアはログイン必須(アカウント作成必須)でログインしないと買えない
  • 該当商品購入時に顧客にタグ付けする(Easy Taggingなどのアプリを使用)
  • 購入時にタグがあれば購入ボタンを押せないようにする

顧客の購入履歴を確認して制限する

  • ストアはログイン必須(アカウント作成必須)でログインしないと買えない
  • customerオブジェクトから購入履歴を検索して、該当商品があれば購入ボタンを押せないようにする

本来なら歓迎するべきヘビーユーザーほどこの処理は重くなるでしょうし、遡れる制限ある場合(未確認)は動作しない可能性もあり、リスクがあるように思います。

現実的な問題

どの方法であれ、そもそもアカウントの複数登録は防げないので厳密な制限は不可能という事実に変わりありません。

そのため「どの程度の精度で制限を行うか」という点で判断を行う必要があるように思います。

結び

当記事のサンプルは実際に運用中のストアに実装したことはないので、実験段階というところです。

そのため、基本的にはアプリによって購入数制限を行う方が筋かなと思います。
アプリによりますが既に導入しているストアが多いのであれば、実績豊富となり安心感がありますので。

3人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄