shopifyテーマのtemplateディレクトリの中身を解説

こんにちは鈴木祐登です。

今回はshopifyテーマのtemplateディレクトリの中身を詳しく解説していこうと思います。

shopifyテーマのtemplateディレクトリには標準で下記のようなディレクトリやファイルが存在します。

404.liquid : 404ページ
article.liquid : ブログ記事個別ページ
blog.liquid : ブログ記事一覧ページ
cart.liquid : カート内アイテム一覧ページ
collection.liquid : 商品一覧ページ
customers/account.liquid : アカウント詳細ページ
customers/activate_account.liquid : アカウント有効化ページ
customers/addresses.liquid : アカウントの住所ページ
customers/login.liquid : アカウントのログインページ
customers/order.liquid : アカウントの注文詳細ページ
customers/register.liquid : アカウントの新規登録ページ
customers/reset_password.liquid : アカウントのパスワード再発行ページ
gift_card.liquid : ギフトカードページ
index.liquid : トップページ
list-collections.liquid : 商品カテゴリ一覧ページ
page.liquid : 固定ページ
product.liquid : 商品詳細ページ
search.liquid : 検索結果ページ

これらの役割を順番に解説していきます。

404.liquid

404liquidは404ページの大枠が格納されています。

404ページは存在しないページのurlにアクセスしようとした時に表示されるページのことです。

404ページに来たユーザーに探してるページが存在しないことがわかりやすいページにすべき

404ページにトップページのリンクを貼っておいたり検索バーを設置するなどして、ユーザーに親切なページ作りを心がけましょう。

article.liquid

article.liquidはブログ記事の個別ページの大枠が格納されています。

article.liquidでは読者がコメントの投稿に成功したのかわかりやすくすべき

読者がコメントを投稿したら、コメントの投稿に成功したのか、エラーで投稿できなかったのかがわかりやすいようにしましょう。

コメントの量が50を超える場合はペジネーションを設置すべき

ブログ記事のコメントの表示数は標準では50コメントまでになっています。

コメントの数が50を超えるときはpaginateタグを使ってペジネーションを設置しましょう。

blog.liquid

blog.liquidはブログ一覧ページの大枠が格納されています。

ブログ記事につけてるタグで絞り込みができる

特定のurlを指定することでブログ記事一覧に表示するブログをタグで絞り込みすることができます

これはサブカテゴリを付けたいとき等に役立ちます。

例えば、下記のurlでブログ記事、ブログ記事2が存在して、ブログ記事2にのみ、testというタグをつけていたとします。

https://suzuki-yasu.myshopify.com/blogs/news

この場合、下記のように tagged/タグ名 をurlの末尾につけることでタグ名で絞り込みができます。

https://suzuki-yasu.myshopify.com/blogs/news/tagged/test

cart.liquid

cart.liquidではカート内アイテム一覧ページの大枠が格納されています

ファイルの中身の解説

ここではcart.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
{% if cart.item_count > 0 %}
  <form action="{{ routes.cart_url }}" method="post" class="cart-form" data-cart-form novalidate>

    <h1 class="h2">{{ 'cart.general.title' | t }}</h1>

    {% for item in cart.items %}
    <div class="cart-row" data-line="{{ forloop.index }}">
      <div class="grid">

        <div class="grid-item large--one-half">
          <div class="grid">

            <div class="grid-item one-third large--one-quarter">
              <a href="{{ item.url }}" class="cart-image">
                <img src="{{ item | img_url: 'medium' }}"  alt="{{ item.title | escape }}">
              </a>
            </div>

            <div class="grid-item two-thirds large--three-quarters">
              <a href="{{ item.url }}">
                {{ item.product.title }}
              </a>
              {% unless item.variant.title contains 'Default' %}
                <br>
                <small>{{ item.variant.title }}</small>
              {% endunless %}

              {% if settings.product_quantity_message and item.variant.inventory_management and item.variant.inventory_quantity <= 0 and item.variant.incoming %}
                {% assign date = item.variant.next_incoming_date | date: format: 'date' %}
                <p><small>{{ 'products.product.will_not_ship_until' | t: date: date }}</small></p>
              {% endif %}

              {% assign property_size = item.properties | size %}
              {% if property_size > 0 %}
                {% for p in item.properties %}
                  {% if forloop.first %}<br>{% endif %}
                  {% assign first_character_in_key = p.first | truncate: 1, '' %}
                  {% unless p.last == blank or first_character_in_key == '_' %}
                    {{ p.first }}:

                    {% if p.last contains '/uploads/' %}
                      <a href="{{ p.last }}">{{ p.last | split: '/' | last }}</a>
                    {% else %}
                      {{ p.last }}
                    {% endif %}

                    <br>
                  {% endunless %}
                {% endfor %}
              {% endif %}
            </div>

          </div>
        </div>

        <div class="grid-item large--one-half medium--two-thirds push--medium--one-third cart-pricing">
          <div class="grid">

            <div class="grid-item one-third text-right">
              <input type="number" name="updates[]" id="updates_{{ item.key }}" data-id="{{ item.key }}" value="{{ item.quantity }}" min="0" data-line="{{ forloop.index }}">
            </div>

            <div class="grid-item one-half medium-down--text-left text-right">

              {%- if item.original_line_price != item.final_line_price -%}
                <span class="visually-hidden">{{ 'products.general.regular_price' | t }}</span>
                <small><s class="cart-original-price order-discount--cart-price">{{ item.original_line_price | money }}</s></small>
                <span class="visually-hidden">{{ 'products.general.sale_price' | t }}</span>
                <span class="order-discount order-discount--cart-price">{{ item.final_line_price | money }}</span>
              {%- else -%}
                <span class="cart-original-price order-discount--cart-price">{{ item.original_line_price | money }}</span>
              {%- endif -%}

              {%- if item.variant.available and item.variant.unit_price_measurement -%}
                {% include 'product-unit-price' variant: item, available: item.variant.available %}
              {%- endif -%}

              {%- if item.line_level_discount_allocations != blank -%}
                <ul class="order-discount order-discount--list order-discount--cart-list order-discount--title" aria-label="{{ 'customer.order.discount' | t }}">
                  {%- for discount_allocation in item.line_level_discount_allocations -%}
                    <li class="order-discount__item">
                      <span class="icon icon-saletag" aria-hidden="true"></span>{{ discount_allocation.discount_application.title }} (-{{ discount_allocation.amount | money }})
                    </li>
                  {%- endfor -%}
                </ul>
              {%- endif -%}
            </div>

            <div class="grid-item one-sixth text-right">
              <a href="{{ routes.cart_change_url }}?line={{ forloop.index }}&amp;quantity=0" data-line="{{ forloop.index }}" class="icon-fallback-text btn-secondary remove">
                <span class="icon icon-x" aria-hidden="true"></span>
                <span class="fallback-text">{{ 'cart.general.remove' | t }}</span>
              </a>
            </div>

          </div>
        </div>

      </div>
    </div>

    {% endfor %}

    <div class="cart-row">
      <div class="grid">

        {% if settings.cart_notes_enable %}
          <div class="grid-item large--one-half">
            <label for="cartSpecialInstructions">{{ 'cart.general.note' | t }}</label>
            <textarea name="note" class="input-full" id="cartSpecialInstructions">{{ cart.note }}</textarea>
          </div>
        {% endif %}

        <div class="grid-item text-right{% if settings.cart_notes_enable %} large--one-half{% endif %}">

          <div class="cart-subtotal{% if settings.cart_notes_enable %} cart-subtotal--notes-enabled{% endif %}">

            {%- if cart.cart_level_discount_applications != blank -%}
              <div class="order-discount-cart-wrapper">
                {%- for discount_application in cart.cart_level_discount_applications -%}
                  <span class="order-discount order-discount--title">
                    <span class="icon icon-saletag" aria-hidden="true"></span><span class="visually-hidden">{{ 'customer.order.discount' | t }}:</span>{{- discount_application.title -}}
                  </span>
                  <span class="order-discount order-discount--cart-price">-{{ discount_application.total_allocated_amount | money }}</span>
                {%- endfor -%}
              </div>
            {%- endif -%}

            {{ 'cart.general.subtotal' | t }}
            <span class="h1 cart-subtotal--price">
              {% include 'price' with cart.total_price %}
            </span>
          </div>

          {%- capture taxes_shipping_checkout -%}
            {%- if shop.taxes_included and shop.shipping_policy.body != blank -%}
              {{ 'cart.general.taxes_included_and_shipping_policy_html' | t: link: shop.shipping_policy.url }}
            {%- elsif shop.taxes_included -%}
              {{ 'cart.general.taxes_included_but_shipping_at_checkout' | t }}
            {%- elsif shop.shipping_policy.body != blank -%}
              {{ 'cart.general.taxes_and_shipping_policy_at_checkout_html' | t: link: shop.shipping_policy.url }}
            {%- else -%}
              {{ 'cart.general.taxes_and_shipping_at_checkout' | t }}
            {%- endif -%}
          {%- endcapture -%}

          <p class="cart__policies"><em>{{ taxes_shipping_checkout }}</em></p>

          <input type="submit" name="update" class="btn-secondary update-cart" value="{{ 'cart.general.update' | t }}">

          <button type="submit" name="checkout" class="btn">
            <span class="icon icon-cart"></span>
            {{ 'cart.general.checkout' | t }}
          </button>

          {% if additional_checkout_buttons %}
            <div class="additional-checkout-buttons">{{ content_for_additional_checkout_buttons }}</div>
          {% endif %}

        </div>

      </div>
    </div>

  </form>

{% else %}

  <div id="EmptyCart">
    <h1 class="h2">{{ 'cart.general.title' | t }}</h1>
    <p class="cart--empty-message">{{ 'cart.general.empty' | t }}</p>
    <p class="cart--continue-message">{{ 'cart.general.continue_browsing_html' | t: link: routes.all_products_collection_url }}</p>
    <p class="cart--cookie-message">{{ 'cart.general.cookies_required' | t }}</p>
  </div>

{% endif %}

カート内の商品表示部分

6~102行目部分でカート内の商品の表示を行なっています。

{% for item in cart.items %}
    <!- 商品情報の表示 -->
{% endfor %}

購入手続きボタン

2~166行目のformタグ,151~154行目のbuttonタグで購入ページへの遷移は管理しています。

formタグでカートページのurlにpostメソッドで出力することで購入に進めることができます。

<form action="{{ routes.cart_url }}" method="post" class="cart-form" data-cart-form novalidate>
  {% for item in cart.items %}
    <!- 商品情報の表示 -->
  {% endfor %}
  <button type="submit" name="checkout" class="btn">
    <span class="icon icon-cart"></span>
    {{ 'cart.general.checkout' | t }}
  </button>
</form>

カート内の商品の削除

90~93行目でカート内の商品の削除ボタンの管理をしています。

{% for item in cart.items %}
    <a href=“{{ routes.cart_change_url }}?line={{ forloop.index }}&amp;quantity=0” data-line=“{{ forloop.index }}” class=“icon-fallback-text btn-secondary remove”>
    <span class=“icon icon-x” aria-hidden=“true”></span>
    <span class=“fallback-text”>{{ ‘cart.general.remove’ | t }}</span>
  </a>
{% endfor %}

上記はSupply(shopify無料テーマ)のコードですが、ごちゃごちゃしてて見にくいですね。

{% for line in cart.items %}
  <a href="/cart/change?line={{ forloop.index }}&quantity=0">Remove</a>
{% endfor %}

上記が公式ドキュメントに載ってるコードです。

仕組みとしてはクエリパラメータのlineとquantityを投げてるだけっていうのがわかりますね。

forloop.indexはforループ内の現在のループのインデックスを出力します。

商品の個数変更

60行目で商品の個数変更部分を管理しています。

inputタグにname=”updates[]”をつけることで実装できます。

<input type="number" name="updates[]" id="updates_{{ item.key }}" data-id="{{ item.key }}" value="{{ item.quantity }}" min="0" data-line="{{ forloop.index }}">

注文メモ

こちらはSupply(shopify無料テーマ)では標準では実装されてません。

下記のコードを追加するだけで注文時のお客さんの個別の要望を受け取ることができます。

<textarea name="note"></textarea>

実際に95行目に上記のコードを入れて見た結果が下記です。

注文時にテキストエリアで入力ができるようになり、試しに「テスト」と入力し、テストで購入して見ました。

管理画面の注文管理から購入した商品を確認すると下記のように右上のメモの部分に入力した項目が表示されているのがわかります。

入力項目の追加

カートページの入力項目を追加する場合はformタグ内でinputタグにname=”attributes[some-value]”をつけて実装することができます。

※some-valueは任意の値

<p>
  <label>Please let us know your favorite color</label>
  <input
    type="text"
    name="attributes[Favorite color]"
    value="{{ cart.attributes['Favorite color'] }}"
  />
</p>

実際に95行目に上記のコードを入れて見た結果が下記です。

注文時にテキストエリアで入力ができるようになり、試しに「赤が好きです!」と入力し、テストで購入して見ました。

管理画面の注文管理から購入した商品を確認すると下記のように右上の追加の詳細の部分に入力した項目が表示されているのがわかります。

collection.liquid

collection.liquidでは商品一覧ページの大枠が格納されています。

商品につけてるタグでコレクション内で絞り込みができる

コレクションページのurlの末尾にタグ名を繋げると商品につけてるタグでコレクション内で絞り込みができます。

例えばmens jeansというコレクションがあって下記のurlにアクセスするとコレクションページが表示されるとします。

https://suzuki-yasu.myshopify.com/collections/mens-jeans

このうちNavy Jeansという商品にのみ「test」というタグがついてて、mens jeansコレクション内のtestタグがついてる商品のみ絞り込みたいとします。

この場合下記のurlにアクセスすると絞り込むことができます。

https://suzuki-yasu.myshopify.com/collections/mens-jeans/test
コレクション内の商品をソートできる

sort_byクエリパラメータを使うことで任意の条件でコレクション内の商品をソートすることができます。

http://my-store.myshopify.com/collections/all?sort_by=price-descending

上記のように、コレクションページurl?sort_by=条件というurlにアクセスすることで条件を指定してソートできます。

商品数が50点を超える場合はペジネーションを実装するべき

shopifyでは標準でコレクションページ1ページあたり、50点までの商品が表示されるようになっており、これを超える場合はペジネーションを実装する必要があります。

下記のようにpaginateタグを使うことで実装ができます。

{% paginate collection.products by 25 %}
  {% for product in collection.products %}
    <!--show product details here -->
    {{ paginate | default_pagination }}
  {% endfor %}
{% endpaginate %}

customers/account.liquid


customersディレクトリ内のaccount.liquidではアカウント詳細ページの大枠が格納されています。

ファイルの中身の解説

ここではaccount.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
<h1>{{ 'customer.account.title' | t }}</h1>

<hr class="hr--small">

<div class="grid">

  <div class="grid-item two-thirds medium-down--one-whole">
    <h2 class="h4">{{ 'customer.orders.title' | t }}</h2>

    {% paginate customer.orders by 20 %}
    {% if customer.orders.size != 0 %}

      <table class="full">
        <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>
              <td>{{ order.name | link_to: order.customer_url }}</td>
              <td>{{ order.created_at | date: format: 'date' }}</td>
              <td>{{ order.financial_status_label }}</td>
              <td>{{ order.fulfillment_status_label }}</td>
              <td>{{ order.total_price | money }}</td>
            </tr>
          {% endfor %}
        </tbody>
      </table>

    {% else %}

      <p>{{ 'customer.orders.none' | t }}</p>

    {% endif %}

    {% if paginate.pages > 1 %}
    <div class="text-center">
      {% include 'pagination-custom' %}
    </div>
    {% endif %}
    {% endpaginate %}
  </div>

  <div class="grid-item one-third medium-down--one-whole">
    <h2 class="h4">{{ 'customer.account.details' | t }}</h2>

    {{ customer.default_address | format_address }}

    <p><a href="{{ routes.account_addresses_url }}">{{ 'customer.account.view_addresses' | t }} ({{ customer.addresses_count }})</a></p>
  </div>

</div>

現在の注文履歴の表示

24~32行目で現在の注文履歴を表示しています。

{% for order in customer.orders %}
  <tr>
    <td>{{ order.name | link_to: order.customer_url }}</td>
    <td>{{ order.created_at | date: format: 'date' }}</td>
    <td>{{ order.financial_status_label }}</td>
    <td>{{ order.fulfillment_status_label }}</td>
    <td>{{ order.total_price | money }}</td>
  </tr>
{% endfor %}

デフォルトの住所を表示

53行目でデフォルトの住所の表示を行なっています。

{{ customer.default_address | format_address }}

住所の情報はcustomer.default_addressオブジェクトに全て格納されています。

都道府県や市町村などの情報を分けて表示したい場合は下記のように実装することもできます。

{% if customer.default_address %}
  <p>{{ customer.default_address.address1 }}</p>
  {% if customer.default_address.address2 != "" %}
    <p>{{ customer.default_address.address2 }}</p>
  {% endif %}
  <p>{{ customer.default_address.city}}, {% if address.province_code %}{{ customer.default_address.province_code }}, {% endif %}{{ customer.default_address.country }}</p>
  <p>{{ customer.default_address.zip }}</p>
  <p>{{ customer.default_address.phone }}</p>
{% endif %}

注文履歴の表示件数が多い場合のペジネーション

10~47行目でペジネーションの管理をしています。

コード
{% paginate customer.orders by 20 %}
{% if customer.orders.size != 0 %}

  <table class="full">
    <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>
          <td>{{ order.name | link_to: order.customer_url }}</td>
          <td>{{ order.created_at | date: format: 'date' }}</td>
          <td>{{ order.financial_status_label }}</td>
          <td>{{ order.fulfillment_status_label }}</td>
          <td>{{ order.total_price | money }}</td>
        </tr>
      {% endfor %}
    </tbody>
  </table>

{% else %}

  <p>{{ 'customer.orders.none' | t }}</p>

{% endif %}

{% if paginate.pages > 1 %}
<div class="text-center">
  {% include 'pagination-custom' %}
</div>
{% endif %}
{% endpaginate %}

customers/activate_account.liquid


customersディレクトリ内のactivate_account.liquidではアカウント有効化ページの大枠が格納されています。

activate_account.liquidの確認方法

1. 管理画面からテスト用の顧客を追加する

まずはshopifyの管理画面の顧客管理画面の右上の「顧客を追加する」から顧客をテストで追加します。

顧客を追加する」ボタンを押すと顧客の情報を入力する画面に移動するので、名前のみ入力して保存します。

2. アカウントの招待を送信する

テスト用の顧客を登録すると顧客画面に遷移します。ここで右上の「アカウントの招待を送信する」ボタンを押します。

すると宛先の入力があるので、顧客登録用のメールアドレスを入力します

メールを確認する」ボタンを押すとメールの確認ページに遷移するので「通知を送信する」ボタンを押します。

メールを確認する

すると顧客データのところで入力したメールアドレスに以下のようなメールが届くので、「アカウントを有効にする」ボタンを押します。

activate_account.liquidページが確認できる

するとactivate_account.liquidページの確認ができます。

ファイルの中身

ここではactivate_account.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
<div class="grid">
  <div class="grid-item large--one-third push--large--one-third">

    <h1>{{ 'customer.activate_account.title' | t }}</h1>
    <p>{{ 'customer.activate_account.subtext' | t }}</p>

    {% form 'activate_customer_password' %}

      {% include 'form-errors-custom' %}

      <label for="customer_password">{{ 'customer.activate_account.password' | t }}</label>
      <input type="password" value="" name="customer[password]" id="customer_password">

      <label for="customer_password_confirmation">{{ 'customer.activate_account.password_confirm' | t }}</label>
      <input type="password" value="" name="customer[password_confirmation]" id="customer_password_confirmation">

      <div class="text-center">

          <p><input type="submit" class="btn" value="{{ 'customer.activate_account.submit' | t }}"></p>
          <p><input type="submit" class="btn-secondary" name="decline" id="customer_decline" value="{{ 'customer.activate_account.cancel' | t }}"></p>

      </div>
    {% endform %}

  </div>
</div>

アカウント有効化フォームはformタグを使ってactivate_customer_passwordを値に入れて実装する必要があります。

formタグ内にはパスワードの入力欄とパスワードの確認の入力欄の二つが必要になります。

inputタグでtypeをpasswordにして、name=”customer[password]”name=”customer[password_confirmation]”のものを用意することで実装することができます。

customers/addresses.liquid


customersディレクトリ内のaddresses.liquidではアカウントの住所ページの大枠が格納されています。

ファイルの中身

ここではaddress.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
<header class="section-header">
  <h1 class="section-header--left">{{ 'customer.account.title' | t }}</h1>
  <div class="section-header--right">
    <a href="#" class="btn btn--small" onclick="Shopify.CustomerAddress.toggleNewForm(); return false;">{{ 'customer.addresses.add_new' | t }}</a>
  </div>
</header>

<hr class="hr--small">

<div class="grid">

  <div class="grid-item one-third medium-down--one-whole">
    <p><a href="{{ routes.account_url }}">{{ 'customer.account.return' | t }}</a></p>
  </div>
  <div class="grid-item two-thirds medium-down--one-whole">
    {% form 'customer_address', customer.new_address %}

      <div id="add_address" {% unless form.errors %}style="display: none;"{% endunless %}>

        <h2>{{ 'customer.addresses.add_new' | t }}</h2>

        {% include 'form-errors-custom' %}

        <div class="grid">

          <div class="grid-item one-half small--one-whole">
            <label for="address_first_name_new">{{ 'customer.addresses.first_name' | t }}</label>
            <input type="text" id="address_first_name_new" class="address_form" name="address[first_name]" value="{{ form.first_name }}">
          </div>

          <div class="grid-item one-half small--one-whole">
            <label for="address_last_name_new">{{ 'customer.addresses.last_name' | t }}</label>
            <input type="text" id="address_last_name_new" class="address_form" name="address[last_name]" value="{{ form.last_name }}">
          </div>

        </div>

        <label for="address_company_new">{{ 'customer.addresses.company' | t }}</label>
        <input type="text" id="address_company_new" class="address_form" name="address[company]" value="{{ form.company }}">

        <label for="address_address1_new">{{ 'customer.addresses.address1' | t }}</label>
        <input type="text" id="address_address1_new" class="address_form" name="address[address1]" value=" {{ form.address1 }}">

        <label for="address_address2_new">{{ 'customer.addresses.address2' | t }}</label>
        <input type="text" id="address_address2_new" class="address_form" name="address[address2]" value=" {{ form.address2 }}">

        <div class="grid">
          <div class="grid-item large--one-half">
            <label for="address_city_new">{{ 'customer.addresses.city' | t }}</label>
            <input type="text" id="address_city_new" class="address_form" name="address[city]" value="{{ form.city }}">
          </div>

          <div class="grid-item large--one-half">
            <label for="address_country_new">{{ 'customer.addresses.country' | t }}</label>
            <select id="address_country_new" name="address[country]" data-default="{{ form.country }}">{{ all_country_option_tags }}</select>
          </div>

          <div class="grid-item" id="address_province_container_new" style="display:none">
            <label for="address_province_new">{{ 'customer.addresses.province' | t }}</label>
            <select id="address_province_new" class="address_form" name="address[province]" data-default="{{ form.province }}"></select>
          </div>

          <div class="grid-item large--one-half">
            <label for="address_zip_new">{{ 'customer.addresses.zip' | t }}</label>
            <input type="text" id="address_zip_new" class="address_form" name="address[zip]" value="{{ form.zip }}" autocapitalize="characters">
          </div>

          <div class="grid-item large--one-half">
            <label for="address_phone_new">{{ 'customer.addresses.phone' | t }}</label>
            <input type="tel" id="address_phone_new" class="address_form" name="address[phone]" value="{{ form.phone }}" placeholder="555-555-1234">
          </div>
        </div>

        <p>
          {{ form.set_as_default_checkbox }}
          <label for="address_default_address_new" class="inline">{{ 'customer.addresses.set_default' | t }}</label>
        </p>

        <input type="submit" class="btn" value="{{ 'customer.addresses.add' | t }}">
        <span class="form-spacer">{{ 'customer.addresses.or' | t }}</span>
        <a href="#" onclick="Shopify.CustomerAddress.toggleNewForm(); return false;">{{ 'customer.addresses.cancel' | t }}</a>

        <hr>
      </div>
    {% endform %}

    <h2>{{ 'customer.addresses.title' | t }}</h2>

    {% paginate customer.addresses by 5 %}
      {% for address in customer.addresses %}

        <h3>
          {{ address.first_name | capitalize }} {{ address.last_name | capitalize }}
          {% if address == customer.default_address %}<em>({{ 'customer.addresses.default' | t }})</em>{% endif %}
        </h3>

        {{ address | format_address }}

        <p>
          {{ 'customer.addresses.edit' | t | edit_customer_address_link: address.id }} |
          {{ 'customer.addresses.delete' | t | delete_customer_address_link: address.url }}
        </p>

        {% form 'customer_address', address %}
          <div id="edit_address_{{ address.id }}" {% unless form.errors %}style="display:none;"{% endunless %}>

            <h4>{{ 'customer.addresses.edit_address' | t }}</h4>
            {% include 'form-errors-custom' %}
            <div class="grid">

              <div class="grid-item one-half small--one-whole">
                <label for="address_first_name_{{ form.id }}">{{ 'customer.addresses.first_name' | t }}</label>
                <input type="text" id="address_first_name_{{ form.id }}" class="address_form" name="address[first_name]" value="{{ form.first_name }}">
              </div>

              <div class="grid-item one-half small--one-whole">
                <label for="address_last_name_{{ form.id }}">{{ 'customer.addresses.last_name' | t }}</label>
                <input type="text" id="address_last_name_{{ form.id }}" class="address_form" name="address[last_name]" value="{{ form.last_name }}">
              </div>

            </div>

            <label for="address_company_{{ form.id }}">{{ 'customer.addresses.company' | t }}</label>
            <input type="text" id="address_company_{{ form.id }}" class="address_form" name="address[company]" value="{{ form.company }}">

            <label for="address_address1_{{ form.id }}">{{ 'customer.addresses.address1' | t }}</label>
            <input type="text" id="address_address1_{{ form.id }}" class="address_form" name="address[address1]" value="{{ form.address1 }}">

            <label for="address_address2_{{ form.id }}">{{ 'customer.addresses.address2' | t }}</label>
            <input type="text" id="address_address2_{{ form.id }}" class="address_form" name="address[address2]" value="{{ form.address2 }}">

            <label for="address_city_{{ form.id }}">{{ 'customer.addresses.city' | t }}</label>
            <input type="text" id="address_city_{{ form.id }}" class="address_form" name="address[city]" value="{{ form.city }}">

            <label for="address_country_{{ form.id }}">{{ 'customer.addresses.country' | t }}</label>
            <select id="address_country_{{ form.id }}" name="address[country]" data-default="{{ form.country }}">{{ all_country_option_tags }}</select>

            <div id="address_province_container_{{ form.id }}" style="display:none">
              <label for="address_province_{{ form.id }}">{{ 'customer.addresses.province' | t }}</label>
              <select id="address_province_{{ form.id }}" class="address_form" name="address[province]" data-default="{{ form.province }}"></select>
            </div>

            <div class="grid">
              <div class="grid-item one-half small--one-whole">
                <label for="address_zip_{{ form.id }}">{{ 'customer.addresses.zip' | t }}</label>
                <input type="text" id="address_zip_{{ form.id }}" class="address_form" name="address[zip]" value="{{ form.zip }}" autocapitalize="characters">
              </div>

              <div class="grid-item one-half small--one-whole">
                <label for="address_phone_{{ form.id }}">{{ 'customer.addresses.phone' | t }}</label>
                <input type="tel" id="address_phone_{{ form.id }}" class="address_form" name="address[phone]" value="{{ form.phone }}" placeholder="555-555-1234">
              </div>
            </div>

            <p>
              {{ form.set_as_default_checkbox }}
              <label for="address_default_address_new" class="inline">{{ 'customer.addresses.set_default' | t }}</label>
            </p>

            <input type="submit" class="btn" value="{{ 'customer.addresses.update' | t }}">
            {{ 'customer.addresses.or' | t }} <a href="#" onclick="Shopify.CustomerAddress.toggleForm({{ form.id }}); return false;">{{ 'customer.addresses.cancel' | t }}</a>

            <hr>
          </div>
        {% endform %}

        <script>
          // Setup province selector on each customer address
          new Shopify.CountryProvinceSelector('address_country_{{ address.id }}', 'address_province_{{ address.id }}', {
            hideElement: 'address_province_container_{{ address.id }}'}
          );
        </script>

      {% endfor %}

      {% if paginate.pages > 1 %}
      <div class="text-center">
        {% include 'pagination-custom' %}
      </div>
      {% endif %}

    {% endpaginate %}
  </div>

</div>


<script>
  // Initialize observers on address selectors
  new Shopify.CountryProvinceSelector('address_country_new', 'address_province_new', {
    hideElement: 'address_province_container_new'
  });

  // Contents of customer_area.js (global asset)
  Shopify.CustomerAddress = {
    toggleForm: function(id) {
      var editEl = document.getElementById('edit_address_'+id);
      editEl.style.display = editEl.style.display == 'none' ? '' : 'none';
      return false;
    },

    toggleNewForm: function() {
      var el = document.getElementById('add_address');
      el.style.display = el.style.display == 'none' ? '' : 'none';
      return false;
    },

    destroy: function(url, confirm_msg) {
      if (confirm(confirm_msg || {{ 'customer.addresses.delete_confirm' | t | json }})) {
        Shopify.postLink(url, {'parameters': {'_method': 'delete'}});
      }
    }
  }
</script>

新しい住所を追加する

16~85行目で「新しい住所を追加する」ボタン部分を実装しています。

{% form 'customer_address', customer.new_address %}
  ...
    <!-- form contents here -->
  ...
{% endform %}

formタグの中身で「新しい住所を追加する」ボタンを押した後に表示されるフォームの中身を実装しています。

<input type="text" name="address[first_name]" size="40" />

フォームの中身は上記のようにinputタグで構成されており、フォームを正常に動作させるには下記のように対応させる必要があります。

入力情報typeの値nameの値
名前textaddress[first_name]
苗字textaddress[last_name]
会社名textaddress[company]
住所textaddress[address1]
建物名、部屋番号などtextaddress[address2]
市区町村textaddress[city]
selectaddress[country]
都道府県selectaddress[province]
郵便番号texttext address[zip]
電話番号teladdress[phone]

住所の編集

90~174行目で住所の編集が実装されています。

forループ内で’customer_address’, addressを使ったformタグで実装されています。

 {% for address in customer.addresses %} ... {% form
'customer_address', address %} ... {% endform %} ... {% endfor %} 

住所の削除

101行目で住所の削除が実装されています。

{{ 'customer.addresses.delete' | t | delete_customer_address_link: address.url }}

194~213行目でクリック時の動作を実装しています。

  // Contents of customer_area.js (global asset)
  Shopify.CustomerAddress = {
    destroy: function(url, confirm_msg) {
      if (confirm(confirm_msg || {{ 'customer.addresses.delete_confirm' | t | json }})) {
        Shopify.postLink(url, {'parameters': {'_method': 'delete'}});
      }
    }
  }

customers/login.liquid

customersディレクトリ内のlogin.liquidではアカウントのログインページの大枠が格納されています。

ファイルの中身

ここではlogin.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
<div class="grid">

  <div class="grid-item large--one-third push--large--one-third text-center">

    <div class="note form-success" id="resetSuccess" style="display:none;">
      We've sent you an email with a link to update your password.
    </div>

    {% form 'customer_login' %}

      <h1>{{ 'customer.login.title' | t }}</h1>

      {% include 'form-errors-custom' %}

      <label for="customer_email" class="hidden-label">{{ 'customer.login.email' | t }}</label>
      <input type="email" value="" name="customer[email]" id="customer_email" placeholder="{{ 'customer.login.email' | t }}" {% if form.errors contains "email" %} class="error"{% endif %} autocorrect="off" autocapitalize="off" autofocus>

      {% if form.password_needed %}

        <label for="customer_password" class="hidden-label">{{ 'customer.login.password' | t }}</label>
        <input type="password" value="" name="customer[password]" id="customer_password" placeholder="{{ 'customer.login.password' | t }}" {% if form.errors contains "password" %} class="error"{% endif %}>

        <p>
          <a href="#" onclick="showRecoverPasswordForm();return false;">{{ 'customer.login.forgot_password' | t }}</a>
        </p>

      {% endif %}

        <p>
          <input type="submit" class="btn" value="{{ 'customer.login.sign_in' | t }}">
        </p>
        {{ 'customer.login.or' | t }} <a href="{{ shop.url }}">{{ 'customer.login.cancel' | t }}</a>

    {% endform %}


    {% comment %}
      This page uses JavaScript to show/hide the recover password form
    {% endcomment %}
    <div id="recover_password" style="display: none;">

      <h2>{{ 'customer.recover_password.title' | t }}</h2>
      <p>{{ 'customer.recover_password.subtext' | t }}</p>

      {% form 'recover_customer_password' %}

        {% include 'form-errors-custom' %}

        {% if form.posted_successfully? %}
          {% assign reset_success = true %}
        {% endif %}

        <label for="recover-email" class="hidden-label">{{ 'customer.recover_password.email' | t }}</label>
        <input type="email" value="" name="email" id="recover-email" placeholder="{{ 'customer.recover_password.email' | t }}" autocorrect="off" autocapitalize="off">

        <p>
          <input type="submit" class="btn" value="{{ 'customer.recover_password.submit' | t }}">
        </p>
        {{ 'customer.login.or' | t }} <a href="#" onclick="hideRecoverPasswordForm();return false;">{{ 'customer.recover_password.cancel' | t }}</a>
        
      {% endform %}

    </div>

    {% if shop.checkout.guest_login %}
      <hr>

      <h2>{{ 'customer.login.guest_title' | t }}</h2>

      {% form 'guest_login' %}
        <input  type="submit" class="btn" value="{{ 'customer.login.guest_continue' | t }}">
      {% endform %}
      
    {% endif %}

  </div>

</div>



<script>
  /*
    Show/hide the recover password form when requested.
  */
  function showRecoverPasswordForm() {
    document.getElementById('recover_password').style.display = 'block';
    document.getElementById('customer_login').style.display='none';
  }

  function hideRecoverPasswordForm() {
    document.getElementById('recover_password').style.display = 'none';
    document.getElementById('customer_login').style.display = 'block';
  }

  // Allow deep linking to the recover password form
  if (window.location.hash == '#recover') { showRecoverPasswordForm() }

  // reset_success is only true when the reset form is
  {% if reset_success %}
    document.getElementById('resetSuccess').style.display = 'block';
  {% endif %}
</script>

ログインページへのリンクの貼り方

ログインページへ飛ぶにはまずはログインページへのリンクをはらなくてはいけません。

こちらはlogin.liquidではなく、sectionディレクトリ内のheader.liquid内で定義されています。

shopifyの管理画面からもコードを確認できますが、一様header.liquidのコードを下記に記載しておきます。

コード
<header class="site-header" role="banner" data-section-id="{{ section.id }}" data-section-type="header-section">
  <div class="wrapper">

    <div class="grid--full">
      <div class="grid-item large--one-half">
        {% if request.page_type == 'index' %}
          <h1 class="header-logo" itemscope itemtype="http://schema.org/Organization">
        {% else %}
          <div class="h1 header-logo" itemscope itemtype="http://schema.org/Organization">
        {% endif %}
          {% if section.settings.logo %}
          {% capture image_size %}{{ section.settings.logo_max_width | escape }}x{% endcapture %}
          {%- assign img_url = section.settings.logo | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}
          {% capture logo_alt %}{{ section.settings.logo.alt | default: shop.name }}{% endcapture %}
          <a href="{{ routes.root_url }}" itemprop="url">
            <div class="lazyload__image-wrapper no-js header-logo__image" style="max-width:{{ section.settings.logo_max_width }}px;">
              <div style="padding-top:{{ 1 | divided_by: section.settings.logo.aspect_ratio | times: 100}}%;">
                <img class="lazyload js"
                  data-src="{{ img_url }}"
                  data-widths="[180, 360, 540, 720, 900, 1080, 1296, 1512, 1728, 2048]"
                  data-aspectratio="{{ section.settings.logo.aspect_ratio }}"
                  data-sizes="auto"
                  alt="{{ logo_alt | escape }}"
                  style="width:{{ section.settings.logo_max_width }}px;">
              </div>
            </div>
            <noscript>
              {% capture image_size %}{{ section.settings.logo_max_width | escape }}x{% endcapture %}
              <img src="{{ section.settings.logo | img_url: image_size }}"
                srcset="{{ section.settings.logo | img_url: image_size }} 1x, {{ section.settings.logo | img_url: image_size, scale: 2 }} 2x"
                alt="{{ logo_alt | escape }}"
                itemprop="logo"
                style="max-width:{{ section.settings.logo_max_width }}px;">
            </noscript>
          </a>
          {% else %}
            <a href="{{ routes.root_url }}" itemprop="url">{{ shop.name }}</a>
          {% endif %}
        {% if request.page_type == 'index' %}
          </h1>
        {% else %}
          </div>
        {% endif %}
      </div>

      <div class="grid-item large--one-half text-center large--text-right">
        {% if section.settings.show_announcement or shop.customer_accounts_enabled %}
          <div class="site-header--text-links{% if section.settings.announcement_text == blank %} medium-down--hide{% endif %}">
            {% if section.settings.show_announcement %}
              {% if section.settings.announcement_link != blank %}
                <a href="{{ section.settings.announcement_link }}">
              {% endif %}

                <p>{{ section.settings.announcement_text | escape }}</p>

              {% if section.settings.announcement_link != blank %}
                </a>
              {% endif %}
            {% endif %}

            {% if shop.customer_accounts_enabled %}
              <span class="site-header--meta-links medium-down--hide">
                {% if customer %}
                  {% capture first_name %}<a href="{{ routes.account_url }}">{{ customer.first_name }}</a>{% endcapture %}
                  {{ 'layout.customer.logged_in_as_html' | t: first_name: first_name }} &middot; {{ 'layout.customer.log_out' | t | customer_logout_link }}
                {% else %}
                  {{ 'layout.customer.sign_in' | t | customer_login_link }}
                  <span class="site-header--spacer">{{ 'layout.customer.or' | t }}</span>
                  {{ 'layout.customer.create_account' | t | customer_register_link }}
                {% endif %}
              </span>
            {% endif %}
          </div>

          <br class="medium-down--hide">
        {% endif %}

        {% include 'search-bar' %}

        <a href="{{ routes.cart_url }}" class="header-cart-btn cart-toggle">
          <span class="icon icon-cart"></span>
          {{ 'layout.cart.cart' | t }} <span class="cart-count cart-badge--desktop {% if cart.item_count == 0 %}hidden-count{% endif %}">{{ cart.item_count }}</span>
        </a>
      </div>
    </div>

  </div>
</header>

<div id="mobileNavBar">
  <div class="display-table-cell">
    <button class="menu-toggle mobileNavBar-link" aria-controls="navBar" aria-expanded="false"><span class="icon icon-hamburger" aria-hidden="true"></span>{{ 'layout.navigation.mobile_menu' | t }}</button>
  </div>
  <div class="display-table-cell">
    <a href="{{ routes.cart_url }}" class="cart-toggle mobileNavBar-link">
      <span class="icon icon-cart"></span>
      {{ 'layout.cart.cart' | t }} <span class="cart-count {% if cart.item_count == 0 %}hidden-count{% endif %}">{{ cart.item_count }}</span>
    </a>
  </div>
</div>

<nav class="nav-bar" id="navBar" role="navigation">
  <div class="wrapper">
    {% include 'search-bar' %}
    {% include 'mobile-nav' %}
    {% include 'site-nav' %}
  </div>
</nav>

※shema部分は省略してます。

61-72行目でログインページへのリンクを制御しています。

{% if shop.customer_accounts_enabled %}
    <span class="site-header--meta-links medium-down--hide">
        {% if customer %}
            {% capture first_name %}<a href="{{ routes.account_url }}">{{ customer.first_name }}</a>{% endcapture %}
            {{ 'layout.customer.logged_in_as_html' | t: first_name: first_name }} &middot; {{ 'layout.customer.log_out' | t | customer_logout_link }}
        {% else %}
            {{ 'layout.customer.sign_in' | t | customer_login_link }}
            <span class="site-header--spacer">{{ 'layout.customer.or' | t }}</span>
            {{ 'layout.customer.create_account' | t | customer_register_link }}
        {% endif %}
    </span>
{% endif %}

まず{% if shop.customer_accounts_enabled %}部分で、顧客アカウントが有効化されているかどうかを条件分岐しています。

shopify管理画面>設定>チェックアウト>顧客アカウント」で顧客アカウントは有効化でき、「アカウントを無効化する」以外が選択されていれば上記の条件分岐ではtrueが返ります。

次に{% if customer %}部分で既にログイン済みかどうかを判定しています。

{% if customer %}
{% comment %} ログイン済みであれば下記が表示される{% endcomment %}
            {% capture first_name %}<a href="{{ routes.account_url }}">{{ customer.first_name }}</a>{% endcapture %}
            {{ 'layout.customer.logged_in_as_html' | t: first_name: first_name }} &middot;   {{ 'layout.customer.log_out' | t | customer_logout_link }}

{% else %}
{% comment %} ログインしていなければ下記が表示される{% endcomment %}
            {{ 'layout.customer.sign_in' | t | customer_login_link }}
            <span class="site-header--spacer">{{ 'layout.customer.or' | t }}</span>
            {{ 'layout.customer.create_account' | t | customer_register_link }}
{% endif %}

ログインフォームの実装

9-34行目でログインフォームが実装されています。

    {% form 'customer_login' %}

      <h1>{{ 'customer.login.title' | t }}</h1>

      {% include 'form-errors-custom' %}

      <label for="customer_email" class="hidden-label">{{ 'customer.login.email' | t }}</label>
      <input type="email" value="" name="customer[email]" id="customer_email" placeholder="{{ 'customer.login.email' | t }}" {% if form.errors contains "email" %} class="error"{% endif %} autocorrect="off" autocapitalize="off" autofocus>

      {% if form.password_needed %}

        <label for="customer_password" class="hidden-label">{{ 'customer.login.password' | t }}</label>
        <input type="password" value="" name="customer[password]" id="customer_password" placeholder="{{ 'customer.login.password' | t }}" {% if form.errors contains "password" %} class="error"{% endif %}>

        <p>
          <a href="#" onclick="showRecoverPasswordForm();return false;">{{ 'customer.login.forgot_password' | t }}</a>
        </p>

      {% endif %}

        <p>
          <input type="submit" class="btn" value="{{ 'customer.login.sign_in' | t }}">
        </p>
        {{ 'customer.login.or' | t }} <a href="{{ shop.url }}">{{ 'customer.login.cancel' | t }}</a>

    {% endform %}

ログインフォームの実装はformタグにcustomer_loginパラメータを渡してやることで実装できます。

フォームの中身には

inputタグでtypeがemailでnameが customer[email]
inputタグでtypeがpasswordでnameが customer[password]

上記の項目が必要です。

パスワードを忘れた際のリセット

40-63行目でパスワードを忘れた際のリセットフォームの実装をしています。

<div id="recover_password" style="display: none;">

      <h2>{{ 'customer.recover_password.title' | t }}</h2>
      <p>{{ 'customer.recover_password.subtext' | t }}</p>

      {% form 'recover_customer_password' %}

        {% include 'form-errors-custom' %}

        {% if form.posted_successfully? %}
          {% assign reset_success = true %}
        {% endif %}

        <label for="recover-email" class="hidden-label">{{ 'customer.recover_password.email' | t }}</label>
        <input type="email" value="" name="email" id="recover-email" placeholder="{{ 'customer.recover_password.email' | t }}" autocorrect="off" autocapitalize="off">

        <p>
          <input type="submit" class="btn" value="{{ 'customer.recover_password.submit' | t }}">
        </p>
        {{ 'customer.login.or' | t }} <a href="#" onclick="hideRecoverPasswordForm();return false;">{{ 'customer.recover_password.cancel' | t }}</a>
        
      {% endform %}

</div>

formタグにrecover_customer_passwordパラメータを渡すことで実装できます。

フォームの中身には下記の項目が必要です。
inputタグでtypeがemail、nameがemail


リセットがうまくいくとリセット手順の乗ったメールが届きます。

決済時のゲストログインの実装

未ログイン時に決済ページからログインしようとしたときにゲストログインを選択するかどうかを選べるようになります。

65-74行目でゲストログイン部分が実装されています。

    {% if shop.checkout.guest_login %}
      <hr>

      <h2>{{ 'customer.login.guest_title' | t }}</h2>

      {% form 'guest_login' %}
        <input  type="submit" class="btn" value="{{ 'customer.login.guest_continue' | t }}">
      {% endform %}
      
    {% endif %}

ゲストログインを有効化にするには

shopify管理画面>設定>チェックアウト>顧客アカウント」で「アカウントを任意にする」を選択してる必要があります。

customers/order.liquid


customersディレクトリ内のorder.liquidではアカウントの注文詳細ページの大枠が格納されています。

ここではorderオブジェクトを使うことで注文に関する様々な情報にアクセスすることができるようになっています。

customers/register.liquid


customersディレクトリ内のregister.liquidではアカウントの新規登録ページの大枠が格納されています。

ファイルの中身

ここではregister.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
<div class="grid">

  <div class="grid-item large--one-third push--large--one-third text-center">

    <h1>{{ 'customer.register.title' | t }}</h1>

    {% form 'create_customer' %}

      {% include 'form-errors-custom' %}

      <label for="first_name" class="hidden-label">{{ 'customer.register.first_name' | t }}</label>
      <input type="text" value="" name="customer[first_name]" id="first_name" placeholder="{{ 'customer.register.first_name' | t }}" {% if form.errors contains "first_name" %} class="error"{% endif %} autofocus>

      <label for="last_name" class="hidden-label">{{ 'customer.register.last_name' | t }}</label>
      <input type="text" value="" name="customer[last_name]" id="last_name" placeholder="{{ 'customer.register.last_name' | t }}" {% if form.errors contains "last_name" %} class="error"{% endif %}>

      <label for="email" class="hidden-label">{{ 'customer.register.email' | t }}</label>
      <input type="email" value="" name="customer[email]" id="email" placeholder="{{ 'customer.register.email' | t }}" {% if form.errors contains "email" %} class="error"{% endif %} autocorrect="off" autocapitalize="off">

      <label for="password" class="hidden-label">{{ 'customer.register.password' | t }}</label>
      <input type="password" value="" name="customer[password]" id="create_password" placeholder="{{ 'customer.register.password' | t }}" {% if form.errors contains "password" %} class="error"{% endif %}>
      <p>
        <input type="submit" value="{{ 'customer.register.submit' | t }}" class="btn">
      </p>
      {{ 'customer.register.or' | t }} <a href="{{ shop.url }}">{{ 'customer.register.cancel' | t }}</a>

    {% endform %}

  </div>

</div>

会員登録フォームの実装

formタグcreate_customerパラメータを渡すことで実装できます。

フォームの中身には下記の項目が必要です。
inputタグでtypeがtext、nameがcustomer[first_name]
inputタグでtypeがtext、nameがcustomer[last_name]
inputタグでtypeがemail、nameがcustomer[email]
inputタグでtypeがpassword、nameがcustomer[password]
inputタグでtypeがsubmit

customers/reset_password.liquid


customersディレクトリ内のreset_password.liquidではアカウントのパスワード再発行ページの大枠が格納されています。

reset_password.liquidの確認の仕方

1. ログインページに移動

上記のように、ログインページから「パスワードをお忘れですか?」ボタンをクリックする

2. メールアドレスを入力する

パスワードをリセットしたいアカウントのメールアドレスを入力する

3. 届いたメールを確認する

入力したメールアドレス宛に上記のようなメールが届くので、「パスワードをリセット」ボタンをクリックする。

4. パスワードリセットページの確認

これで上記のようにパスワードのリセットページに飛ぶことができます。

ファイルの中身

ここではreset_password.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
<div class="grid">
  <div class="grid-item large--one-third push--large--one-third">

    {% form 'reset_customer_password' %}

      <h1>{{ 'customer.reset_password.title' | t }}</h1>

      <p>{{ 'customer.reset_password.subtext' | t: email: email }}</p>

      {% include 'form-errors-custom' %}

      <label for="reset_password">{{ 'customer.reset_password.password' | t }}</label>
      <input type="password" value="" name="customer[password]" id="reset_password" {% if form.errors contains "password" %} class="error"{% endif %}>

      <label for="password_confirmation">{{ 'customer.reset_password.password_confirm' | t }}</label>
      <input type="password" value="" name="customer[password_confirmation]" id="password_confirmation" {% if form.errors contains "password_confirmation" %} class="error"{% endif %}>

      <div class="text-center">
        <input type="submit" class="btn" value="{{ 'customer.reset_password.submit' | t }}">
      </div>

    {% endform %}

  </div>
</div>

パスワードのリセットフォームの実装

formタグreset_customer_passwordパラメータを渡すことで実装できます。

フォームの中身には下記の項目が必要です。
inputタグでtypeがpassword、nameがcustomer[password]
inputタグでtypeがpassword、nameがcustomer[password_confirmation]
inputタグでtypeがsubmit

gift_card.liquid


gift_card.liquidではギフトカードページの大枠が格納されています。

index.liquid


index.liquidではトップページの大枠が格納されています。

ファイルの中身

ここではindex.liquidに記述されている中身に関して見ていきます。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
{{ content_for_index }}

index.htmlでは{{ content_for_index }}を読み込む必要があります。

これを読み込まないと管理画面のテーマエディタから動的セクションの編集ができなくなります。

list-collections.liquid


list-collections.liquidでは商品カテゴリ一覧ページの大枠が格納されています。

/collections」のurlにアクセスすると該当するページを確認することができます。

page.liquid


page.liquidでは固定ページの大枠が格納されています。

search.liquid

search.liquidでは検索結果ページの大枠が格納されています。

検索バーの読み込み

検索結果ページにたどり着くには検索バーをどこかで読み込む必要があります。

今回はshopifyの無料テーマ「Supply」を元に解説していきます。

supplyではsection/header.liquidでsearchbar.liquidというスニペットを読み込むことで検索バーを表示させてます。

shopifyの管理画面からもコードを確認できますが、一様コードを下記に記載しておきます。

コード
<form action=“{{ routes.search_url }}” method=“get” class=“search-bar” role=“search”>
  <input type=“hidden” name=“type” value=“product”>

  <input type=“search” name=“q” value=“{{ search.terms | escape }}” placeholder=“{{ ‘layout.search_bar.placeholder’ | t }}” aria-label=“{{ ‘layout.search_bar.placeholder’ | t }}“>
  <button type=“submit” class=“search-bar--submit icon-fallback-text”>
    <span class=“icon icon-search” aria-hidden=“true”></span>
    <span class=“fallback-text”>{{ ‘layout.search_bar.submit’ | t }}</span>
  </button>
</form>

formタグactionの値を/searchにすることで検索バーを実装できます。

(上記のコードではactionの値が{{ routes.search_url }}になっていますが、これはroutesオブジェクトから値を取り出しているだけで出力されるのは/searchが出力されるのでやってることは同じです)

フォームの中身には下記の項目が必要です。
inputタグでnameがq
inputタグでtypeがsubmit

nameがqになってるinputタグ部分が検索バーのメインの部分になりますが、検索しても検索後のページに検索ワードが残るようにvalueの値が{{ search.terms | escape }}になっています。

参考文献

英語の公式ドキュメント(テンプレートディレクトリの中身)

shopifyテーマ開発入門に戻る