shopify開発の三種の神器ってご存じですか?公式ブログにも記載があるし、公式ブログにしては初心者にもわかりやすい解説だと思います。
今回はその三種の神器の1つ「Cart arributes」について開発初心者向けの解説をします。
- Cart attributeって何?
- なんでCart attributesが必要なのか
- どうやって作るのか?
- どうやって設置するのか
こんな点を解説していきます。
Cart attributeって何?
まぁ、まずはここですよね。そもそもなんだよこれ?って話ですよね。
Cart attributeは早い話が「カートページに追加するinputフィールド」の事です。まぁ、まずは下の画像を見比べてくださいな。
まずはbefore。Debutテンプレートの標準カートページです。
続きましてafter。Cart attributesでinputフィールドを足した同じDebutテンプレートのカートページです。
見比べてみましたか?勘のいいあなたなら、違いにお気づきになるでしょう。そう「くまちゃんの数」がbeforeは1個なのにafterは2個なのです!金額も当然倍です!!
・・・・すいません。ついどうでもいい小ボケを挟みました。
はいっ。そうです。afterの方には何やら配送日指定するinputフィールドがついてますね!!そう、ECサイトなのに標準ではついていない配送日指定ですよ!!アプリで実装すると月に9ドルも取られちゃう配送日指定ですよーーー!(アプリにはその他の機能もあるので使う時はちゃんと使いますけど)
つまり、こんな風にカートページに追加項目が加えられちゃうのがCart attributesです。
なんでCart attributesが必要なのか
まぁ、この点に関しては日本の場合はとにかく配送日指定が一番ですよね。標準では付いていないので何かしら追加してやる必要があるわけですよ。
その他にも例えば、チェックボックスを置いて、購入前に何か同意事項にチェックをもらう必要があるサイトの作成なんかでも必ず役に立ちます。
その辺りはここでは解説しませんがJavaScriptと併用でチェックマーク入れないと、購入画面に進めないようにするカスタマイズなんかが現実的にはあるんじゃないでしょうかね?
備考欄があるテンプレートは多いですが、地味にないテンプレートもありますので、そう言ったときにも備考欄を追加したくなります。
とにかく世界標準は日本標準とはかけ離れた不便さなので、日本標準になじませてあげる機能が追加できるのがCart attributesです。このカスタマイズを提案するだけで、例えばライバルの開発者が月に9ドルの配送日指定アプリを提案している中、あなたは毎月9ドル削減できる提案が出来るようになります!年間1万円の節約ですから「松坂牛のひれステーキ1枚食べていいですよ!」って言ってやって下さい。
Cart attributesの作り方
まぁ単純な話がinputタグなので、shopifyのルールに乗っ取ったinputタグを作ってやればいいのです。そのルールを見るためにまず1つの例を乗っけます。
<p class="cart-attribute__field">
<label for="">誕生日</label>
<input required class="required" id="" type="text" name="attributes[誕生日]" value="{{ cart.attributes["誕生日"] }}">
</p>
はい。例えばこちらです。
これはshopify開発でとってもお世話になるサイト「Shopify UI Element Generator」で作ったinputフィールドです。
結構謎なのは「pタグ」で囲ってある事です。別にいいっちゃいいのですが、僕は気持ち悪いので、結構divタグに書き換えちゃいます。
ちょっと触れたので先に紹介しますとShopify UI Element Generatorはshopify開発者は絶対に知らないといかんサイトです!なんせinputフィールドを作ってくれますからね。
上記のコードを生成した時の画面がこれです。簡単でしょ?
簡単に解説すると、まずは左側部分は3か所の入力があって
「Type of form field」 = inputフィールドのタイプ
「Your form field label」 = 見出し
「Required」 = チェックを入れておくと入力必須項目になる
と言う感じです。右側は、Previewの表示の通り、こんな見た目になるよ!ってだけです。
んでもって出来上がったコードが下の黒い四角枠の中に出てくるのでそれをコピーすりゃいいだけです。簡単にinputフィールドが出来ちゃいます。
仕組みは「name=”attributes[誕生日]”」の部分が公式ページによると「命名規則に沿ったinputタグであることを示します。」と言う説明が書かれているのですが、正直よくわからんですよね。
なので挿入してどうなるのか見てみましょう!
ご覧の通り、くまちゃんが3個に・・・じゃなくて「誕生日」とレベルのついたtextフィールドが出来上がっています!(挿入の仕方は次の章で)
なるほどここに誕生日でも書けばいいんだな。と言う事で入力して先に進んでみます。
これが先に進んだチェックアウトページです。・・・あれ?なんも書いてなくない?ってなるのですが、これがshopifyの悪い所でして、なんも書いてないんです!!
公式ページには「value=”{{ cart.attributes[“誕生日”] }}”」はLiquidからこの値を参照できることを示します。なんて書いてあるのですが・・・shopify Plus出ない限りcheckoutページのコードをいじれないので、そもそも我々フリーランスが扱うショップではめったな事でもない限り使わないと思われます。
唯一、お買い物するお客さんがもう1度目にする事が出来るのは、これもカスタマイズすれば実現可能なのですがチェックアウトの最終ページでは確認する事が出来ます。
誕生日欄があるのがわかるでしょ?(あ、リアル誕生日なので11月26日に何かくれてもいいんですよ)
これを表示させるためには「設定」→「チェックアウト」のところにある「追加スクリプト」の項目に下記のコードを叩き込んでおく必要があります。
{% if attributes %}
<script>
Shopify.Checkout.OrderStatus.addContentBox(
{% for attribute in attributes %}
'<h2>{{ attribute | first }}</h2>',
'<p>{{ attribute | last }}</p>'
{% endfor %}
)
</script>
{% endif %}
この辺は何も考えずに、コピペすればいいんだな。ぐらいでも大丈夫です。
はれてcart attributesで送信されたおじさんの誕生日情報ですが、最終的にはどう受け取るのか?
それがこんな感じ。右側のメモの下に誕生日欄があるでしょ?ここに記載されるのですね!今回は誕生日でしたが、これを「配送日時」とかにしておけばいいわけですよ。あーらくちん。
配送日時に関してはJQueryとコンボでもっといい感じの実装も出来るのですが、その辺りは今度別の解説記事でも書いてみます。
Cart attributesの設置の仕方
これは結構簡単ではあります。さっきこんなコードを生成していますね?
<p class="cart-attribute__field">
<label for="">誕生日</label>
<input required class="required" id="" type="text" name="attributes[誕生日]" value="{{ cart.attributes["誕生日"] }}">
</p>
これをcartテンプレートのformタグ内に設置する。ただそれだけです。
もしくはDanw等、最近のテーマの場合は、formのIDを指定してあげる方法が必要な場合もあります!
Debutテンプレートのケースで見てみましょう。Debutのコード編集でtemplateフォルダのcart.liquidを見ると大した事は書いていませんで、たったこれだけです。
{% comment %}
The contents of the cart.liquid template can be found in /sections/cart-template.liquid
{% endcomment %}
{% section 'cart-template' %}
まぁ、要するにsectionフォルダの「cart-template.liquid」に中身は書いてあるよ!って事なのでそっちのファイルを編集しましょう!
※ここで注意なのがDebutはこう言う構造になっていますが、cart.liquidに直接コードが書いてあるテンプレートもあります。無料のテンプレートでもsimpleとかはそうですね。
で、追記するのはformタグ内なのでDebutの場合は
<form action="{{ routes.cart_url }}" method="post" novalidate class="cart">
ここが開始タグで、閉じタグは
</form>
シンプルにこんな感じです。たまにliquidコードでformタグ自体が書いてあるケースもあるのでご注意を!
後は設置場所をどこでもいいので、UIを考えて設置してやりましょう。今回は小計の上に置いたので、その上下の部分ごと張り付けておきます。
<div{% if cart.cart_level_discount_applications.size == 0 %} class="hide"{% endif %} data-cart-discount-wrapper>
<div class="order-discount-card-wrapper" data-cart-discount>
{%- for discount_application in cartDiscounts -%}
<span class="order-discount order-discount--title order-discount--cart">
{% include 'icon-saletag' %}<span class="visually-hidden">{{ 'customer.order.discount' | t }}:</span><span data-cart-discount-title>{{- discount_application.title -}}</span>
</span>
<span class="order-discount order-discount--cart order-discount--cart-total">
-<span data-cart-discount-amount>{{ discount_application.total_allocated_amount | money }}</span>
</span>
{%- endfor -%}
</div>
</div>
<p class="cart-attribute__field">
<label for="">誕生日</label>
<input required class="required" id="" type="text" name="attributes[誕生日]" value="{{ cart.attributes["誕生日"] }}">
</p>
<div class="cart-subtotal">
<span class="cart-subtotal__title">{{ 'cart.general.subtotal' | t }}</span>
<span class="cart-subtotal__price" data-cart-subtotal><span class='hulkapps-cart-original-total'>{{ cart.total_price | money_with_currency }}</span></span>
</div>
まぁ、簡単ですね。ただコピペしただけですからね。
次にDanw等のテーマの場合を考えてみます。
Dawnの場合formタグの範囲が極めて狭いです!
snippetフォルダ内にある「buy-buttons.liquid」(Ver15.0の場合)と言うファイル内に
%- form 'product',
product,
id: product_form_id,
class: 'form',
novalidate: 'novalidate',
data-type: 'add-to-cart-form'
-%}
<input
type="hidden"
name="id"
value="{{ product.selected_or_first_available_variant.id }}"
{% if product.selected_or_first_available_variant.available == false
or quantity_rule_soldout
or product.selected_or_first_available_variant == nil
%}
disabled
{% endif %}
class="product-variant-id"
>
----中略-----
{%- render 'loading-spinner' -%}
</button>
{%- if show_dynamic_checkout -%}
{{ form | payment_button }}
{%- endif -%}
</div>
{%- endform -%}
こんな感じの場所があります!
なのでCart Attributesをこのformタグ内に書く事も出来ます!これが一番シンプルで簡単な方法ですが、その場合「buy-button」の上下、つまり購入ボタンの上か下にしか設置できな事になってしまいます。
しかし実際には他の場所に貼りたい事も多いのでは?
ここで考えるのはformタグの仕組みです。
formタグは基本的にformタグ内にあるinput要素のvalue値を送信してくれたりするのですが、formタグ外の場合はどのformに連動するのかをinputタグ内に指定してあげる必要があります。
そこでDanw内の他のinput要素をmain-productと言うファイルから見てみると
<input
class="quantity__input"
type="number"
name="quantity"
id="Quantity-{{ section.id }}"
data-cart-quantity="{{ cart_qty }}"
data-min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
{% if product.selected_or_first_available_variant.quantity_rule.max != null %}
data-max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
{% endif %}
step="{{ product.selected_or_first_available_variant.quantity_rule.increment }}"
value="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
form="{{ product_form_id }}"
>
ここは注文する数量を決めるinputタグですね。一番下を赤字にしたのでわかるかと思いますが、fomrタグ外に書いてある、input要素を送信するにはそのformのIDを指定してあげる必要があります!
shopifyの場合そのIDがliquidのタグで示されている場合が多いのでDawnでも同じことをしなくてはいけません。つまりCart Attributesの場合にはこうなります。
<p class="cart-attribute__field">
<label for="">誕生日</label>
<input required class="required" id="" type="text" name="attributes[誕生日]" value="{{ cart.attributes["誕生日"] }}" form="{{ product_form_id }}">
</p>
さっきのformタグ内に設置する場合と違い、formを指定しているコードが増えているのがわかるかと思います。これさえつけておけば商品ページの何処に置いといても無事送信してくれるので、その点だけは把握しておきましょう!
ちなみに他の有料テーマではformのIDをどうやって指定しているのか・・・・?見てみないとわからない所が多いですね。じっくりコードを眺めてみましょう。
Dawnは上記で動きます!
まとめ
cart attributesを使うと、お客さんの入力できる項目がカートページで増える。と言う事がわかったかと思います。
やり方は順を追って書けば
- Shopify UI Element Generatorでコード生成
- cart.liquidにコピペ
シンプルにこれだけです。
あとはShopify UI Element Generatorでの生成は絶対に知っておきましょう。もちろん使わないでオリジナルのinputフィールドを作っても大丈夫です。配送日指定なんて作った方がもっと便利な物になりますしね。
お客さんの要望に応えるカスタマイズを知るためには必ず知っておきたい部分の解説でした。