【Dawn】「最近チェックした商品」の一覧を表示する方法

はじめに

Shopifyの標準テーマであるDawnやRiseでは、ユーザーが「過去に見た商品」を表示する機能はデフォルトで搭載されていません。
しかし、ECサイトにおいて”最近チェックした商品”の表示は、回遊率や再購入率を高める有効なUX改善施策です。

この記事では、ShopifyのDawnテーマで「最近チェックした商品」機能を自作する方法を解説します。
今回ご紹介する機能は、以下の流れで動作します。

  • ユーザーが商品ページを開くたびに、その商品のハンドルをブラウザのローカルストレージに保存
  • トップページや商品ページ下部など任意の箇所に、保存された閲覧履歴を読み込み&一覧表示

この仕組みを使うと、ユーザーが同一デバイスで閲覧した商品履歴を自動的に表示することができます。
LiquidとJavaScriptをそのままコピペすれば実装できますので、制作初心者の方でも挑戦しやすい内容です。
ぜひ最後までご覧ください!

実装方法

1. 履歴保存スクリプトを作成

ブラウザに閲覧履歴を保存するためのアセット「recently-viewed.js」を下記内容で新規作成します。(画像はクリックで拡大します)

document.addEventListener('DOMContentLoaded', () => {
  // 現在の商品ハンドルを取得
  const productHandle =
    window.ShopifyAnalytics?.meta?.product?.handle ||
    window.location.pathname.split('/products/')[1]?.split('/')[0];

  if (!productHandle) return;

  const key = 'recently_viewed';
  let viewed = JSON.parse(localStorage.getItem(key)) || [];

  // すでに同じ商品がある場合は削除して先頭に追加
  viewed = viewed.filter((h) => h !== productHandle);
  viewed.unshift(productHandle);

  // 最新10件まで保持
  if (viewed.length > 10) viewed = viewed.slice(0, 10);

  localStorage.setItem(key, JSON.stringify(viewed));
});

2. 専用のカードセクションを作成

閲覧した商品を描画する際に使用する、商品カード専用のセクション「recently-viewed-card.liquid」を新規作成します。

{%- comment -%}
目的:Dawn標準のカードUI(snippets/card-product.liquid)で
     “指定商品のカード1枚”だけをサーバー側で描画して返す。
{%- endcomment -%}

{%- render 'card-product',
  card_product: product,
  media_aspect_ratio: 'square',       # 'adapt' などに変更可(Dawnと合わせたい比率を設定)
  show_secondary_image: true,
  show_vendor: false,
  show_rating: false,
  lazy_load: true,
  section_id: 'recently-viewed'
-%}

{% schema %}
{
  "name": "Recently viewed card",
  "tag": "div",
  "class": "recently-viewed-card",
  "settings": []
}
{% endschema %}

3. 履歴表示用のセクションを作成

新規セクションファイル「recently-viewed.liquid」を下記内容で作成します。

<section id="recently-viewed" class="page-width">
  <h2 class="section-title">最近チェックした商品</h2>
  <div
    id="recently-viewed-products"
    class="grid
      {% if section.settings.columns_mobile == '2' %} grid--2-col {% else %} grid--1-col {% endif %}
      grid--2-col-tablet
      grid--{{ section.settings.columns_desktop }}-col-desktop">
  </div>
</section>

<script>
document.addEventListener('DOMContentLoaded', async () => {
  const container = document.getElementById('recently-viewed-products');
  if (!container) return;

  // 自分自身は除外
  const currentHandle =
    window.ShopifyAnalytics?.meta?.product?.handle ||
    window.location.pathname.split('/products/')[1]?.split('/')[0];

  // 履歴取得
  let viewed = [];
  try {
    viewed = JSON.parse(localStorage.getItem('recently_viewed')) || [];
  } catch(e) { viewed = []; }

  viewed = viewed.filter(h => h && h !== currentHandle);

  const limit = {{ section.settings.max_products | default: 5 }};
  const targets = viewed.slice(0, limit);

  // 1件ずつ “カードセクション” をサーバー描画して取得
  for (const handle of targets) {
    try {
      const res = await fetch(`/products/${handle}?section_id=recently-viewed-card`, { credentials: 'same-origin' });
      if (!res.ok) continue;
      const html = await res.text();

      // 返ってきたHTMLには余計なラッパーが含まれる可能性があるので抽出
      const tmp = document.createElement('div');
      tmp.innerHTML = html;

      // card-product のルート要素(.card-wrapper)を探す
      const card = tmp.querySelector('.card-wrapper') || tmp.firstElementChild;
      if (!card) continue;

      // Dawnのグリッドに合わせて grid__item で包む
      const wrap = document.createElement('div');
      wrap.className = 'grid__item';
      wrap.appendChild(card);

      container.appendChild(wrap);
    } catch (err) {
      console.error('Render failed:', handle, err);
    }
  }
});
</script>

{% schema %}
{
  "name": "最近チェックした商品",
  "tag": "section",
  "class": "recently-viewed-section",
  "settings": [
    {
      "type": "range",
      "id": "max_products",
      "label": "表示件数",
      "min": 2,
      "max": 10,
      "step": 1,
      "default": 4
    },
    {
      "type": "range",
      "id": "columns_desktop",
      "min": 1,
      "max": 6,
      "step": 1,
      "default": 4,
      "label": "デスクトップ列数"
    },
    {
      "type": "select",
      "id": "columns_mobile",
      "default": "2",
      "label": "モバイル列数",
      "options": [
        {
          "value": "1",
          "label": "1列"
        },
        {
          "value": "2",
          "label": "2列"
        }
      ]    
    }
  ],
  "presets": [
    {
      "name": "最近チェックした商品"
    }
  ]
}
{% endschema %}

4. スクリプトをサイトで読み込む

手順1で作成したスクリプトを商品ページやサイト全体で読み込むため、「main-product.liquid」または「theme.liquid」などに以下を追加します。
※「theme.liquid」に追加する際は、必ず</body>タグ直前に記述してください。

本記事では「main-product.liquid」に追加しています。

5. テーマにセクションを追加

管理画面のテーマエディタで商品ページなど任意のテンプレートを選択し、「セクションを追加」から「最近チェックした商品」を追加します。
これで、ユーザーが商品ページを閲覧するたびに履歴が保存され、「最近チェックした商品」セクションに自動で一覧が表示されるようになります。

まとめ

いかがでしたか?
「最近チェックした商品」機能は、ユーザーの行動履歴を可視化し、サイト内回遊を促す定番施策です。
この仕組みを応用すれば、「再訪問時に前回見た商品をハイライト」「閲覧履歴に基づくメールマーケティング」といった拡張も可能です。
まずは本機能をサイトに導入し、UX改善とリピート促進の両立を目指していきましょう。

弊社では、ECサイト制作だけでなくその後の運用までを、成果にコミットした万全のバックアップ体制でご支援しています。
売上最大化のために必要な運用すべてをサポートさせていただきますので、マーチャント様からの運用フェーズのご相談などでお困りの制作者様もお気軽にご連絡ください!

売上最大化に向けて戦略立案から構築・運用までワンストップでサポート

EC運用でお悩みの方はお任せください!

お問い合わせはこちら
一覧に戻る