Liquid Snippets by ALSEL
🛍️ 商品表示中級

おすすめ商品のスライダー表示

商品をスライダー形式で表示するセクション。コレクションか個別選択、または商品ページでは Shopify の AI アルゴリズムによるおすすめ商品を自動表示する。

用途
トップページやコレクションページで複数商品をカルーセル形式で紹介したいとき。商品ページに設置すれば AI がおすすめ商品を自動抽出して表示する。
設置場所
sections/featured-products.liquid に配置。管理画面のテーマエディタで「セクションを追加」→「おすすめ商品」として選択し、表示する商品とスライダー設定を行う。
注意点
おすすめモード(Recommended Mode)は商品ページでのみ機能するため、コレクションページに設置する場合は個別商品選択またはコレクション指定を使う前提。おすすめモードを有効にしたとき、上部の商品選択設定は無視される。スライダー速度・ナビゲーション・自動再生などの挙動は data-slider-* 属性で制御するため、JavaScript が無効だと動作しない。
タグ:productslidercarouselsectionswiperrecommendation

コード

440 行 / liquid
{% liquid
  if section.settings.collection == blank
    assign products = section.settings.products
  else
    assign products = collections[section.settings.collection].products
  endif
%}

{% capture empty_state %}
  {% unless request.page_type == 'product' %}
    {% for num in (1..section.settings.limit) %}
      <div class="swiper-slide p-4 p-desktop-5">
        <div class="product-card text-center">
          {% capture current %}{% cycle 1, 2, 3, 4, 5, 6 %}{% endcapture %}
          {{ 'product-' | append: current | placeholder_svg_tag: 'product-card-img img-thumbnail mb-4' }}
          <h3 class="product-card-title h6 mb-1">
            Product {{ current }}
          </h3>
          <p class="mb-0">
            $19.99
          </p>
        </div>
      </div>
    {% endfor %}
  {% endunless %}
{% endcapture %}

{% if section.settings.recommended_mode and request.page_type == 'product' %}
<script>
  async function initProductRecommendations ()  {
    const sectionId = '{{ section.id }}'
    const baseUrl = '{{ routes.product_recommendations_url }}'
    const productId = {{ product.id }}
    const limit = {{ section.settings.limit }}
    const intent = '{{ section.settings.recommended_mode_intent }}'
    
    const url = `${baseUrl}?section_id=${sectionId}&product_id=${productId}&limit=${limit}&intent=${intent}`

    const response = await fetch(url)
    const data = await response.text()

    // console.log(url)
    // console.log(data)

    document.querySelector('#featured-products-{{ section.id }}')
      .closest('.shopify-section').outerHTML = data
  }

  window.addEventListener('DOMContentLoaded', () => {
    initProductRecommendations()
  })

  document.addEventListener('shopify:section:load', (e) => {
    if (e.target.querySelector('.featured-products')) {
      initProductRecommendations()
    }
  })  
</script>
{% endif %}

<swiper-slider
  id="featured-products-{{ section.id }}" 
  class="
    featured-products swiper-slider
    {{ section.settings.bg_color }} 
    {{ section.settings.bg_gradient }}
    {{ section.settings.text_color }}
    {{ section.settings.border_top_width | prepend: 'border-top-' }}
    {{ section.settings.border_bottom_width | prepend: 'border-bottom-' }}
    {{ section.settings.border_color }} 
    {{ section.settings.pt | prepend: 'pt-' }} 
    {{ section.settings.pb | prepend: 'pb-' }}
  "
  style="
    --bs-bg-opacity: {{ section.settings.bg_opacity | append: '%' }};
    --bs-border-opacity: {{ section.settings.border_opacity | append: '%' }};
  "
  data-section-id="{{ section.id }}"
  data-slider-speed="{{ section.settings.slider_speed }}"
  data-slider-navigation="{{ section.settings.slider_navigation }}"
  data-slider-pagination="{{ section.settings.slider_pagination }}"
  data-slider-scrollbar="{{ section.settings.slider_scrollbar }}"
  data-slider-autoplay="{{ section.settings.slider_autoplay }}"
  data-breakpoint-mobile="{{ section.settings.breakpoint_mobile }}"
  data-breakpoint-tablet="{{ section.settings.breakpoint_tablet }}"
  data-breakpoint-desktop="{{ section.settings.breakpoint_desktop }}">
  <div 
    class="container"
    style="max-width: {{ section.settings.container_max_width | append: 'px' }};">
    {% render 'section-header' %}
    <div class="swiper mx-n4 mx-desktop-n5 mt-n3 mt-desktop-n5">
      <div class="swiper-wrapper">
        {% if section.settings.recommended_mode and request.path contains 'recommendations' %}
          {% for product in recommendations.products %}
            <div class="swiper-slide p-4 p-desktop-5">
              {% render 'product-card', product: product %}
            </div>
          {% endfor %}
        {% elsif products == blank %}
          {{ empty_state }}
        {% else %}
          {% for product in products limit: section.settings.limit %} 
            <div class="swiper-slide p-4 p-desktop-5">
              {% render 'product-card', product: product %}
            </div>
          {% endfor %}
        {% endif %}
      </div>
      <div class="swiper-controls">
        <div class="swiper-pagination"></div>
        <div class="swiper-scrollbar"></div>
        <div class="swiper-button-prev">
          {% render 'svg-icons', icon: 'chevron-left', size: 24 %}
        </div>
        <div class="swiper-button-next">
          {% render 'svg-icons', icon: 'chevron-right', size: 24 %}
        </div>
      </div>
    </div>
  </div>
</swiper-slider>

{% schema %}
{
  "name": "Featured products",
  "tag": "section",
  "settings": [
    {
      "type": "header",
      "content": "Styling"
    },
    {
      "type": "select",
      "id": "bg_color",
      "label": "Background color",
      "default": "bg-body",
      "options": [
        { "value": "bg-primary", "label": "Primary" },
        { "value": "bg-secondary", "label": "Secondary" },
        { "value": "bg-body", "label": "Body" },
        { "value": "bg-white", "label": "White" }
      ]
    },
    {
      "type": "range",
      "id": "bg_opacity",
      "label": "Background opacity",
      "min": 0,
      "max": 100,
      "step": 1,
      "default": 100,
      "unit": "%"
    },
    {
      "type": "select",
      "id": "bg_gradient",
      "label": "Background gradient",
      "options": [
        { "value": "bg-gradient", "label": "Yes" },
        { "value": "", "label": "No" }
      ],
      "default": ""
    },
    {
      "type": "select",
      "id": "text_color",
      "label": "Text color",
      "default": "text-body",
      "options": [
        { "value": "text-primary", "label": "Primary" },
        { "value": "text-secondary", "label": "Secondary" },
        { "value": "text-body", "label": "Body" },
        { "value": "text-white", "label": "White" }
      ]
    },
    {
      "type": "range",
      "id": "border_top_width",
      "label": "Border top width",
      "default": 0,
      "min": 0,
      "max": 16,
      "step": 1,
      "unit": "px"
    },
    {
      "type": "range",
      "id": "border_bottom_width",
      "label": "Border bottom width",
      "default": 0,
      "min": 0,
      "max": 16,
      "step": 1,
      "unit": "px"
    },
    {
      "type": "select",
      "id": "border_color",
      "label": "Border color",
      "default": "border-body",
      "options": [
        { "value": "border-primary", "label": "Primary" },
        { "value": "border-secondary", "label": "Secondary" },
        { "value": "border-body", "label": "Body" },
        { "value": "border-white", "label": "White" }
      ]
    },
    {
      "type": "range",
      "id": "border_opacity",
      "label": "Border opacity",
      "min": 0,
      "max": 100,
      "step": 1,
      "default": 100,
      "unit": "%"
    },
    {
      "type": "text",
      "id": "container_max_width",
      "label": "Container max-width (px)",
      "info": "Leave empty to use the global container width"
    },
    {
      "type": "header",
      "content": "General"
    },
    {
      "type": "paragraph",
      "content": "Choose whether to display your products by selecting them individually or through a collection. If this section is published on the product page, the \"recommended mode\" is suggested to be used."
    },
    {
      "type": "product_list",
      "id": "products",
      "label": "Products"
    },
    {
      "type": "collection",
      "id": "collection",
      "label": "Collection"
    },
    {
      "type": "range",
      "id": "limit",
      "label": "Limit products",
      "min": 2,
      "max": 24,
      "default": 8,
      "step": 1
    },
    {
      "type": "header",
      "content": "Recommended Mode",
      "info": "Show recommended products based on Shopify AI algorithm. Applies only if this section is published on the product page. The product selection settings bove do not have effect if this setting is enabled."
    },
    {
      "type": "checkbox",
      "id": "recommended_mode",
      "label": "Enable \"Recommended mode\"",
      "default": true
    },
    {
      "type": "select",
      "id": "recommended_mode_intent",
      "label": "Intent",
      "default": "related",
      "options": [
        { "value": "related", "label": "Related" },
        { "value": "complementary", "label": "Complementary" }
      ],
      "info": "\"Related\", offers customers a mix of products that are similar to a product the customer is interacting with. \"Complementary\" recommandations are products that supplement a product. Related recommendations are auto-generated by Shopify AI. Complementary recommendations need to be manually set up. Recommended products for each intent can be configured via the [Shopify Search & Discovery app](https://apps.shopify.com/search-and-discovery)"
    },
    {
      "type": "header",
      "content": "Header"
    },
    {
      "type": "text",
      "id": "header_title",
      "label": "Title",
      "default": "Featured Products"
    },
    {
      "type": "select",
      "id": "header_title_font_size",
      "label": "Title font-size",
      "default": "h2",
      "options": [
        { "value": "h1", "label": "H1" },
        { "value": "h2", "label": "H2" },
        { "value": "h3", "label": "H3" },
        { "value": "h4", "label": "H4" },
        { "value": "h5", "label": "H5" },
        { "value": "h6", "label": "H6" }
      ]
    },
    {
      "type": "richtext",
      "id": "header_description",
      "label": "Description (optional)",
      "default": "<p>Add on optional description for this section</p>"
    },
    {
      "type": "select",
      "id": "header_description_font_size",
      "label": "Description font-size",
      "default": "fs-md",
      "options": [
        { "value": "fs-sm", "label": "sm" },
        { "value": "fs-md", "label": "md" },
        { "value": "fs-lg", "label": "lg" },
        { "value": "fs-xl", "label": "xl" },
        { "value": "fs-xxl", "label": "xxl" }
      ]
    },
    {
      "type": "header",
      "content": "Slider"
    },
    {
      "type": "range",
      "id": "slider_speed",
      "label": "Speed",
      "default": 300,
      "min": 0,
      "max": 2000,
      "step": 100,
      "unit": "ms"
    },
    {
      "type": "checkbox",
      "id": "slider_navigation",
      "label": "Show navigation (arrows)",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "slider_pagination",
      "label": "Show pagination",
      "default": true
    },
    {
      "type": "select",
      "id": "slider_pagination_type",
      "label": "Pagination type",
      "default": "bullets", 
      "options": [
        { "value": "bullets", "label": "Bullets" },
        { "value": "fraction", "label": "Fraction" }
      ],
      "info": "NOTE: This feature is supported only in our Premium Shopify Themes. [Browse premium themes](https://www.kondasoft.com/collections/shopify-themes)"
    },
    {
      "type": "checkbox",
      "id": "slider_scrollbar",
      "label": "Show scrollbar",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "slider_partial_slides_mobile",
      "label": "Partial slides on mobile",
      "default": false,
      "info": "NOTE: This feature is supported only in our Premium Shopify Themes. [Browse premium themes](https://www.kondasoft.com/collections/shopify-themes)"
    },
    {
      "type": "range",
      "id": "slider_autoplay",
      "label": "Autoplay",
      "min": 0,
      "max": 10,
      "default": 0,
      "unit": "sec",
      "info": "Selecing \"0\" will disable autoplay."
    },
    {
      "type": "header",
      "content": "Breakpoints",
      "info": "Adjust items per slide based on the screen resolution"
    },
    {
      "type": "range",
      "id": "breakpoint_mobile",
      "label": "Mobile (<600px)",
      "min": 1,
      "max": 3,
      "step": 1,
      "default": 1
    },
    {
      "type": "range",
      "id": "breakpoint_tablet",
      "label": "Tablet (≥600px)",
      "min": 1,
      "max": 4,
      "step": 1,
      "default": 2
    },
    {
      "type": "range",
      "id": "breakpoint_desktop",
      "label": "Desktop (≥1200px)",
      "min": 1,
      "max": 6,
      "step": 1,
      "default": 4
    },
    {
      "type": "header",
      "content": "Spacing"
    },
    {
      "type": "range",
      "id": "pt",
      "label": "Top",
      "min": 0,
      "max": 20,
      "step": 1,
      "default": 10
    },
    {
      "type": "range",
      "id": "pb",
      "label": "Bottom",
      "min": 0,
      "max": 20,
      "step": 1,
      "default": 10
    }
  ],
  "disabled_on": {
    "groups": ["header", "footer"]
  },
  "presets": [
    {
      "name": "Featured products"
    }
  ]
}
{% endschema %}

出典・ライセンス

License:
MIT

このコードは kondasoft 著作の MIT ライセンスソースです。 原本の著作権は kondasoft が保有します。日本語訳は ALSEL によるものです。

関連項目

🛍️ 商品表示上級

商品ブロック内のLiquid実行

セクションブロック内で管理画面から入力した Liquid コードを直接実行し、パディング設定で上下の余白を制御するスニペット。テーマカスタマイザーでコード記述が可能。

📁 ks-bootshop·MIT·8
🛍️ 商品表示初級

商品ページの見出し

商品詳細ページの商品名を h1 見出しで表示するブロック。テーマカスタマイザーから見出しサイズと上下の余白(padding)を調整できる。

📁 ks-bootshop·MIT·8
🛍️ 商品表示中級

商品レビューバッジの表示

Loox と JudgeMe 両方のレビュー集約アプリに対応したレーティングバッジを商品ページに埋め込む。メタフィールドから平均評価とレビュー数を取得し、各アプリの UI コンポーネントを描画する。

📁 ks-bootshop·MIT·9
🛍️ 商品表示中級

定期販売プランのデータ属性を動的に生成

商品の定期販売プラン(Selling Plans)をループで取得し、data 属性として HTML に埋め込むスニペット。JavaScript で定期販売オプションを制御するためのデータ基盤として機能する。

📁 theme-tools·MIT·10
🛍️ 商品表示初級

商品ページの区切り線

商品詳細ページで、セクション間に区切り線を挿入するブロック。パディング、高さ、背景色、透明度をカスタマイズできる。

📁 ks-bootshop·MIT·15
🛍️ 商品表示初級

商品画像のプリロード出力

商品オブジェクトから image_tag フィルターを使い、preload 属性付きで画像を出力するスニペット。複数商品のループ内でも使える基本的なパターン。

📁 theme-tools·MIT·16