ShopifyはカートECのプラットフォームのため、商品データの登録に関しては多機能ですが、webサイトとしての機能はWordPressなどのCMSと比較すると自由度が低いです。
コレクションそのものが製品カタログ(webカタログ)の役割を果たしているため、PDFのカタログを集めた一覧ページ、資料ダウンロードページなど、製品以外のコンテンツを作ろうと思うと、「ページ」テンプレートを使用することになります。
しかし、多数のページを作って運用するのは煩雑で、それぞれのページを繋ぐナビゲーションなどにおいて、URLを管理するのにもとてつもなく苦労するはずです。
そこで、多数のページを内包するコンテンツをカテゴリごとに管理し、ページの登録を容易にするため、ブログ機能を活用します。
大量のFAQをカテゴリ別に表示したい、アコーディオンではなく単一のURLをもったページを用意したい、といった要望にも応えられます。
この記事では、Shopifyでそういったコンテンツを作る方法を解説します。
今回の目標は下記のとおり。
- ゲームソフトのカタログPDF一覧ページを作る
- 一覧ページから直接ダウンロードもできるようにする
- カテゴリ別の一覧も表示する
- カタログに掲載されているソフトの商品ページを表示する
- 商品ページで当該ソフトが掲載されているカタログを表示する
サンプルは今までの記事でも使ってきた、ゲームソフト販売のECサイトです。
製品カタログ一覧のブログを用意する
最初にストアを作成したときは、デフォルトで「ニュース」ブログができています。
ストアのお知らせとはまったく違うコンテンツになりますので、新規「ブログ」を作成して、テンプレートも製品カタログ専用のものを用意しなければなりません。
また、「ブログ記事」も、通常のお知らせとは異なるレイアウトになりますので、専用のテンプレートが必要ですね。
sectionsディレクトリにあるmain-blog.liquidをもとに、main-blog-catalogue.liquidファイルを作成します。
同様に、main-article.liquidをもとに、catalogue-article.liquidも作成します。
(ファイル名は任意のものに変えてかまいません)
それぞれ、管理画面でブログとブログ記事のテーマテンプレートに設定します。
ブログ記事のほうは、「組織」>「ブログ」の種類を製品カタログにしておくのも忘れないようにしてください。
タグでカテゴリ分類を実現するための準備
製品カタログは、ゲームのジャンル別やメーカー別などで絞り込めるようにしたいです。
メタフィールドにいろいろ登録させて、JavaScrptでゴリゴリにファセットを実装する、ということもできなくはないですが、なんか大変です。
そこで、デフォルトで提供されていて便利なタグ機能を使います。
今回のサンプルでは、「RPG」「アクション」のようなゲームのジャンルのタグと、メーカー名のタグを付与することにします。

PDFの登録と、商品ページ紐付けの準備
ただカタログ一覧を作るだけなら、ブログ記事のコンテンツに直接ファイルのリンクを書くなどすればPDFをダウンロードさせることができます。
でも一覧ページでもPDFをダウンロードさせたり、特定の商品ページとデータを連携させて表示したいですね。
ファイルのデータをあちこちで使用できるようにするため、メタフィールドを活用します。
ファイルをアップロードできるようにコンテンツタイプを「ファイル」にしたメタフィールドを用意します。

そして、紐づける商品を選択させるためコンテンツタイプが「商品」のメタフィールドも用意しますが、たとえば総合カタログなどの場合、掲載商品は複数存在することもあるでしょうから、「リスト」にしておきます。
できたら、各ブログ記事のメタフィールドに登録していきます。

続いて、商品ページのメタフィールドも設定します。

ここでひとつ罠があります。
これほどまでのShopifyのテーマカスタマイズをしようとしている方なら、すでにメタフィールドやダイナミックソースなどを駆使してきたかもしれません。
その感覚でいうと、コンテンツタイプ「ブログ記事」がありそうだ、と思うかもしれません。
しかし、
なんと、
ないのです…
血眼になって探しましたが、ありませんでした。
商品やコレクション、ページはあるのに、ブログがありません。
そのうちしれっとアップデートされて仕様に追加されるかもしれません。
いつの間にかメタフィールドがカスタムデータになったりファイルがコンテンツとかいうメニューになったり、メタオブジェクトが増えてるけど何をどう使うのかよくわからなかったり、そんなことがこの1ヶ月の間に起きている、それがShopify。
とはいえ今この時、ブログのデータを呼び出すことができないという状況は変わりません。
残念ですが、別の手を考えるしかありません。
というわけで、ブログ記事のハンドルをテキストで指定する、という泥臭い方法をとることにしました。

この方法で気をつけていただきたいところは、もし毎年新しい版になるタイプのカタログだったりして、2023と2024を別々に登録するのではなく、同じカタログを差し替えて更新する運用にしたい場合です。
このときハンドルに2023とかいう文字列が入っていると、2024に差し替えたあと微妙な気持ちになります。かといって、ハンドルも2024に直す運用にしてしまうと、毎回掲載されている製品すべての商品ページのメタフィールドを修正しなければなりません。
しんど。
もちろん、2023と2024のカタログを両方掲載して、商品ページ側に2024も追加していく、ということもできますが、どっちにしろしんど。
おすすめは、もし定期的に更新されるタイプの総合カタログなどであれば、ハンドルにバージョンを入れずに差し替えていく運用ですね。
ただここでもうひとつ罠があります。罠だらけです。
Shopifyでは、同じ名前のファイルをアップロードすると、ふたつめ以降のファイル名にハッシュがついてしまいます。
もしめちゃめちゃハッシュつくの嫌だわ、っていう場合は、一度既存のファイルを削除してから、新しいファイルをアップロードする必要があります。
(気にしないなら別にアップしちゃってそのファイルを選択し直せば良いのですが)
カタログの指定方法をブログ記事のハンドルにしたため、商品ページ側ではファイル名が変わっていても問題ありませんが、万が一ファイル名を指定するようにしていたらと思うとゾッとします。
絶対にファイル削除してからアップロードという工程を踏むか、でなければハッシュのついたファイル名をメタフィールドに登録しなければいけないからです。
ゾッとします…
ブログ一覧のテンプレートを作る
カタログデータと商品データの準備ができたら、いよいよ製品カタログ一覧のテンプレートを作っていきます。
main-blog-catalogue.liquid
main-blog-catalogue.liquidファイルに必要なコードはこんな感じです。
<h1 class="mt0 mb0">
{%- unless current_tags -%}
{{ blog.title | escape }}
{%- else -%}
"{{ current_tags.first }}"のカタログ一覧
{%- endunless -%}
</h1>
<ul class="catalogue-archive flex">
{% for article in blog.articles %}
{%- render 'catalogue-card', article: article, col: 'col-4' -%}
{%- endfor -%}
</ul>
その他もともともファイルにあったセクションのsettingsやblocksを利用したい場合は、必要なコードを残しておいても問題ありません。逆に、不要であれば消してしまってもかまいません。
current_tagsは、現在のページがタグページかどうかを判定できます。
{%- unless current_tags -%}
この判定によって、通常のブログのインデックスなのか、タグページなのかで分岐させ、タグページならば「”当該タグ名”のカタログ一覧」というタイトルに変えています。
"{{ current_tags.first }}"のカタログ一覧
カードUIをスニペットにする
リストアイテムは、スニペットファイルで読み込むことにします。
なぜかというと、このカタログデータを商品ページで表示したり、フリーワード検索結果画面でカタログを表示するときに、同じコードを使いまわしたいがためです。
snippetsディレクトリにcatalogue-card.liquidファイルを作成します。
<li class="col-sp-6 {{ col }}">
<a href="{{ article.url }}" class="linkto-article-catalogue">
{%- if article.image != blank -%}
<div class="article-thumbnail" style="background-image:url({{ article.image | image_url }});"></div>
{%- endif -%}
<span>{{ article.title }}</span>
</a>
<a
href="{{ article.metafields.blogs.catalogue | file_url }}"
class="button"
target="_blank">
<i class="fa-solid fa-file-pdf"></i> ダウンロード</a>
</li>
呼び出し元の下記のコードでは、articleとcolの2種類の変数を渡しています。
{%- render 'catalogue-card', article: article, col: 'col-4' -%}
articleはループしているアイテムのarticleオブジェクト、colは呼び出し元のリストのカラム数を決めるためのclass名です。
ちなみにcol-4の数字についてですが、12分割のグリッドを意識した設計なので、4は4/12つまり1/3というわけで、3カラムになっています。
あとは受け取ったデータのタイトルやURL、メタフィールドに登録したカタログPDFファイルのダウンロードボタンなどを記述しています。
見た目のスタイリングはCSSで好きに作ってください。

一覧の画面ができました!
なお、Dawnテーマでサイドメニューを実装する方法はこちらの記事で紹介しています。
製品カタログ記事詳細のテンプレートを作る
次に製品カタログの単一ページにあたる、ブログ記事のテンプレートを作っていきます。
catalogue-article.liquidファイルの中身はこんな感じです。
<article
id="article-catalogue"
itemscope
itemtype="http://schema.org/BlogPosting">
<div class="flex col-12">
<div class="col-sp-12 col-6">
{%- if article.image != blank -%}
{% assign imagesize = article.image.width | append: 'x' %}
<img
srcset="{{ article.image | img_url: imagesize }} 1x, {{ article.image | img_url: imagesize, scale: 2 }} 2x"
src="{{ article.image | img_url: imagesize }}"
loading="lazy"
alt="{{ article.image.alt | escape }}">
{%- endif -%}
</div>
<div class="col-sp-12 col-6 catalogue-info">
<div class="article-heading">
<h1 class="mt0 mb0" itemprop="headline">{{ article.title | escape }}</h1>
{%- if article.tags.size > 0 -%}
{%- render 'tags', tags: article.tags, url: '/blogs/catalogue/' -%}
{%- endif -%}
</div>
<a
href="{{ article.metafields.blogs.catalogue | file_url }}"
class="button"
target="_blank">
<i class="fa-solid fa-file-pdf"></i>
ダウンロード</a>
{%- if article.content != blank -%}
<div class="article-container" itemprop="articleBody">
{{ article.content }}
</div>
{%- else -%}
{{ article.excerpt_or_content }}
{%- endif -%}
<h2>このカタログに掲載されている商品</h2>
<ul class="fa-ul">
{%- for catalogue_product in article.metafields.blogs.catalogue_product.value -%}
<li>
<span class="fa-li">
<i class="fa-solid fa-chevron-right"></i>
</span>
<a href="{{ catalogue_product.url }}">{{ catalogue_product.title }}</a>
</li>
{%- endfor -%}
</ul>
</div>
</div>
</article>
ポイントとなる部分を説明していきます。
カタログのタグリストを表示してタグ別一覧のリンクをつける
以前、タグUIのリンクリストを作成する方法を紹介しました。
上記の記事のとおりに作成したタグUIのスニペットに、article.tagsオブジェクト(タグのデータ)と、タグページのパスを文字列で渡します。
{%- render 'tags', tags: article.tags, url: '/blogs/catalogue/' -%}
これで製品カタログが属するカテゴリの表示と、タグ一覧への導線の両方を実現することができました。
ダウンロードボタンを表示する
カタログPDFファイルは、メタフィールドで設定しているため、file_urlフィルターを使ってURLを取得することができます。
<a
href="{{ article.metafields.blogs.catalogue | file_url }}"
class="button"
target="_blank">
<i class="fa-solid fa-file-pdf"></i>
ダウンロード</a>
ShopifyでのFont Awesomeの使い方も、以前解説を書いていますので、参考にしてください。
投稿コンテンツを表示する
もしカタログについての説明文などを出したい場合は、ブログ記事のコンテンツに自由に入力して、通常のブログ記事と同様に出力します。
{%- if article.content != blank -%}
<div class="article-container" itemprop="articleBody">
{{ article.content }}
</div>
{%- else -%}
{{ article.excerpt_or_content }}
{%- endif -%}
excerpt_or_contentは便利なオブジェクトで、もし記事の「抜粋」がある場合は抜粋を返し、ない場合にはコンテンツをそのまま返してくれる、という優れものです。
今回は先にコンテンツがあるか判定しているので、抜粋がなければ何も表示されないということになります。
ただ抜粋を表示したいだけであれば、article.excerptで抜粋を表示することができますが、その場合は抜粋があるかないかの判定も書かないといけないので、excerpt_or_contentのほうがちょっと楽ができるかもしれません。
上記を活用すれば、たとえば、一覧ページでは抜粋を表示して、ブログ記事ページではコンテンツを表示するという設計もできます。
カタログに掲載されている商品の商品ページを表示する
最後が、商品ページへの導線です。
<h2>このカタログに掲載されている商品</h2>
<ul class="fa-ul">
{%- for catalogue_product in article.metafields.blogs.catalogue_product.value -%}
<li>
<span class="fa-li">
<i class="fa-solid fa-chevron-right"></i>
</span>
<a href="{{ catalogue_product.url }}">{{ catalogue_product.title }}</a>
</li>
{%- endfor -%}
</ul>
メタフィールドに複数商品が登録されているケースがあるので、それらをループしてリンクリストを表示します。
「fa-ul」classは、Font Awesomeがもともと用意しているスタイリングオプションで、今回のようなリストのリストマーカーをFont AwesomeのアイコンにしたUIにしてくれます。
自前でリストのスタイルを用意しなくて良い点もさることながら、リストアイテムごとにアイコンを変えたい場合にも、微調整がいらないのでとくに楽かと思います。
こんな感じになりました。

今回はサンプルは特定のソフト1本のカタログになっていますが、総合カタログであれば商品をたくさん並べて商品の情報も表示したい、という場合もあるかもしれません。
上記はシンプルなテキストリンクですが、商品の画像や価格を取得してくることも可能なので、スニペットを使ってカードUIのリストなどにしても良いと思います。
商品ページにカタログページへの導線とダウンロードボタンを設置する
さて、製品カタログのページはできあがりましたので、次は商品ページにカタログを表示してみます。
とりあえず今回は、Dawnテーマで用意されているセクションのmain-product.liquidファイルに追加してみたいと思います。
<!-- カタログPDF -->
{%- if product.metafields.product.catalogue != blank -%}
{%- assign catalogue_items = product.metafields.product.catalogue.value -%}
<h3>この製品が掲載されているカタログ</h3>
<ul class="catalogue-archive">
{% for item in catalogue_items %}
{%- assign item_handle = 'catalogue/' | append: item -%}
{%- assign catalogue_article = articles[item_handle] -%}
{%- render 'catalogue-card', article: catalogue_article -%}
{%- endfor -%}
</ul>
{%- endif -%}
先ほど紹介した「罠」に対応するため、カタログの情報はハンドルの文字列から探しにいかなければなりません。
メタフィールドのvalueをループしつつ、次の処理をしています。
まずはURLのパスの文字列にハンドルの文字列を繋げます。
appendフィルターを使ってハンドルを後ろに追加して結合しています。
{%- assign item_handle = 'catalogue/' | append: item -%}
なぜこうするかというと、その次の行に意味があります。
{%- assign catalogue_article = articles[item_handle] -%}
articles[ブログのハンドル/記事のハンドル]で特定のブログ記事のパスを指定することで、その記事のオブジェクトを扱うことができます。
本来はメタフィールド上でブログ記事オブジェクトを直接指定したいところですが…
それでもこの方法を利用すればブログ記事の情報を取得することができるので、なんとかなって助かりました。
そして、このブログ記事オブジェクトをスニペットに渡して、カードUIで表示します。
{%- render 'catalogue-card', article: catalogue_article -%}
すでに製品カタログ一覧ページで使用しているカードUIがあるので、それを流用することができます。
もちろん、商品ページでは別のUIで表示するということもできますので、そこらへんは自由にデザインしてください。
できあがりがこんな感じです。

おわり
いやー長かったですね。お疲れ様でした。
これまでShopifyのテーマカスタマイズの記事をいくつか投稿しましたが、がっつりコンテンツ登録〜表示の仕組み自体を作るのはかなり大変でした。
でも、これができたら商品データとその他のコンテンツを紐づけてなんやかんやする、というところの基本がだいたいできたことになります。
「お知らせ」のカテゴリ分けとか、「よくあるご質問」も、同様の方法で実現することができます。
冒頭でも言った通り、ただのカート通販ではなく情報を網羅したwebサイトを制作する、という点で比較すると、Shopifyがプロジェクトの選択肢から外れるケースもあるかもしれません。
でも、考えれば実現できることもあったりするし、わりと選択肢あるよ!というふうに思ってもらえたら嬉しいです。