HOME » BLOG » Shopifyカスタマイズ事例8:商品タグ連動型「関連記事」の表示

BLOGShopifyカスタマイズ事例8:商品タグ連動型「関連記事」の表示

Shopifyカスタマイズ事例8:商品タグ連動型「関連記事」の表示

ECの利益向上に繋がるShopifyカスタマイズ事例8


弊社ではShopifyでの制作をはじめ、様々なECサイトの制作のご依頼をいただいています。
特に、現在はECサイトの売上をUPしつつ効率的な運用を行いたい、月商を1,000万円以上の規模に成長させたい、月商億円規模のサイトを安全にシステム移管したい等、「利益を上げる知識」と「システム構築の知識」を総合的に持つことで解決できるご要望を、ワンストップで実現することを得意としています。
その現場の中で行ってきたカスタマイズ事例について、解説します。

事例8:商品タグ連動型「関連記事」の表示

カスタマイズの背景

商品ページに訪れたユーザーは、スペック情報だけでなく「使い方の例」や「開発背景などのストーリー性」を求める傾向が強まっています。弊社にご相談いただいたサイトのご商品も、商品の設置方法や設置事例が必要な商品だったのですが、すべての情報を商品詳細だけでは伝えるのが難しい商品でした。
そのため、商品詳細ページに、関連したブログ記事を自動表示できると、商品に関係する記事コンテンツの表示・更新・管理が簡単になるのですが、Shopifyのデフォルトでは、そのような機能が存在していませんでした。
そこで、商品に設定したタグと同じタグを持つブログ記事を自動抽出し、商品ページ下部に「関連記事」として表示するカスタマイズを実施しました。

カスタマイズ前の課題

  • 説明や利用例が必要な商品であり、商品の購入率が想定よりも低かった
  • 商品ページの購入前後にブログ記事を閲覧しているケースが多い傾向だったが、商品詳細側からの動線は無かった
  • 商品が複数あるので、管理・更新を効率的に行いたい
  • 関連記事アプリの月額コストの増加を抑制したい

カスタマイズでの要件・解決案

  • 商品タグと記事タグを比較して、完全自動で関連記事を抽出
  • 表示件数・並び順・カラム数を、ノーコードで変更可能に
  • セクションで設置・更新できるように設定し、EC担当者でも簡単に調整できるように
  • ページ速度に影響しないよう、遅延読み込み & 軽量構成を維持
  • Liquidでの開発・設置により、月額コストの増加を回避

実装方法

全体Liquidコード

このコードを、セクションのliquidコードとして用意し、商品詳細ページに追加セクションとして組み込むことで、商品タグに応じた関連記事の自動表示を実現しています。

{% liquid
  assign blog_handle   = section.settings.blog
  if blogs[blog_handle] == nil
	  assign related_posts = []
  else
  assign limit_count   = section.settings.article_limit | default: 3
  assign sort_order    = section.settings.sort_order
  assign posts         = blogs[blog_handle].articles
  assign related_posts = []

  for article in posts
	# 共通タグがあれば収集
	for t in article.tags
	  if product.tags contains t
		assign related_posts = related_posts | push: article
		break
	  endif
	endfor
  endfor

  # 並び替え
  if sort_order == 'random'
	assign related_posts = related_posts | shuffle
  elsif sort_order == 'newest'
	assign related_posts = related_posts | sort: 'published_at' | reverse
  else
	assign related_posts = related_posts
  endif

  # 表示数でカット
  assign related_posts = related_posts | slice: 0, limit_count
  endif
%}

{% if related_posts.size > 0 %}
<section id="RelatedBlogPosts-{{ section.id }}" class="related-blog-posts">
  <style>
	#RelatedBlogPosts-{{ section.id }}{
	  --col-desk: {{ section.settings.columns_desktop }};
	  --col-mob:  {{ section.settings.columns_mobile }};
	}
	#RelatedBlogPosts-{{ section.id }} .articles-grid{
	  display:grid;
	  gap:1.5rem;
	  grid-template-columns:repeat(var(--col-mob),1fr);
	}
	@media(min-width:768px){
	  #RelatedBlogPosts-{{ section.id }} .articles-grid{
		grid-template-columns:repeat(var(--col-desk),1fr);
	  }
	}
	#RelatedBlogPosts-{{ section.id }} .post_card a{
	  display:block;text-decoration:none;color:inherit;height:100%;
	}
	#RelatedBlogPosts-{{ section.id }} .post_card img{
	  width:100%;height:auto;display:block;
	}
	#RelatedBlogPosts-{{ section.id }} .post_meta{
	  font-size:.85rem;color:#777;
	}
  </style>

  <div class="articles-grid">
	{% for a in related_posts %}
	  <article class="post_card">
		  {% if a.image %}
			<a href="{{ a.url }}"><img
			  src="{{ a.image | image_url: width:1200 }}"
			  alt="{{ a.image.alt | default: a.title | escape }}"
			  width="{{ a.image.width }}"
			  height="{{ a.image.height }}"
			  loading="lazy"
			></a>
		  {% endif %}
		  <h3 class="post_title"><a href="{{ a.url }}">{{ a.title }}</a></h3>
		  {% if section.settings.show_date or section.settings.show_author %}
			<p class="post_meta">
			  {% if section.settings.show_date %}
				<time datetime="{{ a.published_at | date: '%Y-%m-%d' }}">
				  {{ a.published_at | date: '%Y/%m/%d' }}
				</time>
			  {% endif %}
			  {% if section.settings.show_author %}
				{% if section.settings.show_date %}&nbsp;|&nbsp;{% endif %}
				{{ a.author }}
			  {% endif %}
			</p>
		  {% endif %}
	  </article>
	{% endfor %}
  </div>
</section>
{% endif %}

{% schema %}
{
  "name": "商品の関連記事",
  "settings": [
	{
	  "type": "blog",
	  "id": "blog",
	  "label": "対象ブログ",
	  "default": "news"
	},
	{
	  "type": "select",
	  "id": "sort_order",
	  "label": "並び順",
	  "options": [
		{ "value": "newest", "label": "新着順" },
		{ "value": "random", "label": "ランダム" }
	  ],
	  "default": "newest"
	},
	{
	  "type": "range",
	  "id": "article_limit",
	  "label": "記事表示数",
	  "min": 1,
	  "max": 12,
	  "step": 1,
	  "default": 3
	},
	{
	  "type": "range",
	  "id": "columns_desktop",
	  "label": "PC表示カラム数",
	  "min": 1,
	  "max": 4,
	  "step": 1,
	  "default": 3
	},
	{
	  "type": "range",
	  "id": "columns_mobile",
	  "label": "スマホ表示カラム数",
	  "min": 1,
	  "max": 4,
	  "step": 1,
	  "default": 1
	},
	{
	  "type": "checkbox",
	  "id": "show_date",
	  "label": "投稿日を表示",
	  "default": true
	},
	{
	  "type": "checkbox",
	  "id": "show_author",
	  "label": "投稿者を表示",
	  "default": false
	}
  ],
  "presets": [
	{ "name": "商品の関連記事" }
  ]
}
{% endschema %}

コード解説

1. セクション設定&初期化

Liquid でブログハンドルや表示数を取得し、関連記事配列を用意します。

  assign blog_handle = section.settings.blog
  if blogs[blog_handle] == nil
	assign related_posts = []       # 対象ブログが存在しなければ空で終了
  else
	assign limit_count   = section.settings.article_limit | default: 3
	assign sort_order    = section.settings.sort_order
	assign posts         = blogs[blog_handle].articles
	assign related_posts = []

ポイント:
section.settings.*テーマエディタ側で変更できる値 を自動反映する便利な仕組みです。エンジニアがコードを触らなくても、EC 担当者が記事件数や並び順を管理画面で変更できます。

2. 商品タグと記事タグを突き合わせ

二重ループでタグを比較し、マッチした記事を表示対象として配列化します。

	for article in posts
	  # 共通タグがあれば収集
	  for t in article.tags
		if product.tags contains t
		  assign related_posts = related_posts | push: article
		  break
		endif
	  endfor
	endfor

ポイント:
・商品側のタグは product.tags が配列で返るため、contains で高速照合できます。
break を入れることで 1 記事につき最初の一致でループ終了。不要なタグ比較をカットしパフォーマンスを確保しています。

3. ソート & 上限件数の制御

新着順かランダムかをセレクトボックスで切替。
最後に slice で表示件数を制限します。

	if sort_order == 'random'
	  assign related_posts = related_posts | shuffle
	elsif sort_order == 'newest'
	  assign related_posts = related_posts | sort: 'published_at' | reverse
	endif

	assign related_posts = related_posts | slice: 0, limit_count
  endif

ポイント:
shuffle は Liquid 標準の 配列シャッフル フィルターです。毎回順序が変わるのでランダム表示が可能です。
sort: 'published_at' | reverse は実質、新着順です。昇順に並んだあと reverse で反転しています。

4. フロント出力(HTML + CSS)

グリッド列数をCSSで可変化し、PC/スマートフォンでの表示変更に対応します。

{% if related_posts.size > 0 %}
<section id="RelatedBlogPosts-{{ section.id }}" class="related-blog-posts">
  <style>
	#RelatedBlogPosts-{{ section.id }}{
	  --col-desk: {{ section.settings.columns_desktop }};
	  --col-mob:  {{ section.settings.columns_mobile }};
	}
	#RelatedBlogPosts-{{ section.id }} .articles-grid{
	  display:grid;
	  gap:1.5rem;
	  grid-template-columns:repeat(var(--col-mob),1fr);
	}
	@media(min-width:768px){
	  #RelatedBlogPosts-{{ section.id }} .articles-grid{
		grid-template-columns:repeat(var(--col-desk),1fr);
	  }
	}
  </style>

  <div class="articles-grid">
	{% for a in related_posts %}
	  <article class="post_card">
		{% if a.image %}
		  <a href="{{ a.url }}"><img src="{{ a.image | image_url: width:1200 }}"
			alt="{{ a.image.alt | default: a.title | escape }}"
			width="{{ a.image.width }}" height="{{ a.image.height }}" loading="lazy"></a>
		{% endif %}
		<h3 class="post_title"><a href="{{ a.url }}">{{ a.title }}</a></h3>
		{% if section.settings.show_date or section.settings.show_author %}
		  <p class="post_meta">
			{% if section.settings.show_date %}
			  <time datetime="{{ a.published_at | date: '%Y-%m-%d' }}">
				{{ a.published_at | date: '%Y/%m/%d' }}
			  </time>
			{% endif %}
			{% if section.settings.show_author %}
			  {% if section.settings.show_date %}&nbsp;|&nbsp;{% endif %}
			  {{ a.author }}
			{% endif %}
		  </p>
		{% endif %}
	  </article>
	{% endfor %}
  </div>
</section>
{% endif %}

ポイント:
・画像に loading="lazy" を付け、ビューポート下の画像は スクロール時に後読み込み。表示速度の改善に寄与します。
・カード全体を <a>…</a> で囲まず、画像とタイトルそれぞれをリンク化→アクセシビリティ面でスクリーンリーダー対策となります。

5. セクション設定(schema)

すべてのオプションは管理画面から変更できます。

{% schema %}
{
  "name": "商品の関連記事",
  "settings": [
	{
	  "type": "blog",
	  "id": "blog",
	  "label": "対象ブログ",
	  "default": "news"
	},
	{
	  "type": "select",
	  "id": "sort_order",
	  "label": "並び順",
	  "options": [
		{ "value": "newest", "label": "新着順" },
		{ "value": "random", "label": "ランダム" }
	  ],
	  "default": "newest"
	},
	{
	  "type": "range",
	  "id": "article_limit",
	  "label": "記事表示数",
	  "min": 1,
	  "max": 12,
	  "step": 1,
	  "default": 3
	},
	{
	  "type": "range",
	  "id": "columns_desktop",
	  "label": "PC表示カラム数",
	  "min": 1,
	  "max": 4,
	  "step": 1,
	  "default": 3
	},
	{
	  "type": "range",
	  "id": "columns_mobile",
	  "label": "スマホ表示カラム数",
	  "min": 1,
	  "max": 4,
	  "step": 1,
	  "default": 1
	},
	{
	  "type": "checkbox",
	  "id": "show_date",
	  "label": "投稿日を表示",
	  "default": true
	},
	{
	  "type": "checkbox",
	  "id": "show_author",
	  "label": "投稿者を表示",
	  "default": false
	}
  ],
  "presets": [
	{ "name": "商品の関連記事" }
  ]
}
{% endschema %}

ポイント:
・各設定値とオプション値を、管理画面側から選択できるようにすることで、ノーコード運用を実現しています。

全体のポイント

今回のカスタマイズは、Shopifyのタグ機能を活用し、商品ページとブログを関連記事として結びつけることで、商品ページからの回遊率や商品購入率の向上を意図した関連記事を、自動で表示することが可能です。
適切な記事を用意することで、購入時に説明や事例が必要な商品に、改善効果を期待することができます。

結果

実装したサイトでは、商品の購入検討材料となる関連記事の存在で、対象商品の購入件数が向上する結果となりました。また回遊率向上の効果から、単価向上にも前向きな数字が出ており、ユーザーのエンゲージメントとしても良い結果となりました。
商品の特性を選ぶ施策ではありますが、商品購入の検討材料が必要な商品については、推奨の施策となります。(記事側からも該当商品に戻る仕掛けを作ることで、より効果があります)
Shopifyでは、セクションの活用で柔軟なカスタマイズが可能ですので、ぜひ自社ECサイトの向上に繋がる実装を試してみてください。

お気軽にお問い合わせください

弊社ではECをスタートされる方から、大規模ECの安全なリニューアル、個別のカスタマイズ実装まで幅広く対応可能です。
ご相談がございましたら、お気軽にご連絡ください。

お問い合わせ
SHARE: