[Udemy]Shopify Theme Development: Create Shopify Themes のメモまとめ

Shopify
この記事は約66分で読めます。

参考URL

Shopify Theme Development: Create Shopify Themes [2023]
LearnhowtocreateShopifythemesusingThemeKitandhowtouseLiquidprogrammingforcustomizingShopifythemes
  1. 6. テーマファイルと設定スキーマ
  2. 7. CSSフレームワークのインストール
  3. 8.ヘッダー
  4. 10. カスタムセクションの作成
    1. {{ content_for_index }}
    2. Scheme
    3. richtextのセクションを作るときの注意点
    4. 画像アップローダー
  5. 11. コレクション内の製品の表示
  6. 12. 商品ページの作成
    1. {% form %}について
    2. チェックボックス セクションの作り方
  7. カートページの作成
      1. IMG_URLのサイズまとめ
  8. 14. カスタムページ(About UsとFAQ)
    1. カスタマイズページで選択肢から選ぶタイプのセクションを追加する方法
    2. 1つのセクションの中にじゃんじゃか設定項目を増やす方法
    3. 日付フォーマットについて
    4. blocks :[{ }] について
      1. blocksの配列には複数のオブジェクトを入れることができる
      2. blocksを呼び出す
      3. blocksを呼び出す 2
      4. blocks全体の上限を設ける max_blocks
    5. とても大事な注意点
    6. settingsのプロパティ解説
    7. その他
  9. 15. コレクションページ
  10. 16. ページネーション
  11. 17. 製品の並べ替え
  12. 18. ブログ一覧ページ
    1. スニペットを使用して、ページネーションを使い回す。
  13. 19. 記事ページ
    1. date: format: オプション
      1. format のエラー
    2. コメント機能について
  14. 20. サイドバー
  15. 21. 404ページ
    1. <h1>{{ 'general.404.title' | t }}</h1> とはなにか
  16. 22. フッター
    1. セクションで選べるtypeの種類解説
      1. 入力タイプの種類(基本)
      2. 入力タイプの種類(リッチ)
      3. 入力タイプの種類(Shopifyのアイテム)
  17. 23. 検索フォーム
    1. section.settings.image.alt について
    2. 検索フォームのコード
  18. 検索結果画面
  19. {{ }} の中で、クラス名を指定する
  20. 25. 翻訳の追加
    1. Locales > en.default.json に関して
  21. 26. ログイン、ユーザー登録メニュー(ヘッダー)
  22. 27. ログインページ
  23. 28. サインアップページ
  24. 29. アカウントページ
    1. 管理画面から注文を作成
  25. 30. アドレスページ
    1. 国名を選択すると選択した国の州・県を選択肢として選べるようにする方法
    2. 住所情報を削除する方法
  26. 31. 注文ページ
  27. 32. パスワードリセット & アカウント有効化ページ
    1. アカウントを有効化させる
    2. アカウント有効化ページ
  28. リセットパスワードページ
      1. パスワードに制限を加える
  29. 33. 次にやるべきこと
  30. 34. 言語選択機能をショップに追加する(アプリ不使用)
    1. 言語選択画面を実装
  31. 36. ストアの支払い方法のリストを表示する

6. テーマファイルと設定スキーマ

settings_scheme.jsonでは最初、テーマ情報・テーマのテンプレート情報を持っている。

このファイルにはより多くの設定を追加することが可能。ナビゲーションの色をカスタマイザーで変更できる設定を付け加えるなど。

theme deployで手動アップデート

7. CSSフレームワークのインストール

CSSファイルはassetsフォルダに投下していく。

CSSファイルを読み込みたい場合は、Layout> theme.liquid> headの下側、{{application.css.liquid | ~~~}の上下適切な位置に該当ファイルを置く。

JSファイルの場合は、bodyタグの最後に置きたい場合はそちらに移動させる。

8.ヘッダー

theme.liquidのbodyのナビゲーション部分は、sectionフォルダにheader.liquid作ってコピペするなどして使うのが吉

{% section 'header' %}
シングルクオーテーションなのに注意

10. カスタムセクションの作成

{{ content_for_index }}

index.liquidで使用されているオブジェクトです。これにより、ホームページを動的にカスタマイズすることができます。
このオブジェクトを使用すると、カスタマイズページにセクションを追加するボタンが表示されます。

Scheme

Scheme tags are used to create settings for your sections and you can find these settings in your customizer page like below.(Schemeタグは、セクションの設定を作成するために使用され、これらの設定はカスタマイザーページで以下のように見ることができます。)

richtextのセクションを作るときの注意点

<p>タグは、settingsのdefaultで指定するので、HTMLでは<p>タグ除いた{{ section.settings.「richtext」 }}で書く(「richtext」は任意のid名)

{
    "type": "richtext",
    "id": "description",
    "default": "<p>Example Paragraph</p>",
    "label": "Heading Description"
}

画像アップローダー

"settings": [
      {
        "type": "image_picker",
        "id": "image",
        "label": "Heading Background Title"
      },

HTMLで画像を出力するときは、if文で画像が空でないか確認する。

{% if section.settings.image != blank %}
    <img src="{{ section.settings.image | img_url }}" alt="">
{% else %}
    {% capture current %}{% cycle 1, 2 %}{% endcapture %}
    {{ "lifestyle-" | append: current | placeholder_svg_tag: "placeholder-svg"}}
{% endif %}
placeholder-svgの指定で、shopifyデフォルトのプレースホルダーが表示される。

ちなみに、lifestyle-2だとは以下のsvgイラスト

参考

Using Placeholder Images for Shopify Products - Shopify
Shopifyhasabuilt-insolutionforplaceholderimagestohelpyourwebsitesfeelsimilartothefinalproduct.Learnmoreinside.

11. コレクション内の製品の表示

Shopifyでコレクションを作ったら、商品をいくつか登録してみよう。

セクションフォルダ>featured-collection.liquidを作成し、"type": "collection"でセクションにコレクションの商品を表示するリストを作成することができる。

<section class="container py-4">
  <h2 class="text-center my-3">{{ section.settings.title }}</h2>
  <div class="row">
    <!-- カスタマイズ画面で選択したコレクション内にある全ての商品のリストを取得してループ -->
    {% for product in collections[section.settings.featured_collection].products %}
      {% assign image = product.featured_media.preview_image %}
      <div class="col">
        <div class="card" style="width: 18rem;">
          {% if image != blank %}
            <img class="card-img-top" src="{{ image | img_url: 'medium' }}" alt="{{ product.title }}">
          {% else %}
            {{ 'product-1' | placeholder_svg_tag: 'card-img-top' }}
          {% endif %}
          <div class="card-body">
            <h3><a href="{{ product.url }}">{{ product.title }}</a></h3>
            <p>{{ product.price | money_without_trailing_zeros }}</p>
          </div>
        </div>
      </div>
    {% endfor %}
  </div>
</section>


{% schema %}
{
  "name": "Featured Collection",
  "class": "featured-collection-section",
  "settings": [
    {
      "type": "collection",
      "id": "featured_collection",
      "label": "Collection"
    },
    {
      "type": "text",
      "id": "title",
      "default": "Featured Collection",
      "label": "Title"
    }
  ],
  "presets": [
    {
      "category": "Collection",
      "name":"Featured Collection"
    }
  ]
}

{% endschema %}

ちなみに、

<img src="{{ product.featured_media.preview_image | img_url: 'medium' }}" alt="{{ product.title }}">

の、featured_media.preview_imageは下のような感じ↓

12. 商品ページの作成

商品の詳細ページのデザインを変えるには、tepmlates>product.liquid

この講座では、すでにデフォルトのコードが書かれているが、全部削除しゼロから商品ページのコーディングを始める。

もともとあったコード↓ (product.liquid)

{% assign current_variant = product.selected_or_first_available_variant %}
{% assign featured_image = current_variant.featured_image | default: product.featured_image %}
<img src="{{ featured_image | img_url: 'large' }}" alt="{{ featured_image.alt | escape }}" id="ProductPhotoImg">
{% for image in product.images %}
  <a href="{{ image.src | img_url: 'large' }}">
    <img src="{{ image.src | img_url: 'compact' }}" alt="{{ image.alt | escape }}">
  </a>
{% endfor %}
<h1>{{ product.title }}</h1>
<form action="/cart/add" method="post" enctype="multipart/form-data" id="AddToCartForm">
  <select name="id" id="productSelect">
    {% for variant in product.variants %}
      {% if variant.available %}
        <option value="{{ variant.id }}">
          {{ variant.title }} - {{ variant.price | money_with_currency }}
        </option>
      {% else %}
        <option disabled="disabled">
          {{ variant.title }} - sold out
        </option>
      {% endif %}
    {% endfor %}
  </select>
  {{ current_variant.price | money }}
  <label for="Quantity">quantity</label>
  <input type="number" id="Quantity" name="quantity" value="1" min="1">
  <button type="submit" name="add" id="AddToCart">Add to cart</button>
</form>
<div>{{ product.description }}</div>

{% form %}について

事前定義されたフォームタイプは次のとおりです。

  • activate_customer_password
  • contact
  • currency
  • customer
  • create_customer
  • customer_address
  • customer_login
  • guest_login
  • new_comment
  • product
  • recover_customer_password
  • reset_customer_password
  • storefront_password
How to Use Liquid to Build Forms on Shopify for Themes - Shopify
FormsareusedacrossarangeoftouchpointsonShopifystores.Inthisarticle,welookathowtobuildformsonShopifywithLiquid.

{% form 'activate_customer_password' %} のように使う。(今回使うのはproduct)

例えば以下の出力例↓

{% form 'product', product, class:"product-form", id:"AddToCartForm" %}
{% endform %}
<form method="post" action="/cart/add" id="AddToCartForm" accept-charset="UTF-8" class="product-form" enctype="multipart/form-data">
    <input type="hidden" name="form_type" value="product" />
    <input type="hidden" name="utf8" value="✓" />
</form>

{% form 'product', product,← 最後のproductは引数。formタグはクラスもIDもつけやすくて便利だね。

product.liquid

{% section 'product-template' %}

sections>product-template.liquid (カスタマイザーで動的に内容変えられるようにセクションで作る)

{% assign current_product = product.selected_or_first_available_variant %}
{% assign product_image = current_product.featured_image | default: product.featured_image %}

<div class="container">
  <div class="row">
    <div class="col-md-6 col-12">
      <img src="{{ product_image | img_url: 'large' }}" alt="{{ product_image.alt }}" class="img-fluid" id="ProductMainImage">
      {% for image in product.images %}
        <img src="{{ image.src | img_url: 'medium' }}" alt="{{ image.alt }}">
      {% endfor %}
    </div>
    <div class="col-md-6 col-12">
      <h1>{{ product.title }}</h1>
      <p>{{ current_product.price | money_with_currency }}</p>


      {% form 'product', product, class:"product-form", id:"AddToCartForm" %}{%- comment -%}productは引数{%- endcomment -%}
        <div class="mb-3">
          <!-- バリエーション選択フォーム -->
          <select name="id" id="productSelect" class="form-select">
            {% for variant in product.variants %}
              {% if variant.available %}
                <option value="{{ variant.id }}">
                  {{ variant.title }}
                </option>
              {% else %}
                <option value="{{ variant.id }}" disabled="disabled">
                  {{ variant.title }}
                </option>
              {% endif %}
            {% endfor %}
          </select>
        </div>

        <div class="mb-3">
          <!-- 数量選択フォーム -->
          <input type="number" class="form-control" name="quantity" id="Quantity" value="1" min="1">
        </div>

        <!-- カートボタン -->
        <button type="submit" name="add" id="AddToCart" class="btn btn-secondary btn-lg w-100 rounded-0">カートに追加</button>

        {% if section.settings.dynamic_button_checkbox == true %}
          <!-- チェックアウトボタン -->
          {{ form | payment_button }}
        {% endif %}
      {% endform %}
    </div>
  </div>
</div>

{% schema %}
{
  "name": "Product pages",
  "settings": [
    {
      "type": "checkbox",
      "id": "dynamic_button_checkbox",
      "label": "Enable Dynamic Buttons",
      "default": false
    }
  ]
}
{% endschema %}

チェックボックス セクションの作り方

{% schema %}
{
  "name": "Product pages",
  "settings": [
    {
      "type": "checkbox",
      "id": "dynamic_button_checkbox",
      "label": "Enable Dynamic Buttons",
      "default": false
    }
  ]
}
{% endschema %}
Disable → Enable

こんな感じでチェックボックス使う↓

{% if section.settings.dynamic_button_checkbox == true %}
  <!-- チェックアウトボタン -->
  {{ form | payment_button }}
{% endif %}

カートページの作成

cart.liquidを編集して作ります。

{% if cart.item_count > 0 %}
  <div class="container">
    <div class="row">
      <p class="h2 my-5 text-center">Shopping Cart</p>
    </div>
    <div class="my-5">
      <form action="/cart" method="POST" class="row" novalidate>
        <div class="col-12 col-md-8">
          <div class="card shadow">
            <div class="card-body">
              <table class="tabele table-borderless">
                <thead>
                  <th colspan="2">Prod</th>
                  <th>Price</th>
                  <th>Qty</th>
                  <th>total</th>
                </thead>
                <tbody>
                  {% for item in cart.items %}
                    <tr>
                      <td>
                        <a href="{{ item.url | within: collections.all }}">
                          <img src="{{ item | img_url: 'small' }}" alt="{{ item.title | escape }}">
                        </a>
                      </td>
                      <td>
                        <a href="{{ item.url }}">{{ item.product.title }}</a>
                        <p class="small">{{ item.variant.title }}</p>
                        <a  href="/cart/change?line={{ forloop.index }}&amp;quantity=0">remove</a>
                      </td>
                      <td>{{ item.price | money }}</td>
                      <td>
                        <input type="number" name="updates[]" id="updates_{{ item.key }}" value="{{ item.quantity }}" min="0">
                      </td>
                      <td>
                        {% if item.original_line_price != item.line_price %}{{ item.original_line_price | money }}{% endif %}
                        {{ item.line_price | money }}
                        {% for discount in item.discounts %}{{ discount.title }}{% endfor %}
                      </td>
                    </tr>
                  {% endfor %}
                </tbody>
              </table>
            </div>
          </div>
        </div>
        <div class="col-12 col-md-4">
          <div class="card shadow">
            <div class="card-body">
              <p class="h3">The total amount is</p>
              <p>{{ cart.total_price | money }}</p>
              <p>sub total : {{ cart.total_price | money }}</p>
              <div class="d-grid gap-2">
                <button type="submit" class="btn btn-primary" name="update">Update</button>
                <button type="submit" class="btn btn-primary" name="checkout">Checkout</button>
              </div>
            </div>
          </div>
        </div>
      </form>
    </div>
  </div>
{% else %}
  <div class="container">
    <div class="row">
      <h2 class="text-center">Cart</h2>
      <p>Cart is empty</p>
    </div>
  </div>
{% endif %}

IMG_URLのサイズまとめ

img_urlのサイズ一覧です。

名前実際のサイズ(px)
pico16 × 16
icon32 × 32
thumb50 × 50
small100 × 100
compact160 × 160
medium240 × 240
large480 × 480
grande600 × 600
original1024 × 1024
[Shopify] liquidでimg_urlタグの画像サイズを調整する方法
 こんにちは、ECペンギンです!ECサイトを運営していく上で、画像の管理ってめちゃくちゃ大事ですよね。しかし、画像を挿入しても中々上手く調整できない時ってありませんか??もっと画像を小さくしたい!あぁ、それじゃ枠におさまってない!など、結構ストレスを抱えている人も多いのではないでしょうか。今回はそんなストレスフルな?S[...more]

14. カスタムページ(About UsとFAQ)

Lorem生成ページ 参考

ダミーテキストジェネレータ│無料でダミーテキストを生成
この無料オンラインツールを使って特定の数の段落、文字、文章でロレン・イプサムテキストを素早く生成します。デザインやサイトのためにダミーテキストを作成しましょう。

JSONオブジェクトでエラーがでたときに使いたい検証系ページ↓

JSON整形&構文チェック:jsonデータ、jsonファイルをフォーマットする | ラッコツールズ🔧
インデントレベルを揃えてJSON文字列をフォーマットし、構文エラーを表示します。

カスタマイズページで選択肢から選ぶタイプのセクションを追加する方法

sectionsにファイルを作成(page-template.liquid)、以下のスキーマを設定する

{% schema %}
{
  "name": "ページ設定 動画14",
  "settings": [
    {
      "type": "select",
      "id": "container",
      "label": "レイアウト",
      "options": [
        {
          "value": "container",
          "label": "Container"
        },
        {
          "value": "container-fluid",
          "label": "Container Fluid"
        }
      ],
      "default": "container"
    }
  ]
}
{% endschema %}

選択肢型のセクションはこう使うと便利↓

{% if section.settings.container == "container" %}
  {% assign container_class = 'container' %}
{% else %}
  {% assign container_class = 'container-fluid' %}
{% endif %}

<div class="{{ container_class }}">...</div>

これで、選択肢によってかんたんにデザインを変更することができます。

ちなみにcontainerクラスは左右両側に余白ができますが、container-fluidクラスの場合、fluid(液体)のように目一杯広がります(余白ができない)(Bootstrap最速の入門書)

1つのセクションの中にじゃんじゃか設定項目を増やす方法

{% schema %}
{
  "name": "ページ設定 動画14",
  "settings": [
    {
      "type": "select",
      
      (省略)
    }  ←ここに,{}追加したらじゃんじゃか設定項目入れることができる。
  ]
}
{% endschema %}
{% schema %}
{
  "name": "ページ設定 動画14",
  "settings": [
    {
      "type": "select",
      (省略)
    },
    {
      "type": "checkbox",
    (省略)
    }
  ]
}
{% endschema %}

↓こんな感じ

2つできた。

日付フォーマットについて

<small>{{ page.published_at | date: '%B %d, %Y' }}</small>
フォーマット文字列出力形式
%A曜日の名称(Sunday, Monday ... )
%a曜日の省略名(Sun, Mon ... )
%B月の名称(January, February ... )
%b月の省略名(Jan, Feb ... )
%c日付と時刻
%d日(01-31)
%H24時間制の時(00-23)
%I12時間制の時(01-12)
%j年中の通算日(001-366)
%M分(00-59)
%m月を表す数字(01-12)
%p午前または午後(AM,PM)
%S秒(00-60) (60はうるう秒)
%U週を表す数。最初の日曜日が第1週の始まり(00-53)
%W週を表す数。最初の月曜日が第1週の始まり(00-53)
%w曜日を表す数。日曜日が0(0-6)
%X時刻
%x日付
%Y西暦を表す数
%y西暦の下2桁(00-99)
%Zタイムゾーン
%%%自身
"%Y年 %m月 %d日"

とかで使えます。

日付オブジェクトを指定したフォーマットで文字列に変換する
Dateクラスのオブジェクトを作成したあと、指定したフォーマットを使って日付オブジェクトを文字列に変換することができます。ここではRubyで日付オブジェクトを指定したフォーマットで文字列に変換する方法について解説します。

blocks :[{ }] について

blocks: [{}] は画像や商品など数が増える可能性がある設定を記述する。

{% schema %}
{
  "name": {
    "ja": "セクション名"
  },
  "class": "セクションに自動で追加されるclass名",
  "blocks": [
    // 画像や商品など数が増える可能性がある設定を記述する
  ],
  "settings": [
    // 見出しやテキストなど数が増えない設定を記述する
  ],
  "presets": [
    {
      "name": {
        "ja": "管理画面のセクション一覧に表示されるセクション名"
      },
      "category": {
        "ja": "管理画面のセクション一覧のグループに表示される名前"
      }
    }
  ]
}
{% endschema %}

blocksは、以下のように記述します。

"blocks":[
  {
    "type": "custom",
    "name": {
      "ja": "画像"
    },
    "limit": 3,
    "settings": [
      {
        "type": "image_picker",
        "id": "image_picker",
        "label": {
          "ja": "画像"
        }
      }
    ]
  }
],
プロパティ名解説
type基本的にcustomにしておけば大丈夫だと思います。公式ドキュメントを読んでも、blocksのtypeを何にすればいいのかイマイチ仕様がわかりませんでした…。
→Udemyでは、"You can set your own types of blocks type and your own type."
→ つまり、自分自身でタイプを作ることができるということか?
name管理画面に表示される設定の名前
limit設定を複数登録する場合の上限数
settingssettingsで設定を定義します。

settingsとblocksの違いですが、、見出しやテキストのような設定する値が1つの場合はsettings商品や画像のような値を複数設定する可能性があるものblocksにする…のような違いがあります。

【Shopify】Content Schemaを理解して、管理画面からサイトをカスタマイズできるようにする - #08
content_for_indexcontent_for_indexShopifyでは、管理画面上からサイトをカスタマイズすることができます。 ここで指す「カスタマイズ」とは、サイト上に

blocksの配列には複数のオブジェクトを入れることができる

ちなみに、下のようにblocksの[ ]の中に、追加でオブジェクトを入れることができる。

"blocks":[
  {
    "type": "custom",
    (省略)
  },
  {
    "type": "image",
    (省略)
  }
],

オブジェクトを追加すると、カスタマイズ画面で複数選択が可能になる。

コンテンツを追加するをクリックすると、blocks配列の2つのオブジェクト(サイドバー画像ブロック、サイドバーテキストブロック)から追加したいコンテンツを選ぶことができる。

上記はUdemy動画20回目の12分から説明がある。
出力する際は、if block.type =="" みたいな感じで分岐させて呼び出す。

blocksを呼び出す

blocksは値が複数(配列)ある場合があるので、forで回して値を呼び出します。

{% for block in section.blocks limit: section.blocks.size %}
    {% if block.settings.image_picker != blank %}
        {{ block.settings.image_picker | img_url: '300×' | img_tag }}
    {% endif %}
{% endfor %}

サンプルコードでは、上記のように呼び出しています。

  1. section.blocksオブジェクトをforで回しblockに代入
  2. if文でblock.settings.image_pickerオブジェクトだったら、その値を呼び出す

blocksを呼び出す 2

<div class="container">
  <div class="accordion accordion-flush" id="accordionFAQ">
    {% for block in section.blocks %}
      <div class="accordion-item">
        <h2 class="accordion-header" id="{{ block.id }}">{{ block.settings.title }}</h2>
      </div>
    {% endfor %}
  </div>
</div>

{% schema %}
{
  "name": "FAQ",
  "blocks": [
    {
      "name": "FAQ Items",
      "type": "faq",
      "settings": [
        {
          "type": "text",
          "id": "title",
          "label": "Title(ラベル)",
          "default": "FAQ Title Example"
        },
        {
          "type": "richtext",
          "id": "answer",
          "label": "Answer"
        }
      ]
    }
  ]
}
{% endschema %}

block.idは次のように出力される→id="54b0dc9a-2e1d-405d-baaf-d8f220748147"

block.idは、for文で作られる block ごとに違う一意のIDをもっている。(例:次のループでは、block.idはcefbb22d-cb0e-4105-913b-eed3f4cb958fでさっきと全く異なる)

blocks全体の上限を設ける max_blocks

blcoksのsettingsを作れる数に上限を設けるlimitがあるが、

max_blocksも、blockの追加に制限を加えることができます。

limitとの違いとしては、様々な種類のblockに対して適用でき、その合計数を制限します。

{% schema %}
  {
    "name": "Slideshow",
    "max_blocks": 4,
    "blocks": [
      {
        (省略)
      }
    ]
  }
{% endschema %}
image.png

とても大事な注意点

管理画面上でセクションのテキストや画像を設定する。

この行為を行うと、本番環境にアップされているsettings_data.jsonのファイルに、管理画面で行ったアクション(テキストの追加や画像の設定など)が反映されます。

例:画像を追加したら、その画像のURLなどの情報がsettings_data.jsonのファイルに追記されます

つまり、管理画面で色々操作をすると、その分、本番環境のsettings_data.jsonが更新されるので、ローカル環境のsettings_data.jsonと差分が生まれます。

もう何が言いたいのか分かるとは思いますが、差分がある状態で、watch中にローカル環境のsettings_data.jsonを何かしら変更して保存をすると、その内容で本番環境のsettings_data.jsonが上書きされてしまいます。

なので、管理画面で色々操作した内容が無くなってしまいます。

これを防ぐには、管理画面で操作をしたら、管理画面 > テーマ > アクション > コード編集するからsettings_data.jsonのコードをコピーしてローカル環境のsettings_data.jsonに反映させるしかないです。

このフローを忘れなければ、色々設定をしたにも関わらず、それがいつの間にか元に戻ってしまったという恐ろしいことは起きないと思います。

settingsのプロパティ解説

プロパティ名解説
type設定の種類。一行のテキストボックスの場合はtext、複数行の場合はtextarea、チェックボックスの場合はcheckboxのように記述します。種類によって戻り値が異なり、textの場合は入力したテキスト、checkboxの場合はtrue/falseで返ってきます。他にも画像や商品、コレクションなども設定できます。詳しくは公式ドキュメントを参照ください。
id一意のユニークな値を設定します。このid名を使い、liquid側で設定した値を呼び出します。変数名のようなイメージです。
label管理画面に表示される設定の名前
info管理画面に表示される設定の説明文
default設定のデフォルト値typeがtextの場合、default: "デフォルトテキスト"のように記述しておくと、「デフォルトテキスト」が最初から入力された状態になります。

その他

  • richtextタイプは textタイプと違って文字を太くしたり、リンクをつけられたり等できる。

15. コレクションページ

templates > collection.liquid

{% paginate collection.products by 2 %}
  <h1>{{ collection.title }}</h1>
  {% for product in collection.products %}
    <div>
      <a href="{{ product.url | within: collection }}">{{ product.title }}</a>
      {{ product.price | money }}
      {% unless product.available %}<br><strong>sold out</strong>{% endunless %}
      <a href="{{ product.url | within: collection }}">
        <img src="{{ product.featured_image.src | img_url: 'large' }}" alt="{{ product.featured_image.alt | escape }}">
      </a>
    </div>
  {% else %}
    <p>no matches</p>
  {% endfor %}
  {% if paginate.pages > 1 %}
    {{ paginate | default_pagination }}
  {% endif %}
{% endpaginate %}

{% paginate collection.products by 2 %} ← 1ページに表示する商品の数

16. ページネーション

ページネートはこんな感じで使う。デフォルトは{{ paginate | default_pagination }}

{% paginate collection.products by 1 %}
  
  (省略)

  {% if paginate.pages > 1 %}
    <nav aria-label="Page navigation">
      <ul class="pagination justify-content-center">
        {% if paginate.previous.is_link %}
          <li class="page-item"><a href="{{ paginate.previous.url }}" class="page-link">{{ paginate.previous.title }}</a></li>
        {% endif %}

        <!-- 1ページ、2ページといったそれぞれのページパート -->
        {% for part in paginate.parts %}
          {% if part.is_link %}
            <li class="page-item"><a href="{{ part.url }}" class="page-link">{{ part.title }}</a></li>

          <!-- リンクがない→いまこのパートページにいる場合 -->
          {% else %}
            <li class="page-item disabled"><a href="{{ part.url }}" class="page-link">{{ part.title }}</a></li>
          {% endif %}
        {% endfor %}

        {% if paginate.next.is_link %}
          <li class="page-item"><a href="{{ paginate.next.url }}" class="page-link">{{ paginate.next.title }}</a></li>
        {% endif %}
      </ul>
    </nav>
  {% endif %}
{% endpaginate %}

17. 製品の並べ替え

まず、並べ替え機能を実装したいページに以下のようなコードを実装(Bootstrap)

<div class="row justify-content-center">
  <select name="sorting" id="sort_by" class="form-select form-select-sm w-25">
    {% for option in collection.sort_options %}
      <option value="{{ option.value }}"
        {% if option.value == collection.sort_by%}
          selected
        {% endif %}
      >{{ option.name }}</option>
    {% endfor %}
  </select>
</div>

ただし、これだけでは動的に並べ替えを行うことはできないので、javascriptを変更する。

assets > application.js

if( document.getElementById('sort_by') != null){
  document.querySelector('#sort_by').addEventListener('change', function(e) {
    var url = new URL(window.location.href);
    url.searchParams.set('sort_by', e.currentTarget.value);

    window.location = url.href;
  })
}

18. ブログ一覧ページ

blog.liquid

スニペットを使用して、ページネーションを使い回す。

スターターファイルにはsnippetsフォルダがないので、新しくsnippetsフォルダを作成する。
綴に注意すること。

使いまわしたいコードをsnippetsフォルダの新規フォルダに書いたら、

{% render '読み込みたいファイル名' %}と記述する。(includeは現在非推奨)

読み込みたいsnippetsファイルで、参照元のオブジェクトを取得する必要がある場合は、うまく読み込んでくれないので注意。

例)
snippets > pagination.liquid
{% if paginate.pages > 1 %}
<nav aria-label="Page navigation">

上記のような、paginateというオブジェクトは、renderを使うファイルのpaginateを読み込む必要がある。

よって、renderを使う場合は以下のように書く必要がある。
collection.liquid
{% render 'pagination', paginate: paginate %}

引数paginateに、値paginateを渡すという理解でOK!

19. 記事ページ

article.liquid

date: format: オプション

time_tagフィルタにformatパラメータを渡すことで、ストアフロントの言語の日付フォーマットを出力することができます
利用可能なフォーマットは以下の通りです。

time_tagだけでなく、dateタグでも同様にformatが使える。

  • abbreviated_date
  • basic
  • date
  • date_at_time
  • default
  • on_date
{{ article.published_at | time_tag: format: 'date' }}

<time datetime="2018-12-31T18:00:00Z">December 31, 2018</time>

さまざまな言語で表示されるformatオプションのプレビューを以下の表にまとめています。

formatEnglishFrenchJapanese
abbreviated_dateDec 31, 201831 déc 20182018年12月31日
basic12/31/201831/12/20182018/12/31
dateDecember 31, 201831 décembre 20182018年12月31日
date_at_timeDecember 31, 2018 at 1:00 pm31 décembre 2018 à 13:002018年12月31日 13:00
defaultMonday, December 31, 2018 at 1:00 pm -0500lundi 31 décembre 2018 à 13:00 -05002018年12月31日(月曜日) 13:00 -0500
on_dateon Dec 31, 2018le 31 déc 20182018年12月31日で
以降、動画
long4月 1, 2021 11:57
short1 4月 11:57

日付の書式は、テーマのローカル設定で定義することも出来ます。←動画のはこれ

theme/locales/en.json

"date_formats": {
  "month_day_year": "%B %d, %Y"
}

etc.liquid

{{ article.published_at | time_tag: format: 'month_day_year' }}

<time datetime="2016-02-24T14:47:51Z">February 24, 2016</time>

format のエラー

Liquid error: The format option 'month_day_year' is not a supported format.

上記がブログ記事画面に出力される場合は、'month_day_year'を任意のフォーマット名(abbreviated_dateなど)に変更する。

コメント機能について

コメント機能(if blog.comments_enabled?以下)を有効化するには、ブログ記事>ブログを管理する>該当ブログ記事>コメントにて、設定する(デフォルトでは無効になっている)

20. サイドバー

sections > sidebar.liquid

blocksを使って作成する。以前のblocksの説明部分を参照。

21. 404ページ

404.liquid

<h1>{{ 'general.404.title' | t }}</h1> とはなにか

404.liquidを開くと上記のような{{ 'general.404.title' | t }}といったコードが出てくる。

<h1>{{ 'general.404.title' | t }}</h1>
<p>{{ 'general.404.subtext_html' | t }}</p>

これは、locales > en.default.json で設定されているのを呼び出したもの。

en.default.json

{
  "general": {
    "404": {
      "title": "Not found",
      "subtext_html": "The page you were looking for does not exist"
    }
  }
}

翻訳フィルターで、ja.jsonのファイルを読み込み翻訳してくれます。

ja.json

{
  "general": {
    "404": {
      "title": "ページが見つかりませんでした。"
    }
  }
}

localesディレクトリには、言語ごとの翻訳jsonファイルを格納します。(日本語だとja.json)
jsonファイル上で翻訳箇所を定義すれば、管理画面の言語編集から修正することも可能です。

Shopify管理画面のテーマ言語エディタ(コード編集画面から入れる)

settings_data.jsonと同じく、管理画面から修正した内容は翻訳jsonファイルに保存されるローカルのファイルには変更が反映されない)ので、管理画面経由で修正したものをローカルの値で上書きしないように、運用ルールを設けておくと良いでしょう。
デフォルトで作成されるのはen.default.jsonファイルだけなので、適宜、翻訳の定義を追加した段階で複製し、ja.jsonとして日本語の内容を追加します。

Shopifyテーマの構造解説。各ディレクトリとファイルの役割を知る | non-standard world株式会社
こんにちは、エンジニアの川島です。先日の記事で、ECプラットフォームShopifyのテーマカスタマイズの始め方について述べました。今回は、Shopfyテーマの構造に加えて、各ディレクトリとファイル

22. フッター

sections > footer-section.liquid

footer-section.liquidに、</body>上のスクリプトタグも入れてしまおう。

セクションで選べるtypeの種類解説

404: ページが見つかりませんでした | HPcode(えいちぴーこーど)

入力タイプの種類(基本)

textテキスト

{
 "type": "text",
  "id": "my_text_name",
  "label": "テキストのラベル",
  "default": "テキストの初期値"
}
textareaテキストエリア

{
  "type": "textarea",
  "id": "my_textarea_name",
  "label": "テキストエリアのラベル",
  "default": "テキストエリアの初期値"
}
image_picker画像

{
  "type": "image_picker",
  "id": "my_image_picker_name",
  "label": "画像のラベル"
}
radioラジオボックス

{
  "type": "radio",
  "id": "my_radio_name",
  "label": "ラジオボタンのラベル",
  "options": [
     { "value": "a", "label": "A"},
     { "value": "b", "label": "B"},
     { "value": "c", "label": "C"}
  ]
}
select選択

{
  "type": "select",
  "id": "my_select_name",
  "label": "セレクトボックスのラベル",
  "options": [
     { "value": "a", "label": "A"},
     { "value": "b", "label": "B"},
     { "value": "c", "label": "C"}
    ]
}
checkboxチェックボックス

{
  "type": "checkbox",
  "id": "my_checkbox_name",
  "label": "チェックボックスのラベル",
  "default": true
}
rangeレンジ

{
  "type": "range",
  "id": "my_range_name",
  "min": 1,
  "max": 10,
  "step": 1,
  "unit": "単位",
  "label": "レンジのラベル",
  "default": 2
}

入力タイプの種類(リッチ)

次にリッチな入力を影響できる入力タイプを紹介していきます。最初のほうで紹介したカラーピッカーのように標準の入力よりもより操作性高く入力できるようになります。

colorカラーピッカー

{
  "type": "color",
  "id": "my_color_name",
  "label": "色のラベル",
  "default": "#333"
}
video_url動画URL

{
  "type": "video_url",
  "id": "my_video_url_name",
  "label": "動画URLのラベル",
  "accept": ["youtube", "vimeo"]
}
richtextリッチテキスト

{
  "type": "richtext",
  "id": "my_richtext_name",
  "label": "リッチテキストのラベル",
  "default": "<p><strong>リッチテキスト<\/strong>を挿入できます。</p>"
}
htmlカスタムHTML

{
  "type": "html",
  "id": "my_html_name",
  "label": "HTMLのラベル",
  "default": "<p>HTMlタグを挿入できます。</p>"
}

入力タイプの種類(Shopifyのアイテム)

そして、Shopifyの各コンテンツを設置するための入力タイプも標準でたくさん用意されています。

font_pickerフォント選択

{
  "type": "font_picker",
  "id": "my_font_picker_name",
  "label": "フォントのラベル",
  "default": "helvetica_n4"
}
collectionコレクション

{
  "type": "collection",
  "id": "my_collection_name",
  "label": "コレクションのラベル"
}
product商品詳細

{
  "type": "product",
  "id": "my_product_name",
  "label": "商品詳細のラベル"
}
blogブログ(カテゴリー)

{
  "type": "blog",
  "id": "my_blog_name",
  "label": "ブログのラベル"
}
page個別記事

{
  "type": "page",
  "id": "my_page_name",
  "label": "記事のラベル"
}
link_listメニュー

{
  "type": "link_list",
  "id": "my_link_list_name",
  "label": "メニューのラベル"
}
urlURL(全ページ対象)

{
  "type": "url",
  "id": "my_url_name",
  "label": "URLのラベル"
}
articleブログ詳細

{
  "type": "article",
  "id": "my_article_name",
  "label": "記事詳細のラベル"
}

23. 検索フォーム

section.settings.image.alt について

{% schema %}の中で設定しなくても、カスタマイザーの画像を編集でaltを設定すれば、section.settings.image.alt を呼び出すことができる。

検索フォームのコード

<form action="/search" method="GET" role="search">
  <input type="text" name="q" value="{{ search.terms | escape }}">
</form>

上記で検索窓ができる。

検索結果画面

search.liquid

{{ }} の中で、クラス名を指定する

例)class="card-img-top"をつけたい。

{{ item.featured_image.src | img_url: 'medium' | img_tag: item.featured_image.alt, 'card-img-top' }}

, 以降で、クラス名を指定できる。

<img src="//cdn.shopify.com/s/files/1/0558/0727/9277/products/villa-1_medium.jpg?v=1617000481" alt="Example Pants" class="card-img-top">

25. 翻訳の追加

テーマ言語エディタ(管理画面で言語の翻訳作業ができるやつ)は、管理画面>コードを編集>Localsのファイルを開くと表示

管理画面>テーマのアクション>言語を編集から行ったほうが早い

Locales > en.default.json に関して

テーマをインストールしたとき、Localesには、en.default.jsonがインストールされている。
これは、ローカルのデフォルトは英語ですよーという意味だが、これを "ja.default.json"とするとデフォルトを日本語にすることができる

となると、日本でテーマ開発をするなら、ja.default.json とするのがよいのだろうか。自分はよくわからない。

というのも、そもそもShopifyで無料・有料テーマを...

Localesファイルは、調べた感じ、テーマを国際化対応させるために作るファイルである。

→ 自分が作ったテーマを、海外の方にも使ってもらうために作るもの。だと思う。

→ このファイルを作ったら外国人がサイトを見たときに翻訳されているといった類のものではない。

テーマを導入するユーザーが、導入後に自分で入力する動的なコンテンツ以外はこっちですでに日本語化できることになる。

動画34で、ユーザーがショップから言語を変更すると、localesファイルの中身を参照して言語を変更できることがわかった。

よって、locasesファイルはテーマを国際化させるために作るだけのファイルではない。

(ただし、Shopifyアプリを使用したらどうなるかよくわからん)

26. ログイン、ユーザー登録メニュー(ヘッダー)

header.liquid

{% if shop.customer_accounts_enabled %}
  {% if customer %}
    <a href="/account">account</a>
    {{ 'log out'  | customer_logout_link }}
  {% else %}
    {{ 'log in ' | customer_login_link }}
    {{ 'register' | customer_register_link }}
  {% endif %}
{% endif %}

をいじる。

現状では、チェックアウトを完了するために顧客アカウントが必要な場合のみ、ヘッダー画面にログインなどが表示されるようになっている。

設定>チェックアウト>顧客アカウント から、「アカウントを無効化」「アカウントを任意化」「アカウントを必要とする」を選べる。
「アカウントを無効化」以外を選ぶと、"shop.customer_accounts_enabled" がtrueを返す。

27. ログインページ

templates > customers > login.liquid

基本的に、{% form %}を使うときは、{% for error in form.errors %}がセットでついてくる。
article.liquidのところで解説。

なので、{% for error in form.errors %}のところはスニペット化しておくのがおすすめ。(やらないのももちろんあり)

28. サインアップページ

register.liquid

29. アカウントページ

account.liquid

管理画面から注文を作成

注文は管理画面からでも作成することができる。

30. アドレスページ

addresses.liquid

application.js

やはりドキュメントは読むべし。

customers/addresses
Learnaboutthecustomeraddressestemplate,whichallowscustomerstoviewandmanagetheircurrentaddresses,aswellasaddnewones.

国名を選択すると選択した国の州・県を選択肢として選べるようにする方法

<div class="col-12 col-md-4 mb-3">
  <label for="AddressCountryNew" class="form-label">国名</label>
  <select id="AddressCountryNew" name="address[country]" class="form-control">
    {{ all_country_option_tags }}
  </select>
</div>
<div class="col-12 col-md-4 mb-3">
  <label for="AddressProvinceNew" class="form-label">都道府県</label>
  <select id="AddressProvinceNew" name="address[province]" class="form-control" disabled="disabled"></select>
</div>

{{ all_country_option_tags }} は下のようにHTMLに出力される。

<option value="Iceland" data-provinces="[]">アイスランド</option>
<option value="Ireland" data-provinces="[[&quot;Carlow&quot;,&quot;
   カーロウ州&quot;],[&quot;Cavan&quot;,&quot;キャバン州&quot;],
   [&quot;Clare&quot;,&quot;クレア州&quot;],[&quot;Cork&quot;,&quot;コーク州
   &quot;],[&quot;Donegal&quot;,&quot;ドニゴール州&quot;],
   [&quot;Dublin&quot;,&quot;ダブリン州&quot;],[&quot;Galway&quot;,&quot;
   ゴールウェイ州&quot;],[&quot;Kerry&quot;,&quot;ケリー州&quot;],

   (以下省略)

州・県がある国には、data-provinces属性に各州県が出力される。

application.js

if ( document.getElementById('AddressCountryNew') != null) {
  document.getElementById('AddressCountryNew').addEventListener('change', function(e) {
    var provinces = this.options[this.selectedIndex].getAttribute('data-provinces');
    var provinceSelecter = document.getElementById('AddressProvinceNew');
    var provinceArray = JSON.parse(provinces);

    // console.log(provinceArray);
    if (provinceArray.length < 1) {
      provinceSelecter.setAttribute('disabled', 'disabled');
    } else {
      provinceSelecter.removeAttribute('disabled');
    }

    provinceSelecter.innerHTML = '';
    var options = '';

    for (var i = 0; i < provinceArray.length; i++) {
      options += '<option value="' + provinceArray[i][0] + '">' + provinceArray[i][1] + '</option>'
    }

    provinceSelecter.innerHTML = options;
  })
}

ちなみに、11行目の、//consle.log(provinceArray); の出力例(日本)

0: (2) ["Aichi", "愛知県"]
1: (2) ["Akita", "秋田県"]
2: (2) ["Aomori", "青森県"]
3: (2) ["Chiba", "千葉県"]
4: (2) ["Ehime", "愛媛県"]
5: (2) ["Fukui", "福井県"]
6: (2) ["Fukuoka", "福岡県"]
7: (2) ["Fukushima", "福島県"]
8: (2) ["Gifu", "岐阜県"]
9: (2) ["Gunma", "群馬県"]
10: (2) ["Hiroshima", "広島県"](以下省略)

(課題)郵便番号で検索をかけられるようにする。

住所情報を削除する方法

<div class="card">
  <div class="card-body">
    {{ address | format_address }}
  </div>
  <div class="card-footer">
    <form
      action="/account/addresses/{{ address.id }}"
      method="POST"
      data-config-message="Delete Address"
    >
      <input type="hidden" name="_method" value="delete">
      <button class="btn btn-danger">削除</button>
    </form>
  </div>
</div>

削除する際の確認画面を設ける必要がある。

31. 注文ページ

order.liquid

もともとあったコード

<!-- /templates/customers/order.liquid -->

<h2>Billing Address</h2>
<p><span>Payment Status:</span> <span class="status_{{ order.financial_status }}">{{ order.financial_status }}</span></p>
<p>{{ order.billing_address.name }}</p>
<p>{{ order.billing_address.company }}</p>
<p>{{ order.billing_address.street }}</p>
<p>{{ order.billing_address.city }}, {{ order.billing_address.province }}</p>
<p>{{ order.billing_address.country }} {{ order.billing_address.zip }}</p>
<p>{{ order.billing_address.phone }}</p>

<h2>Shipping Address</h2>
<p><span>Fulfillment Status:</span><span class="status_{{ order.fulfillment_status }}">{{ order.fulfillment_status }}</span></p>
<p>{{ order.shipping_address.name }}</p>
<p>{{ order.shipping_address.company }}</p>
<p>{{ order.shipping_address.street }}</p>
<p>{{ order.shipping_address.city }}, {{ order.shipping_address.province }}</p>
<p>{{ order.shipping_address.country }} {{ order.shipping_address.zip }}</p>
<p>{{ order.shipping_address.phone }}</p>

<h2>Order Items</h2>
<table>
  {% for line_item in order.line_items %}
  <tr>
    <td>{{ line_item.title | link_to: line_item.product.url }}</td>
    <td>{{ line_item.sku }}</td>
    <td>{{ line_item.original_price | money }}</td>
    <td>{{ line_item.quantity }}</td>
    <td>{{ line_item.line_price | money }}</td>
  </tr>
  {% endfor %}
</table>

32. パスワードリセット & アカウント有効化ページ

アカウントを有効化させる

まだ、アカウントが有効になっていない(メールアドレスに届いたメールから有効化リンクをクリックしていない)場合は、管理画面>顧客管理>顧客画面>(右上)「アカウントの招待を送信する」から有効かメールを再送する

アカウント有効化ページ

アカウントを作った際に送られるメールから「アカウントを有効化する」リンクをクリックして表示されるページ。パスワードを登録して有効化完了となる。

acrivate_account.liquid

初期

<!-- /templates/customers/activate_account.liquid -->
{% form 'activate_customer_password' %}
{{ form.errors | default_errors }}
<div class="password">
  <label for="password">Password</label>
  <input type="password" name="customer[password]" />
</div>
<div class="password_confirm">
  <label for="password_confirmation">Password Confirmation</label>
  <input type="password" name="customer[password_confirmation]" />
</div>
<div class="action_bottom">
  <input type="submit" value="Activate Account" />
  <span>or</span>
  <input type="submit" name="decline" value="Decline Invitation" />
</div>
{% endform %}

リセットパスワードページ

まずは、ログインページに「リセットパスワード」機能を実装(login.liquid, application.js)

<!-- /templates/customers/login.liquid -->
<div class="container py-5 my-5">
  <div class="login-form">
    {% form 'customer_login' %}

      (省略)
    {% endform %}

    <a href="#recover" id="forgetPassword" class="text-center">パスワードをお忘れですか?</a>
  </div>

  <div id="forget_password_form" class="forget-password-form d-none">
    {% form 'recover_customer_password' %}
      {% render 'form-error', form: form %}

      <div class="col-12">
        <label for="resetPassword" class="form-label">Email アドレス</label>
        <input class="form-control" type="email" name="email" id="resetPassword">
      </div>

      <input type="submit" value="パスワードをリセット" class="btn btn-secondary">
    {% endform %}
  </div>
</div>
if (document.getElementById('forgetPassword') != null ) {
  document.getElementById('forgetPassword').addEventListener('click', function(e) {
    // document.getElementById('forget_password_form').className.replace(/\bd-none\b/, 'd-block');
    const element = document.querySelector('#forget_password_form');
    if(element.classList.contains('d-none')) {
      element.classList.remove('d-none');
      element.classList.add('d-block');
    }
  })
}

正規表現 参考

https://murashun.jp/article/programming/regular-expression.html

RegExpoについて 参考

JavaScriptの正規表現で利用するRegexpオブジェクトを現役エンジニアが解説【初心者向け】 | TechAcademyマガジン
初心者向けにJavaScriptにおける正規表現で利用するRegexpオブジェクトについて解説しています。Regexpによる正規表現の扱い方の基本、フラグの設定方法、実際の使用例を見ていきましょう。

reset_password.liquid 初期状態

<!-- /templates/customers/reset_password.liquid -->

{% form 'reset_customer_password' %}

{{ form.errors | default_errors }}

<label for="password">Password</label>
<input type="password" value="" name="customer[password]" size="16" />

<label for="password_confirmation">Password Confirmation</label>
<input
  type="password"
  value=""
  name="customer[password_confirmation]"
  size="16"
/>

<input type="submit" value="Reset Password" />

{% endform %}

パスワードに制限を加える

inputタグにsize属性を追加する。

33. 次にやるべきこと

  • liquidフィルターなど、文法の確認
  • テーマを最適化する
    • 再利用可能なコンポーネントをスニペット化する
      • product-card.liquidなど
  • Bootstrapのマスター

34. 言語選択機能をショップに追加する(アプリ不使用)

ショップにサイトで表示したい言語の選択肢をドロップダウンで表示する方法

管理画面>設定>ストアの言語>翻訳された言語「言語を追加する」をクリック→公開するをクリック

試しに英語を追加すると、(shopifyサイトのURL/en)へのプレビューリンクが作成される。

ちなみにページ右側の「言語を追加する」からも同じようにできる。

言語選択画面を実装

sections に translation.liquidを作成し、theme.liquidで読み込む。

translation.liquid

{% form 'localization', id: "localization_form_tag", class: "dropup" %}
  <div class="localeBtn">{{ 'globe.png' | asset_img_url: '50px' | img_tag }}</div>
  <div class="dropup-content">
    {% for locale in shop.published_locales %}
      <a href="#" id="localeItem" lang="{{ locale.iso_code }}">{{ locale.endonym_name }}</a>
    {% endfor %}
  </div>

  <input type="hidden" name="locale_code" id="localeCode" value="{{ form.current_locale.iso_code }}">
{% endform %}

application.js

var localeItems = document.querySelectorAll('#localeItem');
if (localeItems.length > 0 ) {
  localeItems.forEach(item => {
    item.addEventListener("click", event => {
      document.getElementById('localeCode').value = item.getAttribute('lang');
      document.getElementById('localization_form_tag').submit();
    })
  })
}

言語を選択できる機能が実装できたら、表示したい言語を選択してみる。

言語を選択すると、(サイトURL/en)といったページになり、かつ(lang="en")と変化してくれる。

localesフォルダに選択した言語のファイルがある場合、そのファイルを読み込んで表示してくれる。

locales > en.json

{
  "general": {
    "404": {
      "title": "Not Found",
      "subtext_html": "The page you looking for is not exist."
    },
    "Cart": {
      "title": "Cart"
    },
    "Layout": {
      "login_text": "Login",
      "register_text": "Register",
      "account_text": "User"
    }
  }
}

つまり、localesファイルはテーマ利用者だけでなく、サイト利用者にも意味があった!

疑問:

作成者がカスタマイズ画面で書き込んだ文字はこれだと変換されないので、別途やはりアプリを使う必要があるのではないか?

36. ストアの支払い方法のリストを表示する

何で支払うことが可能か。そのアイコンを表示してくれるリストを出力してくれる。

<div class="container justify-content-center d-flex">
  {% for payment_type in shop.enabled_payment_types %}
    <img src="{{ payment_type | payment_type_img_url }}">
  {% endfor %}
</div>

ただし、支払い方法がそもそも追加されていないと出てこないので注意。

タイトルとURLをコピーしました