#05 ダイナミックセクションの作成方法
このページを読むことで以下のことが学べます。
①ダイナミックセクションの設定方法がわかります。
②Liquidについて詳しくなれます。
・for product in~ の product は変数?それともオブジェクトなのか?
・collections.frontpage.products プロパティが2つあってもいいのか?
・グローバルオブジェクトについて
Liquidやプログラムについて詳しい方は
Liquidの解説前半・後半は飛ばしてもらって大丈夫です。
{{ content_for_index }} からご覧ください。
ダイナミックセクションとは
Shopifyの管理画面からセクションを追加・編集・削除をドラック&ドロップで操作できるセクションのことです。
オンラインストア2.0になる前まではトップページのみダイナミックセクションを使えていましたが、オンラインストア2.0になりShopifyの仕様が拡張されて、トップページ以外のほぼすべてのページでダイナミックセクションが使えるようになりました。
「templates」フォルダの「index.liquid」を開きます。
{% for product in collections.frontpage.products limit:4 %}
<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>
{% endfor %}
Liquidの解説 前半
{% for product in collections.frontpage.products limit:4 %}
① ② ③
処理内容
{% endfor %}
①product は変数なのか?オブジェクトなのか?
②collections.frontpage.products
collections オブジェクト
.frontpage プロパティ
.products プロパティ2
③limit:4 ループを指定された反復回数に制限する
この場合 4回ループ処理する
※他のプログラム言語で「0」をループ回数に含む場合があるが、
Liquidのforループの場合
limit:4 なら 4回ループということになる
0をループ回数に含まないので 5回ループということにはならない
for product in 条件
①forの後の product は変数なのか?オブジェクトなのか?
forの後の product は変数です。
ループ内の現在のアイテムを示す変数 になります。
Shopify公式ブログでも記載です。
(例){% for image in product.images %}
各リストアイテムのプロパティにアクセスするには、
ループ内の現在のアイテムを示す変数を指定します。
今回の例では、画像(image)です。
これは明白な選択であり、今後ほかのデザイナーがあなたのロジックを理解するのを助けますが、何でも入れようと思えば入れられます。
たとえば、次のようなalltheimagesintheworldを使うこともできます。
{% for alltheimagesintheworld in product.images %}
もちろんこれは馬鹿げた例です。imageのほうが合理的ですが、Liquidコレクションと関係がない変数であることを強調したかっただけです。
forの後はループ内で使用されている変数と書いてあります。
forの後はオブジェクトではなく変数だということです。
つまり「ループ内で使われている現在の変数」です。
◎ for ループ内で使用される現在の変数 in 条件
× for オブジェクト in 条件
Liquidについての基本理解が足りなかったので以下の記事を見ました。
Liquidループの見出しのSTEP.1が参考になります!
collections.frontpage.products プロパティが2つ?
②collections.frontpage.products
オブジェクトに対してプロパティ2つ指定していいのか?
これは collections オブジェクトに対して
frontpage と products の2つのプロパティがある訳ではありません。
プロパティはオブジェクトにもなる
ということです。
collections.frontpage.products
① ② ③
①collections オブジェクト
②.frontpage collections オブジェクトに対するプロパティ
プロパティだったものはオブジェクトになるので
②frontpage オブジェクト
③products frontpage オブジェクトに対するプロパティ
――
① collections オブジェクトに対して
②frontpage と ③products プロパティがある訳ではありません。
このようなプロパティが2つになる理由は、
プロパティの中にさらにプロパティが存在するためです。
web業界で働く方を少しだけ手助けするメディアさんの記事が参考になります。
グローバルオブジェクト
collections.frontpage.products
collections オブジェクトはcollectionオブジェクトと違いはあるのか?
「s」 があるのと何が違うのか?
公式の開発者ドキュメントにはcollections オブジェクトという項目がなく
collectionがありました。
https://shopify.dev/api/liquid/objects#collections
しかし、私が探しているオブジェクトはcollectionsなので、
collectionsはオブジェクトではないのか?と思いましたが、
@eijiSaitoさんの記事を参考にすると「s」がつくと
どうやらグローバルオブジェクトと呼ばれるものだと気づきました。
グローバルオブジェクトとは
テーマ内の任意のファイルから使用することができるオブジェクトです。
私のイメージですが、オブジェクトを人に例えると、
わからないことをなんでも聞けるサポートセンターのような存在です。
例えば、オブジェクトに「商品名を教えて」と聞くとちゃんと答えを返してくれる存在です。実際にLiquidでコードを書くと「product.title」です。
ただ、そんななんでも聞ける存在でも聞く場所によって、答えを持っていないことがあります。聞きたいことをその場所(ファイル)では聞けないことがあります。これが普通のオブジェクトの役割です。
適切な場所でオブジェクトが知っていることを聞かないと答えてくれないのです。
適切な場所とは、例えばShopifyのテーマのフォルダ「template」にあるファイルから質問したとき、普通のオブジェクトにとっては
「ここでは答えることができません(箱には答えが入っていない)」
となる場合と
「そのことであれば答えはこれです。(箱には答えが入っている)」
となる場合があります。
普通のオブジェクトとグローバルオブジェクトの違いについては、人に例えると、グローバルオブジェクトはShopifyのテーマのどの場所(ファイル)から質問しても答えてくれる人をグローバルオブジェクトと呼び、
場所によって答えを持っていない人をオブジェクトと呼びます。
そして、どの場所からでも答えくれるグローバルオブジェクトは21種類あると言われています。
詳しくは@eijiSaitoさんの記事にまとめられているので参考になります。
https://qiita.com/eijiSaito/items/4e71457fc38a4964f977#global-objects
Liquidの解説 後半
<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>
<a href="{{ product.url | within: collection }}">{{ product.title }}</a>
product.url 商品詳細ページのURLを取得する
| within: collection URLフィルター
| within: collectionを使うことで
現在表示中のコレクション内にある商品URLを取得することができる
(例)
コレクション名:アイスクリーム / ハンドル:icecreem
商品名:チョコレート /ハンドル chocolate
※ハンドルとはURLのことでWordPressに例えるとパーマリンクのことです
商品のURLは
<a href="{{ product.url | within: collection }}">
↓
<a href="/collections/icecreem/products/chocolate">
@eijiSaitoさんの記事が参考になります。
https://qiita.com/eijiSaito/items/70aad4d59cc5427981e1#within
{{ product.price | money }}
product.price 商品価格
| money moneyフィルター
Shopifyの管理画面からストア通貨の設定ができます。
https://note.com/webyonet/n/ne3ea5df53566?magazine_key=m32b4fb7012f4
左下の「設定」から「一般設定」をクリックします。
ページ下部の「ストア通貨」の項目から「表示形式を変更する」をクリックすると以下の内容が展開されます。
①通貨表示が含まれているHTML ¥{{amount_no_decimals}} JPY
②通貨表示が含まれていないHTML ¥{{amount_no_decimals}}
③通貨表示が含まれているメール ¥{{amount_no_decimals}} JPY
④通貨表示が含まれていないメール ¥{{amount_no_decimals}}
| money moneyフィルターでは、
①通貨表示が含まれているHTML ¥{{amount_no_decimals}} JPY
の形式で表示されます。
なので、100円の場合は、「¥100 JPY」と表示されます。
①~④はShopifyの管理画面から編集できますので、修正することが可能です。
さらに詳しくは@eijiSaitoさんの記事が参考になります!
https://qiita.com/eijiSaito/items/8d20098567e48249bd92
{% unless product.available %}<br><strong>sold out</strong>
{% endunless %}
商品が購入可能でなければ sold out を表示する
<img src="{{ product.featured_image.src | img_url: 'large' }}" alt="{{ product.featured_image.alt | escape }}">
product.featured_image 商品の最初の画像
※featured とは最初の画像の意味
productオブジェクト
https://shopify.dev/api/liquid/objects/product#product-featured_image
featured_image.src 画像の相対パスを取得できる
imageオブジェクト
https://shopify.dev/api/liquid/objects/image#image-src
| img_url: 'large' 「この大きさで」と画像の大きさを指定できる
img_urlフィルター
https://shopify.dev/api/liquid/filters/url-filters#img_url
| img_url: 'large' ってどれくらいの大きさ?480×480
pico 16 x 16
icon 32 x 32
thumb 50 x 50
small 100 x 100
compact 160 x 160
medium 240 x 240
large 480 x 480
grande 600 x 600
1024x1024 1024 x 1024
2048x2048 2048 x 2048
master largest image
Code Shopifyさんを参考にしました。
http://www.codeshopify.com/blog_posts/new-features-for-the-shopify-img_url-filter
<img src="{{ product.featured_image.src | img_url: 'large' }}" alt="{{ product.featured_image.alt | escape }}">
product.featured_image.alt 商品の説明
| escape エスケイプフィルター
| escape エスケイプフィルターの役割
HTML上で、>や、"、などの特殊文字を表示するための処理です。
例えば、<は、<に変換されます。
https://qiita.com/eijiSaito/items/b4a1675ec196546aa4f2#escape
{{ content_for_index }}
このオブジェクトを使用することでダイナミックセクションの機能を追加することができます。Shopifyの管理画面からセクションの追加・編集・削除ができるようになります。
「templates」フォルダの「index.liquid」を開きます。
{% for product in collections.frontpage.products limit:4 %}
<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>
{% endfor %}
元々あるコードを削除して以下のコードを追加します。
{{ content_for_index }}
管理画面に「+セクションを追加」が表示されます。
ヒーローイメージ(メインビジュアル)を管理画面から編集できるようにする
「sections」フォルダに「hero.liquid」を作成します。
次にBootstrapのコードを記述します。
(Bootstrapの説明について省略させてください)
<section class="container py-5">
<div class="row">
<div class="col-lg-6 col-md-8 mx-auto">
<h1>説明</h1>
<p>これは説明文です。</p>
<a href="#">オンラインショップ</a>
</div>
</div>
</section>
次にスキーマの記述をします。
スキーマについて
https://note.com/webyonet/n/n115ddd636cd4#NZMEM
スキーマを設定することで管理画面を自分で設定できるようになります。
{% schema %}
{
"name": "Heroイメージ",
"class": "hero-section",
"settings": [
{
"type": "text",
"id": "title",
"default": "タイトル",
"label": "見出しのタイトル"
},
{
"type": "richtext",
"id": "description",
"default": "<p>段落</p>",
"label": "見出し説明"
},
{
"type": "text",
"id": "button_label",
"default": "ボタン",
"label": "見出しボタンラベル"
},
{
"type": "url",
"id": "button_link",
"label": "見出しボタンリンク"
}
]
}
{% endschema %}
上記のJSONのコードでは「このテンプレートでご利用のテーマセクションはありません。」と管理画面に表示されます。
管理画面にセクションを反映させるにはプリセットの記述が必要
プリセットの記述を追加する
"presets": [
{
"category": "Hero",
"name": "Simple Hero"
}
]
プリセットのコードを追加する場所は {% endschema %} の上部です。
{% schema %}
{
"name": "Heroイメージ",
"class": "hero-section",
"settings": [
{
"type": "text",
"id": "title",
"default": "タイトル",
"label": "見出しのタイトル"
},
{
"type": "richtext",
"id": "description",
"default": "<p>段落</p>",
"label": "見出し説明"
},
{
"type": "text",
"id": "button_label",
"default": "ボタン",
"label": "見出しボタンラベル"
},
{
"type": "url",
"id": "button_link",
"label": "見出しボタンリンク"
}
],
"presets": [
{
"category": "Hero",
"name": "Simple Hero"
}
]
}
{% endschema %}
プリセットの記述を追加することで
管理画面にダイナミックセクションのセクションの追加ができます。
「Simple Hero」というセクションが追加されています。
管理画面にセクションを反映させるにはプリセットの記述が必要
JSONの記述が管理画面にどう影響するのか?
◆JSON
"name": "Heroイメージ",
"class": "hero-section",
「"settings"」はセクションの中身を設定するときに必要な記述です。
◆JSON
"settings": [
{
"type": "text",
"id": "title",
"default": "タイトル",
"label": "見出しのタイトル"
}
]
◆JSON
"settings": [
{
"type": "richtext",
"id": "description",
"default": "<p>段落</p>",
"label": "見出し説明"
}
]
リッチテキストでは太字や斜体やリンクを設定することができる
◆JSON
"settings": [
{
"type": "text",
"id": "button_label",
"default": "ボタン",
"label": "見出しボタンラベル"
}
]
◆JSON
"settings": [
{
"type": "url",
"id": "button_link",
"label": "見出しボタンリンク"
}
]
管理画面から編集した内容がプレビューに反映されない
見出しのタイトルに「テスト」と入力してみましたが、プレビュー画面は「説明」のままです。本当なら「テスト」変更されるはずですが、反映されません。
編集画面の内容が反映されない理由
変数や値を実際に使用していないため
「sections」フォルダの「hero.liquid」を開きます。
<section class="container py-5">
<div class="row">
<div class="col-lg-6 col-md-8 mx-auto">
<h1>説明</h1>
<p>これは説明文です。</p>
<a href="#">オンラインショップ</a>
</div>
</div>
</section>
上記のコードにBootstrapのクラスやLiquidの変数を追加していきます。
<section class="container py-5">
<div class="row">
<div class="col-lg-6 col-md-8 mx-auto">
<h1>{{ section.settings.title }}</h1>
{{ section.settings.description }}
<a href="{{ section.settings.button_link }}" class="btn btn-secondary">
{{ section.settings.button_label }}</a>
</div>
</div>
</section>
見出しのタイトルに「こんにちわ」を入力するとプレビュー画面も「こんにちわ」とリアルタイムで反映されました。
{{ section.settings.title }}
JSONの"settings": [ ] 内で設定したid「title」を出力する という意味
※idは任意で決めてOK
◆JSON
"settings": [
{
"type": "text",
"id": "title",
"default": "タイトル",
"label": "見出しのタイトル"
}
]
残りは同じ要領です。
idだけを変えるだけでJSONで設定した項目を出力することが可能です。
{{ section.settings.description }}
{{ section.settings.button_link }}
{{ section.settings.button_label }}
画像アップローダーを付ける
(ヒーロー画像を管理画面からアップロードできるようにするため)
◆JSON(変更前)
"settings": [
{
"type": "text",
"id": "title",
"default": "タイトル",
"label": "見出しのタイトル"
}
]
◆JSON(変更後)
"settings": [
{
"type": "image_picker",
"id": "image",
"label": "Hero画像"
}
]
管理画面に画像アップローダーが追加できます。
アップロードした画像の上に「見出しのタイトル」が来るように設定する
「hero.liquid」のHTMLコードを以下のように編集します。
(Liquidの解説は下に記載します)
<section class="inner-hero-section">
{% 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 %}
<div class="container py-5">
<div class="row">
<div class="col-lg-6 col-md-8 mx-auto">
<h1>{{ section.settings.title }}</h1>
{{ section.settings.description }}
<a href="{{ section.settings.button_link }}" class="btn btn-secondary">{{ section.settings.button_label }}</a>
</div>
</div>
</div>
</section>
プレビュー画面
画像の下にタイトルや段落とボタンがあります。
これを画像の上に追加するためのCSSを設定します。
「application.css.scss」に以下のコードを追記します。
html, body {}
.inner-hero-section {
position: relative;
overflow: hidden;
width: 100%;
height: 400px;
}
.inner-hero-section img,
.inner-hero-section svg {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
プレビュー画面
Liquidの解説
{% 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 %}
もし管理画面の画像アップローダーに画像が設定されている場合は
アップロードした画像を表示する
それ以外の場合は
Shopifyが用意したnoimg用の画像を表示する
<img src="{{ section.settings.image | img_url }}" alt="">
section.settings.image
管理画面から画像をアップロードした画像
| img_url フィルター 画像のURLを取得できる
管理画面から画像をアップロードした画像のURLを出力する
{% capture current %}{% cycle 1,2 %}{% endcapture %}
{% capture current %}
変数の中身
{% endcapture %}
assignではなくcaptureを使う理由①
複数行の文字列を含めた変数を作ることができる
(例)
{% assign favorite_food = "pizza" %}
{% assign age = 35 %}
{% capture about_me %}
I am {{ age }} and my favorite food is {{ favorite_food }}.
{% endcapture %}
{{ about_me }}
↓
I am 35 and my favorite food is piza.
assignではなくcaptureを使う理由②
変数の中身にLiquidを含めることができる
(例){% capture current %}{% cycle 1,2 %}{% endcapture %}
↓
変数currentに1と2を交互に繰り返し代入する
{% cycle 1,2 %}
cycle 繰り返し処理 (この場合1と2を交互に出力する)
liquid noteさんの記事が参考になります。
https://ikdlog.com/liquid-tag/#rtoc-14
@eijiSaitoさんの記事が参考になります。
https://qiita.com/eijiSaito/items/1dcee7a82e47a7b20560#cycle
{{ 'lifestyle-' | append: current | placeholder_svg_tag: 'placeholder-svg' }}
↓
出力されるHTMLコード
<svg class="placeholder-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1052 400"><path d="M727.XXXXX"></svg>
Shopifyが用意した画像(SVG)を表示するためのコード
| append: current
指定された文字列を別の文字列の末尾に追加する
この場合
'lifestyle-' | append: current
→ lifestyle-1
→ lifestyle-2
placeholder(プレースホルダー)名とは?
Shopifyが用意している画像(SVG)は複数あり、どの画像(SVG)を呼び出すのかを指定するために名前が割り振られています。
今回使用されている画像(SVG)は
プレースホルダー名「lifestyle-1」「lifestyle-2」です。
詳しくは公式のサイトで確認ができます。
https://shopify.dev/api/liquid/filters/additional-filters#placeholder_svg_tag
| placeholder_svg_tag: 'placeholder-svg'
| placeholder_svg_tag: 'クラス名' SVGにCSSのクラス名を追加できる
↓
<svg class="placeholder-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1052 400"><path d="M727.XXXXX"></svg>
placeholder_svg_tag
①プレースホルダー名を取得し、Shopifyが用意した画像(SVG)を出力する
②HTMLのSVGの記述が出力される
この記事が気に入ったらサポートをしてみませんか?