BLOGShopifyカスタマイズ事例2:マイページ改修
Shopifyカスタマイズ事例2:マイページ改修
月商1億円超えを支えたShopifyカスタマイズ事例2
弊社ではShopifyでの制作をはじめ、様々なECサイトの制作のご依頼をいただいています。
月商1億円を超えることを目指したECサイト制作、または月商規模が既に億単位を超えているサイトのShopifyリニューアルにあたり、弊社が実際に行ってきたカスタマイズ事例のTipsを定期的にご紹介します。
事例2:マイページの改善カスタマイズ
カスタマイズの背景
ご依頼いただいた寝具のECサイト、生活雑貨のECサイト、化粧品メーカーのEC、それぞれマイページの情報の充実が課題となっていました。
寝具・生活雑貨では大規模なサイトのため、リニューアル前と同等または超えるレベルのマイページ情報量が必要であり、化粧品メーカーではShopifyの基本テーマで運用していましたが、ポイント表示やランク等を取り入れても表示されないシンプルな表示でした。
それぞれリピーターへの施策が重要となるサイトのため、マイページの充実を図る必要がありました。
カスタマイズ前の課題
- テーマそのままではマイページとしての機能が足りなかった。
- LINEアカウントとの連携が必要だった。
- 所有するポイントの表示が必要だった。
- 店舗のPOSとの連携について、マイページにバーコードを表示する必要があった。
- Yappliなどのアプリと連携する必要があった。
- マイページ会員に必要なメニューを表示する必要があった。
上記の課題から、テーマのパーツだけでは実現が難しいため、カスタマイズしたパーツを作成し実装することになりました。
カスタマイズでの要件
上記課題から、カスタマイズでは下記が要件となりました。
- ポイントアプリの組み込みと所有ポイント表示
- 店舗のPOSと連携するバーコードの表示
- マイページに必要なリンクの設定
- 情報量が多いもの(ポイント履歴・受注履歴)も表示
- 住所変更等Shopifyの基本機能はデザインに合わせて継続実装
カスタマイズでの解決案
上記要件を受けて、弊社では下記の解決案を用意し、カスタマイズ実装を行いました。
- ポイントアプリの選定と表示の実装
- POS連携用のバーコードのスクリプト実装
- LINE連携アプリの選定と実装
- 会員ランクの表示
- 情報量が多い部分はタブへの切り替えをliquidで実装
実装方法
具体的に行った実装方法は下記のような方法を利用しています。
※各コードは例であり、各パーツへの機構を組み込むサンプルのため、あくまで機構づくりの参考として記載しています。
ポイントアプリの組み込み
ポイントアプリの実装要件にはShopify Flowでの自動化の仕組みが必要となるケースが多いため、「どこポイ」または「VIP」を利用するケースが多いです。
総合ポイントアプリ「どこポイ」
VIP ‑ 会員プログラム
easyPoints ‑ ポイントアプリ
所有ポイント表示、ポイント履歴は、アプリのブロックでテーマに入れることができるため、ブロック挿入後のCSS調整や、アプリブロックをsectionに組み込む方式を取ると自由なパーツ位置での設定が可能となります。
<!-- アプリブロックを設置するコード例 --> {%- for block in section.blocks -%} {%- case block.type -%} {%- when '@app' -%} {%- render block -%} {%- endcase -%} {%- endfor -%}
バーコードアプリの設定
店舗POSとの連携として、Omni Hubでの実装ケースでは、Omni Hub側にバーコード表示のアプリブロックが存在するため、上記のように任意の箇所にアプリパーツを入れるカスタマイズを行っておくと、自由に配置が可能となります。
LINE連携パーツの実装
LINEアカウントとの連携として、CRM PLUS on LINEでの実装を行うケースでは、こちらもアプリ側に連携パーツのアプリブロックが存在するため同様に配置箇所を任意に設定することが可能です。
会員ランクの表示
顧客の会員ランクの表示方法は複数の方法がありますが、カスタムフィールドで実装する場合は、下記の方法で実装が可能です。
※メタフィールド側に設定を行っておく必要があります。
{% if customer.metafields.custom._lank %} <p class="customer_rank"><span>現在の会員ランク:</span> {{ customer.metafields.custom._lank }}</p> {% else %} <p class="customer_rank_none"><span>現在の会員ランク:</span>ランク情報がありません。</p> {% endif %} {% if customer.metafields.customer_fields.rank_id %} <p class="makurabo_rank"><span>ランクID:</span> {{ customer.metafields.customer_fields.rank_id }}</p> {% endif %}
情報量が多い部分はタブへの切り替えをliquidで実装
情報量が多くなる部分は、タブでのコンテンツ切り替えを行えるようにコードを実装しました。
下記はそのコードの例ですが、アプリを組み込む機構など、総合的な設定を入れています。
※実際の利用時は、日本語の部分を翻訳にできるように変数化などを行って制作する必要があります。
<style> .app_tabs > li { background-image: url({{ 'tab_arrow_active.svg' | asset_url }}); background-repeat: no-repeat; } .app_tabs > li.active { background-image: url({{ 'tab_arrow_active.svg' | asset_url }}); } </style> {%- if section.settings.divider -%}<div class="liquid_app_tab_box section--divider">{%- endif -%} <div class="page-width{% if section.settings.class != blank %} {{section.settings.class}}{% endif %}"> {%- if section.settings.title != blank -%} <div class="section-header text-{{ section.settings.heading_position }}"> <h2 class="section-header__title {{ section.settings.heading_size }}">{{ section.settings.title }}</h2> </div> {%- endif -%} {%- if section.blocks.size > 1 -%} <div class="app_tab_box hidden-sp"> <div class="accout_tab_wrap"> <div class="exp_tab_wrap app_tab_part"> <ul class="exp_tabs app_tabs"> <li><span data-target="exp_tab_name" class="app_tab_name" title="#ex1">{% if section.settings.icon_img1 != blank %}<i class="icon_img app_tab_icon"><img src="{{ section.settings.icon_img1 | img_url: 'master' }}" art="{{ section.settings.tab_title_1 }}"></i>{% endif %}<b>{% if section.settings.tab_title_1 != blank %}{{ section.settings.tab_title_1 }}{% endif %}</b></span></li> <li><span data-target="exp_tab_name" class="app_tab_name" title="#ex2">{% if section.settings.icon_img2 != blank %}<i class="icon_img app_tab_icon"><img src="{{ section.settings.icon_img2 | img_url: 'master' }}" art="{{ section.settings.tab_title_2 }}"></i>{% endif %}<b>{% if section.settings.tab_title_2 != blank %}{{ section.settings.tab_title_2 }}{% endif %}</b></span></li> <li><span data-target="exp_tab_name" class="app_tab_name" title="#ex3">{% if section.settings.icon_img3 != blank %}<i class="icon_img app_tab_icon"><img src="{{ section.settings.icon_img3 | img_url: 'master' }}" art="{{ section.settings.tab_title_3 }}"></i>{% endif %}<b>{% if section.settings.tab_title_3 != blank %}{{ section.settings.tab_title_3 }}{% endif %}</b></span></li> <li><span data-target="exp_tab_name" class="app_tab_name" title="#ex4">{% if section.settings.icon_img4 != blank %}<i class="icon_img app_tab_icon"><img src="{{ section.settings.icon_img4 | img_url: 'master' }}" art="{{ section.settings.tab_title_4 }}"></i>{% endif %}<b>{% if section.settings.tab_title_4 != blank %}{{ section.settings.tab_title_4 }}{% endif %}</b></span></li> <li><span data-target="exp_tab_name" class="app_tab_name" title="#ex5">{% if section.settings.icon_img5 != blank %}<i class="icon_img app_tab_icon"><img src="{{ section.settings.icon_img5 | img_url: 'master' }}" art="{{ section.settings.tab_title_5 }}"></i>{% endif %}<b>{% if section.settings.tab_title_5 != blank %}{{ section.settings.tab_title_5 }}{% endif %}</b></span></li> </ul> <div class="exp_tab_contents_list"> {% for block in section.blocks %} <div id="ex{{- forloop.index -}}" class="exp_tab_content"> {% case block.type %} {%- when 'liquid' -%} {{ block.settings.custom_liquid }} {%- when 'order' -%} <div class="order_list_box"> {%- if customer.orders.size != 0 -%} <table class="table--responsive table--small-text"> <thead> <tr> <th>{{ 'customer.orders.order_number' | t }}</th> <th>{{ 'customer.orders.date' | t }}</th> <th>{{ 'customer.orders.payment_status' | t }}</th> <th>{{ 'customer.orders.fulfillment_status' | t }}</th> <th>{{ 'customer.orders.total' | t }}</th> </tr> </thead> <tbody> {%- for order in customer.orders -%} <tr class="table__section"> <td data-label="{{ 'customer.orders.order_number' | t }}"><a href="{{ order.customer_url }}" data-order-id="{{ order.id }}">{{ order.name }}</a></td> <td data-label="{{ 'customer.orders.date' | t }}">{{ order.created_at | time_tag: format: 'date' }}</td> <td data-label="{{ 'customer.orders.payment_status' | t }}">{{ order.financial_status_label }}</td> <td data-label="{{ 'customer.orders.fulfillment_status' | t }}">{{ order.fulfillment_status_label }}</td> <td data-label="{{ 'customer.orders.total' | t }}">{{ order.total_price | money }}</td> </tr> {%- endfor -%} </tbody> </table> <hr class="hr--clear"> {%- else -%} <p>{{ 'customer.orders.none' | t }}</p> {{ block.settings.order_add_code }} {%- endif -%} </div> {%- when 'address' -%} <div class="address_list flbox"> <div class="address_list_inner"> {%- for address in customer.addresses -%} <div class="address_card_box"> <p class="address_card_box_title">住所{{- forloop.index -}}</p> <div class="address_card_inner"> <p>{{ address.last_name }} {{ address.first_name }}</p> <p>{{ address.zip }} {{ address.province }} {{ address.city }}</p> {% if address.address1 != blank %}<p>{{ address.address1 }}</p>{% endif %} {% if address.address2 != blank %}<p>{{ address.address2 }}</p>{% endif %} </div> </div> {%- endfor -%} </div> <div class="address_list_btn_area"> <div class="address_list_btn_wrap"> <a class="address_list_btn" href="/customers/addresses">配送先の追加/編集</a> </div> </div> </div> {{ block.settings.address_list }} {%- when 'registration' -%} <div class="registration_info"> <div class="registration_info_inner"> <ul class="regist_info_btn_list flbox"> <li><a class="btn_2nd" href="/tools/customr/edit-account">登録会員情報変更</a></li> <li><a class="btn_2nd" href="/account/login?return_url=%2Faccount#recover">パスワード変更</a></li> <li> {% comment %} <form action='{{settings.redirection_url}}' method='post' id='delete_me-button'> <button id='delete-account-button' type='submit' data-email='{{ customer.email }}' data-customer-id='{{customer.id}}' class="btn_2nd"> <span> 退会する </span> </button> </form> {% endcomment %} <button id='delete-account-button' type='submit' data-email='{{ customer.email }}' data-customer-id='{{customer.id}}' class="btn_2nd"> <span> 退会する </span> </button> </li> </ul> </div> </div> {{ block.settings.registration_info }} {% else %} {% render block %} {% endcase %} </div> {% endfor %} </div> </div> </div> </div> {%- endif -%} {%- if section.blocks.size > 1 -%} <div class="app_toggle_box visible-sp"> <div class="accout_toggle_wrap"> <div class="exp_toggle_wrap app_toggle_part"> <ul class="exp_toggles app_toggles"> {% for block in section.blocks %} <li> {%- if forloop.index == 1 -%} <span id="ex_click1" data-target="exp_toggle_name" class="app_toggle_name arrow_toggle" title="#ex_click1">{% if section.settings.icon_img1 != blank %}<i class="icon_img app_toggle_icon"><img src="{{ section.settings.icon_img1 | img_url: 'master' }}" art="{{ section.settings.tab_title_1 }}"></i>{% endif %}<b>{% if section.settings.tab_title_1 != blank %}{{ section.settings.tab_title_1 }}{% endif %}</b></span> {%- elsif forloop.index == 2 -%} <span id="ex_click2" data-target="exp_toggle_name" class="app_toggle_name arrow_toggle" title="#ex_click2">{% if section.settings.icon_img2 != blank %}<i class="icon_img app_toggle_icon"><img src="{{ section.settings.icon_img2 | img_url: 'master' }}" art="{{ section.settings.tab_title_2 }}"></i>{% endif %}<b>{% if section.settings.tab_title_2 != blank %}{{ section.settings.tab_title_2 }}{% endif %}</b></span> {%- elsif forloop.index == 3 -%} <span id="ex_click3" data-target="exp_toggle_name" class="app_toggle_name arrow_toggle" title="#ex_click3">{% if section.settings.icon_img3 != blank %}<i class="icon_img app_toggle_icon"><img src="{{ section.settings.icon_img3 | img_url: 'master' }}" art="{{ section.settings.tab_title_3 }}"></i>{% endif %}<b>{% if section.settings.tab_title_3 != blank %}{{ section.settings.tab_title_3 }}{% endif %}</b></span> {%- elsif forloop.index == 4 -%} <span id="ex_click4" data-target="exp_toggle_name" class="app_toggle_name arrow_toggle" title="#ex_click4">{% if section.settings.icon_img4 != blank %}<i class="icon_img app_toggle_icon"><img src="{{ section.settings.icon_img4 | img_url: 'master' }}" art="{{ section.settings.tab_title_4 }}"></i>{% endif %}<b>{% if section.settings.tab_title_4 != blank %}{{ section.settings.tab_title_4 }}{% endif %}</b></span> {%- elsif forloop.index == 5 -%} <span id="ex_click5" data-target="exp_toggle_name" class="app_toggle_name arrow_toggle" title="#ex_click5">{% if section.settings.icon_img5 != blank %}<i class="icon_img app_toggle_icon"><img src="{{ section.settings.icon_img5 | img_url: 'master' }}" art="{{ section.settings.tab_title_5 }}"></i>{% endif %}<b>{% if section.settings.tab_title_5 != blank %}{{ section.settings.tab_title_5 }}{% endif %}</b></span> {%- endif -%} <div id="ex_toggle{{- forloop.index -}}" class="exp_toggle_content"> </div> </li> {% endfor %} </ul> </div> </div> </div> {%- endif -%} <div class="account_logout_box"> <a href="/account/logout">ログアウト</a> </div> </div> {%- if section.settings.divider -%}</div>{%- endif -%} <script> $(function() { // 初期表示 $(".exp_tab_content").hide(); // 各タブセットに対して初期設定 $(".exp_tabs").each(function() { $(this).find("li:first").addClass("active").show(); $(this).closest('.exp_tab_wrap').find(".exp_tab_content:first").show(); }); // タブクリック時 $("ul.exp_tabs li").click(function() { var parentWrap = $(this).closest('.exp_tab_wrap'); parentWrap.find('ul.exp_tabs li').removeClass("active"); $(this).addClass("active"); // そのタブセット内のコンテンツを非表示 parentWrap.find(".exp_tab_content").hide(); // クリックされたタブのインデックスに基づいて対応するコンテンツを表示 var index = $(this).index(); parentWrap.find(".exp_tab_content").eq(index).fadeIn('fast'); return false; }); }); window.addEventListener('DOMContentLoaded', function() { // 1から5までの各要素に対してループ for (let i = 1; i <= 5; i++) { // クリックイベントリスナーを追加 let clickElement = document.getElementById('ex_click' + i); if (clickElement) { clickElement.addEventListener('click', function handler() { // 元の要素を取得 let original = document.getElementById('ex' + i); // 複製先の要素を取得 let target = document.getElementById('ex_toggle' + i); // 元の要素の内容を複製先に設定 if (original && target) { target.innerHTML = original.innerHTML; } // イベントリスナーを削除して、複製が1回だけ行われるようにする clickElement.removeEventListener('click', handler); }); } } }); </script> {% schema %} { "name": "app or liquid tab", "class": "index-section", "max_blocks": 5, "settings": [ { "type": "text", "id": "title", "label": "t:sections.featured-collections.settings.title.label", "default": "Title" }, { "type": "select", "id": "heading_size", "label": "t:common.heading_size.label", "default": "h2", "options": [ { "value": "h3", "label": "t:common.heading_size.options.small.label" }, { "value": "h2", "label": "t:common.heading_size.options.medium.label" }, { "value": "h1", "label": "t:common.heading_size.options.large.label" }, { "value": "h0", "label": "t:common.heading_size.options.extra_large.label" } ] }, { "type": "select", "id": "heading_position", "label": "t:common.heading_position.label", "default": "left", "options": [ { "value": "left", "label": "t:common.heading_position.options.left.label" }, { "value": "center", "label": "t:common.heading_position.options.center.label" }, { "value": "right", "label": "t:common.heading_position.options.right.label" } ] }, { "type": "checkbox", "id": "divider", "label": "t:sections.featured-collections.settings.divider.label", "default": false }, { "type": "text", "id": "class", "label": "Class" }, { "type": "text", "id": "tab_title_1", "label": "Tab title 1" }, { "type": "image_picker", "id": "icon_img1", "label": "Icon image 1" }, { "type": "text", "id": "tab_title_2", "label": "Tab title 2" }, { "type": "image_picker", "id": "icon_img2", "label": "Icon image 2" }, { "type": "text", "id": "tab_title_3", "label": "Tab title 3" }, { "type": "image_picker", "id": "icon_img3", "label": "Icon image 3" }, { "type": "text", "id": "tab_title_4", "label": "Tab title 4" }, { "type": "image_picker", "id": "icon_img4", "label": "Icon image 4" }, { "type": "text", "id": "tab_title_5", "label": "Tab title 5" }, { "type": "image_picker", "id": "icon_img5", "label": "Icon image 5" } ], "blocks": [ { "type": "tab", "name": "タブコンテンツliquid", "settings": [ { "type": "liquid", "id": "custom_liquid", "label": "Liquid code" } ] }, { "type": "order", "name": "注文履歴", "settings": [ { "type": "liquid", "id": "order_add_code", "label": "注文履歴に追加するコード" } ] }, { "type": "address", "name": "住所リスト", "settings": [ { "type": "liquid", "id": "address_list", "label": "住所リストに追加するコード" } ] }, { "type": "registration", "name": "登録情報", "settings": [ { "type": "liquid", "id": "registration_info", "label": "登録情報変更に追加するコード" } ] }, { "type": "@app" } ], "presets": [ { "name": "app or liquid tab", "blocks": [ { "type": "tab" }, { "type": "tab" }, { "type": "tab" } ] } ], "disabled_on": { "groups": ["footer", "header", "custom.popups"] } } {% endschema %}
結果
Shopifyでも、日本のECに向けたマイページの充実を図ることで、リピート施策が打ちやすくなります。店舗とのポイント連携も兼ねた施策で、リニューアル前のECの売上を落とさず、現在も高い成長率を維持しています。
お気軽にお問い合わせください
弊社ではECをスタートされる方から、大規模ECの安全なリニューアル、個別のカスタマイズ実装まで幅広く対応可能です。
ご相談がございましたら、お気軽にご連絡ください。