【Shopify】LiquidのSection概要まとめ

#はじめに
今回は、liquidのSectionの概要をまとめていきます。

頑張っていきましょう。

[こちら](https://shopify.dev/docs/themes/sections)の記事の和訳です。

#概要
Secitonの概要です。

>テーマには Sections という新しいディレクトリがあります。セクションは、他のテンプレートと同じグローバルオブジェクト、タグ、フィルターにアクセスできるLiquidテンプレートです。
セクションの外で作成された変数は、セクション内では利用できません。同様に、セクション内で作成された変数は、セクション外では利用できません。セクションにスニペットが含まれている場合、スニペットはセクション内の変数にアクセスできます。
セクションでは、3つの新しいLiquidタグがサポートされています。これらの新しいタグはセクションの外では使用できません。
{% schema %}
{% javascript %}
{% stylesheet %}

セクションでは、Shopifyの核となる部分です。管理画面で操作できる「画像付きテキスト」や「リッチテキスト」の一つ一つがセクションです。

このセクションの中で使用できる３つのタグがあります。それが、`{% schema %}`と`{% javascript %}`と`{% stylesheet %}`です。

##静的セクションと動的セクション
セクションはテーマのテンプレートに静的に含めることもできますし、テーマエディタからテーマのホームページに動的に追加することもできます。

Shopifyがセクションをレンダリングするとき、一意のid属性を持つ<div>要素で各セクションをラップします。

```.html
<div id="shopify-section-[id]" class="shopify-section">
  [output of the section template]
</div>
```

###静的セクション
sectionタグを使用して、テンプレートファイルにセクションを含めることができます。

```.liquid
{% section 'header' %}
```

上記のコードにより、`sections/header.liquid`ファイルが呼び出されます。

このように、明示的に呼び出すセクションを`静的セクション`と呼びます。

セクションは複数のページで呼び出すことができますが、セクションのインスタンスは一つしか存在しません。つまり、複数ページで同一のセクションファイルを呼び出した場合、それらは複数ページで共通になります。

簡単にいうと、トップページで「画像付きテキスト」セクションを静的に呼び出して、About usページで同一の「画像付きテキスト」セクションを静的に呼び出すと、片方の「画像付きテキスト」セクションに変更を加えた場合に、もう一方の「画像付きテキスト」セクションにも変更が反映されることになります。

ちなみに、セクション内で他のセクションを呼び出すことはできません。

###動的セクション
セクションのそれぞれの`schema`にプリセットが定義されている場合、セクションはテーマのホームページに動的に追加することができます。

プリセットが定義されているセクションは、テーマエディタから自動的にアクセス可能になります。

端的に書くなら、以下のようにテーマのカスタマイズ画面に出てくるということです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411258/06da3c55-6e60-b87c-b7a0-ed7a78ea24d7.png)

動的セクションは、カスタマイズ画面に25個表示することができます。

もっと細かく解説すると、schemaにプリセットが記述されたセクションは、自動的に`content_for_index`に追加されます。

その`content_for_index`は、`index.liquid`の中に記述されており、トップページはこの`index.liquid`ファイルそのものになります。

もっと細かく解説すると、`index.liquid`ファイルの中で`theme.liquid`という`Layout`が呼ばれ、`index.liquid`は`theme.liquid`ファイル内の`content_for_layout`内に格納されます。

##セクションスキーマタグの活用
セクションには、`{% schema %}`タグで定義されたschemaがあります。コメントタグのように、スキーマはその内容を出力せず、スキーマタグ内のLiquidコードは実行されません。

このschemaがShopifyの核となる部分で、このschemaを定義することでユーザーが操作できる部分を作成することができます。

セクションのschemaタグ内で以下のプロパティを定義することができます。

+ name
+ class
+ tag
+ settings
+ blocks
+ max_blocks
+ presets
+ default
+ locales

###name
セクションには、セクションスキーマで定義された名前を付ける必要があります

```.liquid
{% schema %}
  {
    "name": "Slideshow"
  }
{% endschema %}
```

###class
スキーマ内のセクションのラッパーに追加のクラスを指定できます。

```.liquid
{% schema %}
  {
    "name": "Slideshow",
    "class": "slideshow"
  }
{% endschema %}
```

```.html
<div id="shopify-section-[id]" class="shopify-section slideshow">
  [output of the section template]
</div>
```

###tag
セクションのラッパーのHTMLタグを指定できます。

```.liquid
{% schema %}
  {
    "name": "Slideshow",
    "tag": "section"
  }
{% endschema %}
```

```.html
<section id="shopify-section-[id]" class="shopify-section">
  [output of the section template]
</section>
```

また、セクションは次のタグをサポートしています。

+ article
+ aside
+ div
+ footer
+ header
+ section

タグが指定されていない場合、セクションのラッパーはデフォルトで<div>です。

###settings
セクションには、settings_schema.jsonと同じ形式を使用する独自の設定スキーマがあります。

```.liquid
{% schema %}
  {
    "name": "Slideshow",
    "settings": [
      {
        "id": "header",
        "type": "text",
        "label": "Header",
        "default": "Hello world"
      }
    ]
  }
{% endschema %}
```

セクションの中のsettingsのid属性は、section.settingsの中で一意である必要があります。

上記のようにスキーマを定義すると、`Header`というラベルでユーザーがテキストを入力できるフォームがShopifyのカスタマイズ画面に現れます。

その定義したスキーマをファイル内で使用する際は、以下のようにします。

```.liquid
{{ section.settings.header }}
```

上記のようにすることで、settingsのheader id、つまり以下のオブジェクトにアクセスできます。

```.liquid
{
  "id": "header",
  "type": "text",
  "label": "Header",
  "default": "Hello world"
}
```

このオブジェクトは、カスタマイズ画面でユーザーが入力したテキストそのものが格納されています。

####Section title
テーマエディタは {% schema %} 内の入力タイプに基づいてセクションのタイトルを作成します。

どの入力がセクションタイトルの値を制御するかを明示的に設定するには、設定配列のtitleに入力のidを代入します。

```.liquid
{% schema %}
  {
    "name": "Gallery",
    "settings": [
      {
        "id": "title",
        "type": "text",
        "label": "Title",
        "default": "Hello world"
      }
    ]
  }
{% endschema %}
```

カスタマイズ画面で、以下のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411258/de5e1ec0-cc89-bc7c-9c5f-2ca66908346e.png)


###blocks
>セクションは、そのスキーマの中でブロックを定義することができます。ブロックは設定やコンテンツのコンテナで、セクション内で追加、削除、並び替えが可能です。
ブロックには名前と型が必要です。ブロックの型は、テーマ開発者が設定した任意の値にすることができます。ブロックは settings_schema.json と同じフォーマットで設定を持ちます。

簡単に書くと、blocksとは可変schemaです。

blocksの中身は、schemaのリストになっています。

基本的にschemaの構造は、nameでschemaの名前を決めます。この`name`はセクションの名前そのものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411258/1e45a841-f971-303f-2d69-25d80b934d1b.png)

そして、settingsの中にリスト形式でオブジェクトを格納します。オブジェクトの要素として、`id`、`type`、`label`、`default`、`option`などがあります。

この、name、settings、オブジェクトのリストというschemaの構造自体がリストになっているのがblockです。

以下が、schemaのblocksのコードになります。

```
{% schema %}
  {
    "blocks": [
      {
        "type": "quote",
        "name": "Quote",
        "settings": [
          {
            "id": "content",
            "type": "text",
            "label": "Quote"
          }
        ]
      }
    ]
  }
{% endschema %}
```

blocksの中身は、schemaの構造に`type`という属性を付与したものになります。

この`type`はschemaのオブジェクトの`type`とは異なり、プログラマーが自由に設定できる値です。ちなみにschemaのオブジェクトの`type`はShopifyの予約語で、`text`や`image_picker`、`color`などがあります。

blocksのtypeは、各block毎に一意であれば良いです。

liquidファイル内でblocksをfor文などで回す際に、if文を使用します。その際に、if文の中で、`block.type`の値に応じて条件分岐させることで、blockを表示させることができます。

###limit
デフォルトでは、ユーザーは無限にblockを追加できますがblockに制限を加えることができます。

それが、`limit`です。

これは、ある特定の種類のblockの対して、追加上限を設けます。

```.liquid
{% schema %}
  {
    "blocks": [
      {
        "type": "payment_icons",
        "name": "Payment Icons",
        "limit": 1
      }
    ]
  }
{% endschema %}
```

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

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

```.liquid
{% schema %}
  {
    "name": "Slideshow",
    "max_blocks": 2
  }
{% endschema %}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411258/e7a2a20f-48d4-f95e-80e5-27017a9fb63e.png)

###presets
>セクションに1つ以上のプリセットがある場合、各プリセットはダイナミックセクションになり、content_for_indexオブジェクトがindex.liquidに含まれている場合、マーチャントはテーマのホームページに追加することができます。プリセットを持つセクションは、テーマのテンプレートに静的に含めるべきではありません。静的なセクションはデフォルトの設定を使用してください。

つまり、プリセットをschemaで定義したセクションは動的セクションとみなされ、`content_for_index`から呼ばれるようになります。

```.liquid
{% schema %}
  {
    "presets": [
      {
        "category": "Custom Content",
        "name": "Text",
        "settings": {
          "heading": "Hello World"
        },
        "blocks": [
          {
            "type": "text",
            "settings": {
              "content": "Once upon a time..."
            }
          }
        ]
      }
    ]
  }
{% endschema %}
```

プリセットは名前とカテゴリを持っている必要があります。セクションのプリセットは、テーマエディタでカテゴリー毎にグループ化されます。

プリセットのsettingsオブジェクトには、マーチャントがホームページに追加したときに割り当てられる値が含まれます。

プリセットのブロックには、マーチャントがテーマに追加したときにセクションに含まれるブロックになります。つまり、セクションのブロックのデフォルト値です。プリセットのブロックは、セクションのブロックスキーマに従う必要があります。

###default
テーマのテンプレートに静的に含まれているセクションは、スキーマでデフォルトの構成を定義できます。

```.liquid
{% schema %}
  {
    "default": {
      "settings": {
        "heading": "Hello World"
      },
      "blocks": [
        {
          "type": "text",
          "settings": {
            "content": "Once upon a time..."
          }
        }
      ]
    }
  }
{% endschema %}
```

フォーマットはセクションのプリセットと同じですが、名前やカテゴリはありません。

defaultは、複数のテーマやショップで再利用したりインストールすることを想定しているセクションにのみ使用する必要があります。

テーマに既にインストールされている静的セクションは、settings_data.jsonで定義されているデフォルトの設定を持つべきです。

###locales
セクションは、独自の翻訳された文字列のセットをlocalesオブジェクトで提供することができます。

独自の翻訳を持つセクションはテーマのロケールディレクトリに依存しないので、複数のテーマやショップにインストールするセクションに便利な機能です。

```.liquid
{% schema %}
  {
    "locales": {
      "en": {
        "title": "Welcome"
      },
      "fr": {
        "title": "Bienvenue"
      }
    }
  }
{% endschema %}
```

翻訳は、言語エディタのセクションタブに表示されます。

>言語エディタで翻訳を更新すると、翻訳は該当するロケールファイルに保存され、スキーマは変更されません。セクションのスキーマ内の翻訳がデフォルト値として機能します。
しかし、セクションファイルが翻訳された内容を出力するためにロケールオブジェクトは必要ありません。
セクションファイルは、locales ディレクトリで定義されているグローバル翻訳にアクセスすることができます。t (translation) フィルタは、他のテンプレートと同様にセクション内でも使用できます。
セクション内では、t フィルタは現在のセクションのコンテキスト、次にセクションのスキーマ、そしてグローバルコンテキストの中から翻訳を見つけようとします。たとえば、section/header.liquid 内の {{{ 'title' | t }}} は、ロケールファイル内の sections.header.title を探し、次にセクションのスキーマ内の title を探し、次にロケールファイル内の title を探します。

###Rendering section blocks
セクションは、section.blocksをループすることで、ブロックをレンダリングします。


```.liquid
{% for block in section.blocks %}
  <div class="grid-item" {{ block.shopify_attributes }}>
    {% case block.type %}
    {% when 'text' %}
      {{ block.settings.content }}
    {% when 'image' %}
      <img src="{{ block.settings.image | img_url }}">
    {% endcase %}
  </div>
{% endfor %}
```

`block.shopify_attributes`は、各ブロックのコンテナに追加する必要があります。

また、ブロックが単一の場合は、その要素のクラスに対して`block.shopify_arrtibutes`を追加します。

Shopifyのテーマエディタは、JavaScript APIのブロックを適切に識別するために`shopify_attributes`を使用します。

`shopify_attributes`の値はテーマエディタ内でのみ返され、テーマはテンプレートやスクリプトの中でshopify_arrtibuteesに依存するべきではありません。

###JavaScript and stylesheet tags
セクションはjavascriptとstylesheetタグを使用して、独自のスクリプトとスタイルアセットをバンドルすることができます。

これは、複数のテーマやショップで再利用したりインストールしたりすることを意図しているセクションにのみ使用する必要があります。

スキーマタグのように、javascriptとstylesheetタグは何も出力しません。各セクションは一つのjavascriptタグと一つのstylesheetタグを持つことができます。

また、`{% stylesheet 'scss' %}`を使用してスタイルシートにSassのサポートを追加することができます。

```.liquid
<div class="slideshow" id="slideshow-{{ section.id }}"></div>

<style>
  #slideshow-{{ section.id }} { … }
</style>

{% javascript %}
  $('.slideshow').slideshow();
{% endjavascript %}

{% stylesheet %}
  .slideshow {
    /* default styles */
  }
{% endstylesheet %}
```

###Bundling scripts and styles
全てのセクションのスクリプトは、Shopifyによって一つのファイルに連結され、`content_for_header`に注入されます。

注入された`<script>`は`defer`属性で非同期にロードされるように設定されています。javascriptタグは、自己実行型の匿名関数とtry/catchでラップされているため、変数はクロージャ内で定義され、実行時の例外が他のセクションに影響を与えることはありません。

**全てのセクションのスタイルはShopifyによって一つのファイルに連結され、content_for_headerに注入されます。**

バンドルされたアセットがcontent_for_headerに注入されるのは、各セクションに対して一度だけです。

セクションの各インスタンスに対して注入されるのではありません。

**インスタンス固有のCSSを定義するには、インラインの`<style>`タグを使用します。**

インスタンス固有のJavaScriptを定義するには、data-attributesを使用し、各インスタンスの属性をJavaScriptに読み込ませます。

例えば、`data-slide-speed="{{ section.settings.speed }}"`のようにします。

#終わりに
今回の記事はここまでになります。

ありがとうございました。

# Shopify アプリのご紹介

Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。

https://coming-soon.reterior.jp/

https://apps.shopify.com/shopify-application-314?locale=ja&surface_detail=%E3%83%AA%E3%83%86%E3%83%AA%E3%82%A2&surface_inter_position=1&surface_intra_position=1&surface_type=search