FROM CACHE - jp_header
解決済

複数のページに挿入したブロックの内容を別の固定ページで取得する

ec_man
Shopify Partner
14 0 2

商品詳細ページA,B,C,DにそれぞれセクションZ(画像やテキストのブロックあり)を挿入し、A,B,Cに挿入したセクションZのブロックのすべて内容を固定ページaで取得する方法はありますか?

1 件の受理された解決策

st_mh
探検家
40 13 11

成功

●セクションファイルの設定内容、その保存先について

 

基本的に、セクションの設定というのはそのセクション内でしか使えない設計になっているはずです。

 

動的レンダリングでセクションZを追加している際、その設定内容(登録した画像やテキスト類)はセクションZを読み込ませているテンプレートファイルに保存されます。

商品詳細ページであり、テーマがDawnなら「product.json」です。

 

要望は商品詳細ページと、固定ページで共通項目の表示ということですね。

この場合、「product.json」と「page.json」で、セクションZを読み込ませる訳ですが、設定内容はそれぞれのjsonテンプレートファイルに保存されるため、設定内容が共有されることはありません。

特定テンプレートファイルから、別テンプレートファイルの設定の取得も出来ないでしょう。

 

しかし、テンプレートファイルが静的レンダリング(product.liquidなど)で、これにセクションZを埋め込ませるなら、セクションの設定内容は「設定 > settings_schema.json」に保存されます。

この場合、設定内容の共有が可能です。

※ただし、最新のテーマでは静的レンダリングが主流でなくなっています。

 

動的レンダリングでありながらも設定内容を共有させるなら、共通のファイルにセクションZを埋め込むしかないです。
即ちtheme.liquidが該当します。

 

ーー

 

●A,B,Cに挿入したセクションZのブロックのすべて内容を、固定ページaで取得する方法

 

これ自体はやり方が複数存在すると思います。例えば以下の様な方法です。

 

  • セクションZに全ての設定を保存させる。
    • 商品詳細A用のブロックに画像類登録。BCDも同様。
    • このブロック内では、表示させるページを指定する欄を設けておく
      • 閲覧ページが商品詳細ページであり、かつハンドル名が一致すれば、設定内容を出力
    • 固定ページaでは、A・B・C用の設定のみ出力させる
      • 閲覧ページがpages以下であり、固定ページのハンドル名が一致すれば、特定の設定内容を出力

st_mh_1-1687159785668.png

 

セクションZ内では以下の様な分岐を行います。

{% for block in section.blocks %}
  {%- # 登録された全ブロックをループで識別 -%}
  {% if template.name == 'product' %}
    {%- # 商品詳細ページの時 -%}
    {% unless block.setting.product_handle == product.handle %}
      {%- # block.setting.product_handleには、表示させたい商品詳細ページのハンドル名が入る -%}
      {%- # 出力対象ではない場合、次のループへ -%}
      {% continue %}
    {% endunless  %}
  {% elsif page.handle == '固定ページaのハンドル名' %}
    {%- # 固定ページaの時 -%}
    {% if block.setting.product_handle == '商品詳細Dのハンドル名' %}
      {%- # 出力させない商品詳細ハンドル名を記述しておく -%}
      {%- # 出力対象ではない場合、次のループへ -%}
      {% continue %}
    {% endif  %}
  {% endif %}

  {%- # 除外対象ではない場合、以下の処理が走る -%}
  ・・(画像やテキストを出力)・・
{% endfor %}

 

{% schema %}のblocks内に、id"product_handle"を用意しておき、その設定を参照させています。

実際どの程度の規模のページに適用させるのか分かりませんが、状況次第ではコードの編集が必要です。

 

静的レンダリングならば、product.liquidとpage.liquidにセクションZを埋め込ませ、セクションZ側で全ブロックを識別しながら、設定された内容を表示したいページで出力させることが可能です。

 

動的レンダリングなら、theme.liquidにセクションZを埋め込ませれば、同じように出力可能です。

ただし、出力場所が自由に変更できないですね。

{% sections 'header-group' %}
{% section 'セクションZ' %}← コンテンツ内に記述できない
{{ content_for_layout }}
{% section 'セクションZ' %}← コンテンツ内に記述できない
{% sections 'footer-group' %}

content_for_layoutの上下どちらかしか設置できない弱みがあります。

それで問題ないならいいのですが。

 

ーー

 

●動的レンダリングでありながら、jsonテンプレート内どこでも設置する方法

 

st_mh_3-1687161724997.png

動的レンダリングなら画面のように、任意の順番でセクションの設置が可能です。

このように自由な場所で出力させたい場合、方法は1通りしかないように思います。

 

jsでのHTMLパースです。

以下二種類のファイルを用意することで、任意の場所に出力可能です。

  1. セクションZの設定管理用
    • theme.liquidに設置する
    • jsのオブジェクトを出力させる
    • 全ページに同じjsオブジェクトが出力されるため、共通設定のように取得可能
  2. セクションZのHTMLパース用
    • テンプレートファイルから読み込ませる
    • 1で出力したjsオブジェクトを、HTMLにパースさせる

既存のファイルを大幅に変更させることになるため、難易度が上がるのが難点です。

SEOの観点からも、HTMLパースさせた要素は認識されない(されにくい)でしょう。

const sectionZObject = [
  {%- for block in section.blocks -%}
  {
    "image": "{{ block.settings.画像 | image_url: width: '640x' }}",
    "text": "{{ block.settings.テキスト }}",
    "product_handle": "{{ block.settings.表示対象ページ }}",
  }{%- unless forloop.last -%},{%- endunless -%}
  {%- endfor -%}
];

上記のようにセクションZで記述しておくと、以下のオブジェクトが出力されます。

const sectionZObject = [
  { "image": "//cdn.shopify.com/s/files/1/0000/0000/0000/files/image1.jpg", "text": "Text 1", "product_handle": "商品A" },
  { "image": "//cdn.shopify.com/s/files/1/0000/0000/0000/files/image2.jpg", "text": "Text 2", "product_handle": "商品B" },
  { "image": "//cdn.shopify.com/s/files/1/0000/0000/0000/files/image3.jpg", "text": "Text 3", "product_handle": "商品C" }
  .....
];

これをHTMLにパースさせるわけです。

 

 

元の投稿で解決策を見る

4件の返信4

st_mh
探検家
40 13 11

成功

●セクションファイルの設定内容、その保存先について

 

基本的に、セクションの設定というのはそのセクション内でしか使えない設計になっているはずです。

 

動的レンダリングでセクションZを追加している際、その設定内容(登録した画像やテキスト類)はセクションZを読み込ませているテンプレートファイルに保存されます。

商品詳細ページであり、テーマがDawnなら「product.json」です。

 

要望は商品詳細ページと、固定ページで共通項目の表示ということですね。

この場合、「product.json」と「page.json」で、セクションZを読み込ませる訳ですが、設定内容はそれぞれのjsonテンプレートファイルに保存されるため、設定内容が共有されることはありません。

特定テンプレートファイルから、別テンプレートファイルの設定の取得も出来ないでしょう。

 

しかし、テンプレートファイルが静的レンダリング(product.liquidなど)で、これにセクションZを埋め込ませるなら、セクションの設定内容は「設定 > settings_schema.json」に保存されます。

この場合、設定内容の共有が可能です。

※ただし、最新のテーマでは静的レンダリングが主流でなくなっています。

 

動的レンダリングでありながらも設定内容を共有させるなら、共通のファイルにセクションZを埋め込むしかないです。
即ちtheme.liquidが該当します。

 

ーー

 

●A,B,Cに挿入したセクションZのブロックのすべて内容を、固定ページaで取得する方法

 

これ自体はやり方が複数存在すると思います。例えば以下の様な方法です。

 

  • セクションZに全ての設定を保存させる。
    • 商品詳細A用のブロックに画像類登録。BCDも同様。
    • このブロック内では、表示させるページを指定する欄を設けておく
      • 閲覧ページが商品詳細ページであり、かつハンドル名が一致すれば、設定内容を出力
    • 固定ページaでは、A・B・C用の設定のみ出力させる
      • 閲覧ページがpages以下であり、固定ページのハンドル名が一致すれば、特定の設定内容を出力

st_mh_1-1687159785668.png

 

セクションZ内では以下の様な分岐を行います。

{% for block in section.blocks %}
  {%- # 登録された全ブロックをループで識別 -%}
  {% if template.name == 'product' %}
    {%- # 商品詳細ページの時 -%}
    {% unless block.setting.product_handle == product.handle %}
      {%- # block.setting.product_handleには、表示させたい商品詳細ページのハンドル名が入る -%}
      {%- # 出力対象ではない場合、次のループへ -%}
      {% continue %}
    {% endunless  %}
  {% elsif page.handle == '固定ページaのハンドル名' %}
    {%- # 固定ページaの時 -%}
    {% if block.setting.product_handle == '商品詳細Dのハンドル名' %}
      {%- # 出力させない商品詳細ハンドル名を記述しておく -%}
      {%- # 出力対象ではない場合、次のループへ -%}
      {% continue %}
    {% endif  %}
  {% endif %}

  {%- # 除外対象ではない場合、以下の処理が走る -%}
  ・・(画像やテキストを出力)・・
{% endfor %}

 

{% schema %}のblocks内に、id"product_handle"を用意しておき、その設定を参照させています。

実際どの程度の規模のページに適用させるのか分かりませんが、状況次第ではコードの編集が必要です。

 

静的レンダリングならば、product.liquidとpage.liquidにセクションZを埋め込ませ、セクションZ側で全ブロックを識別しながら、設定された内容を表示したいページで出力させることが可能です。

 

動的レンダリングなら、theme.liquidにセクションZを埋め込ませれば、同じように出力可能です。

ただし、出力場所が自由に変更できないですね。

{% sections 'header-group' %}
{% section 'セクションZ' %}← コンテンツ内に記述できない
{{ content_for_layout }}
{% section 'セクションZ' %}← コンテンツ内に記述できない
{% sections 'footer-group' %}

content_for_layoutの上下どちらかしか設置できない弱みがあります。

それで問題ないならいいのですが。

 

ーー

 

●動的レンダリングでありながら、jsonテンプレート内どこでも設置する方法

 

st_mh_3-1687161724997.png

動的レンダリングなら画面のように、任意の順番でセクションの設置が可能です。

このように自由な場所で出力させたい場合、方法は1通りしかないように思います。

 

jsでのHTMLパースです。

以下二種類のファイルを用意することで、任意の場所に出力可能です。

  1. セクションZの設定管理用
    • theme.liquidに設置する
    • jsのオブジェクトを出力させる
    • 全ページに同じjsオブジェクトが出力されるため、共通設定のように取得可能
  2. セクションZのHTMLパース用
    • テンプレートファイルから読み込ませる
    • 1で出力したjsオブジェクトを、HTMLにパースさせる

既存のファイルを大幅に変更させることになるため、難易度が上がるのが難点です。

SEOの観点からも、HTMLパースさせた要素は認識されない(されにくい)でしょう。

const sectionZObject = [
  {%- for block in section.blocks -%}
  {
    "image": "{{ block.settings.画像 | image_url: width: '640x' }}",
    "text": "{{ block.settings.テキスト }}",
    "product_handle": "{{ block.settings.表示対象ページ }}",
  }{%- unless forloop.last -%},{%- endunless -%}
  {%- endfor -%}
];

上記のようにセクションZで記述しておくと、以下のオブジェクトが出力されます。

const sectionZObject = [
  { "image": "//cdn.shopify.com/s/files/1/0000/0000/0000/files/image1.jpg", "text": "Text 1", "product_handle": "商品A" },
  { "image": "//cdn.shopify.com/s/files/1/0000/0000/0000/files/image2.jpg", "text": "Text 2", "product_handle": "商品B" },
  { "image": "//cdn.shopify.com/s/files/1/0000/0000/0000/files/image3.jpg", "text": "Text 3", "product_handle": "商品C" }
  .....
];

これをHTMLにパースさせるわけです。

 

 

ec_man
Shopify Partner
14 0 2

とても詳しく説明頂き有難うございます。

実装してみます。

 

今回のケース以外でも活用出来そうな点をたくさんご提示頂き、非常に勉強になりました。

st_mh
探検家
40 13 11

追記です。

私の方で使用していなかった為に選択肢に入っていませんでしたが、メタオブジェクトの活用により実現化できると思いました。

 

※これらを使うことにより、テーマのカスタマイズ画面から更新を行うのではなく、メタオブジェクトからの更新となります。

 

【作業内容】

1.新規メタオブジェクトを追加
2.商品詳細とページに、1を繋いだメタフィールドを追加

 

■1.新規メタオブジェクトを追加

メタオブジェクトの使用例はこちらを参考にしてください。

https://commerce-media.info/blogs/ec/meta-object

 

メタオブジェクトであれば、全ページから参照可能です。

リンク先、画像、テキストなど、項目に存在するものなら何でも使えます。

 

仮に識別用タイプ名「test_metaobject」を作成したとします。

 

そのメタオブジェクトのエントリーとして商品詳細A~D用を作成します。

st_mh_6-1688101324627.png

 

この時点で、作成したメタオブジェクトは何処のページからでも参照可能です。

 

フィールドの固有ID「test_A」内にある、テキスト情報を格納したキー「title」を出力するとしたらこのように書きます。

 

(liquidファイルにて)

 

{{ shop.metaobjects.test_metaobject.test_A.title }}
// shop.metaobjects.オブジェクト名.エントリー名.フィールド名

↓↓↓

Aのタイトル

 

 

 

■2.商品詳細とページに、1を繋いだメタフィールドを追加

この時点で登録情報の出力は可能ですが、より簡潔なサイト管理のため、メタフィールドと連携させると良いでしょう。

 

【作業内容】

2-1.商品とページでメタフィールドを作成

2-2.商品とページで、接続するメタオブジェクトを定義

2-3.2-2を出力させる

 

●2-1.商品とページでメタフィールドを作成

「設定 > カスタムデータ」より、「商品」と「ページ」に新しく定義を追加します。

 

「タイプを選択する」からは、1で作成したメタオブジェクトを指定します。

 

参考:公式ヘルプ「メタオブジェクトを参照する」
https://help.shopify.com/ja/manual/custom-data/metaobjects/referencing-metaobjects

 

商品とページでは、共に「metaobject_test」というメタフィールドを作成したとします。

※ページでは複数のメタオブジェクトを出力させるため「エントリーのリスト」を選択します。

st_mh_8-1688102687997.png

 

●2-2.任意の商品とページで、接続するメタオブジェクトを定義

 

・商品Aで、A用のメタオブジェクトを出力させたいと思います。

商品管理より、画面下のメタフィールドから表示させたいオブジェクトを選択します。

st_mh_10-1688102858510.png

※商品BやCでも、同様に任意のオブジェクトを選択します。

 

・固定ページaも同様に、複数のオブジェクトを選択します。

st_mh_12-1688103141430.png

※表示順序は入れ替え可能

※たとえば、固定ページbでBとDを出力させたいとしても、同様の手順を踏むことで実現できます。

 

●2-3.2-2を出力させる

最後に、liquidのタグ等で出力させていきます。

 

・注意点

上記の方法で格納したメタオブジェクトは、gidというグローバルID上の管理データです。形式は"gid://shopify/Metaobject/000000"というものです。
このようなメタオブジェクトの処理が分かりにくく、海外にも苦心する方が居ました。

もしかしたら、今後最適なコードが提供されるかもしれません。

当件に関する参考URL: https://github.com/Shopify/liquid/issues/1589

 

・ページでの出力方法(複数のオブジェクトを出力)

 

 

{% assign metaobjects = page.metafields.custom.metaobject_test.value | reverse | reverse %}
{% for metaobject in metaobjects %}
  {{ metaobject.title }}<br>
{% endfor %}

↓↓

Aのタイトル<br>
Bのタイトル<br>
Cのタイトル<br>

 

 

A用、B用、C用の順で格納したなら、その順番に処理されます。

例ではタイトルのみ出力させていますが、任意のHTML構成にして下さい。

※「| reverse |  reverse」が無いと何も処理できない。

※「.value」を付けて初めて値が取得できる。

 

・商品ページ用(単一のオブジェクトを出力)

 

 

{% assign metaobjects = product.metafields.custom.metaobject_test.value | reverse | reverse %}
{% for metaobject in metaobjects %}
  {{ metaobject.title }}<br>
  {{ metaobject.image | image_url }}
{% endfor %}

↓↓↓

Aのタイトル<br>
cdn.shopify.com/s/files/1/0593/2902/0056/products/画像.jpg

 

 

単一なら、もっと簡単に出力できると思ったのですが、こちらでもループ処理が必要でした。

 

 

// ダイレクトに項目の出力を試みたが、何も出力されなかった記述

タイトル:{{ product.metafields.custom.metaobject_test.value.title }}
画像:{{ product.metafields.custom.metaobject_test.value.image }}

 

 

この辺りが不親切と評価される理由でしょう。

 

こういったコードが今後改善されるかもしれないため、念のためご留意ください。

 

出力コードは、main_product.liquid内に記述したり、スニペットファイルに記述してカスタムliquidのセクションパーツから呼び出すなど、色々カスタマイズしてみてください。

 

何か分からなければ、追記で質問頂ければと思います。

ec_man
Shopify Partner
14 0 2

詳細なご説明ありがとうございます!

 

メタオブジェクトの活用ですね。

まだまだ使いきれていないので、ご提示いただいた内容を試してみて勉強させて頂きます。