[Shopify] 簡単なセクションの作り方

前記事からの続き。コード編集によるセクションの自作方法について。

大抵の機能はアプリでどうにかできるShopifyだけど、作り方さえわかっていれば自分で作れてしまうものも多いのだ。

画像のカルーセルをセクションで自作したので過程をメモっておいた。
ライブラリはSwiperを使うことにします。

※ Dawnにはスライドショーのセクションが含まれているので、それを使うこともできる

セクションファイルの作成

section/image-carousel.liquid を作成したら、Swiper規定のHTMLをコピペ。
その下にschemaでセクションの設定を入れる。
名前だけ決まってればいいのでとりあえずは日本語で直書きしておく。

<div class="image-carousel swiper">
  <div class="image-carousel__wrapper swiper-wrapper">
    <div class="image-carousel__slide swiper-slide">Slide 1</div>
    <div class="image-carousel__slide swiper-slide">Slide 2</div>
    <div class="image-carousel__slide swiper-slide">Slide 3</div>
  </div>
  <div class="image-carousel__pagination swiper-pagination"></div>

  <div class="image-carousel__btn image-carousel__btn--prev swiper-button-prev"></div>
  <div class="image-carousel__btn image-carousel__btn--next swiper-button-next"></div>
</div>

{% schema %}
{
  "name": "画像のカルーセル",
  "settings": [],
  "blocks": [],
  "presets": []
}
{% endschema %}

schemaで設定できる内容はドキュメント参照で。

これでセクションとして機能する状態になっている。

ホームに表示したいので、テンプレートの設定を変更する。
templates/index.json を開いて、先頭に作成したカルーセルのセクションを規定の形式で追加する。

"一意なID": {
   "type": "セクションのファイル名"
}
{
  "sections": {
    "image_carousel": {
      "type": "image-carousel"
    },
    "image_banner": {
.....

開発ストアにpush

※テーマが既にpush済みならこの手順は必要ない

CLIで shopify theme push すると、コンソールにプレビューとオンラインストアエディタのURLが表示されるので、アクセスする。

設定に追加したセクションが追加されていたらOK。
shopify theme serve しておく。

ブロックの設定

カルーセルの中身は自由に追加できるようにしたい。そこでブロックの出番である。
これはセクションのschemablocksに設定を追加するだけでできるのだが、
最初のうちは欲しい機能を持っている他のセクションからコピペする方がミスしにくい。

欲しい設定を section/multicolumn.liquid が持っているので開いて、必要な部分をコピペする。
labelとかは翻訳用にこのような記述になっているのだが、とりあえずそのままでいい。

typeslideにすること。

{% schema %}
{
  "name": "画像のカルーセル",
  "class": "section",
  "settings": [
  ],
  "blocks": [
    {
      "type": "slide",
      "name": "t:sections.multicolumn.blocks.column.name",
      "settings": [
        {
          "type": "image_picker",
          "id": "image",
          "label": "t:sections.multicolumn.blocks.column.settings.image.label"
        },
        {
          "type": "text",
          "id": "title",
          "default": "Slide",
          "label": "t:sections.multicolumn.blocks.column.settings.title.label"
        },
        {
          "type": "url",
          "id": "link",
          "label": "t:sections.multicolumn.blocks.column.settings.link.label"
        }
      ]
    }
  ],
  "presets": []
}
{% endschema %}

編集画面をリロードして「列を追加」が表示されていたらOK。

適当に設定をしておく。

ブロックコンテンツの表示

liquidでセクションのHTMLを変更していく。

セクションにユニークなIDをつける

<div id="swiper-{{ section.id }}" class="image-carousel swiper">

ブロックをforループで処理する

{%- for block in section.blocks -%}
    <div class="image-carousel__slide swiper-slide" {{ block.shopify_attributes }}>Slide 1</div>
{%- endfor -%}

ブロックの画像を表示する

<div class="image-carousel__slide swiper-slide">
{%- if block.settings.image -%}
  <img
        src="{{ block.settings.image | image_url: width: 1500 }}"
        loading="lazy"
        alt="{{ block.settings.image.alt | escape }}"
        width="{{ block.settings.image.width }}"
        height="{{ block.settings.image.width | divided_by: block.settings.image.aspect_ratio }}"
        class="image-carousel__slide__img"
      >
{%- endif -%}
</div>

非推奨のimg_urlimage_urlはフィルタの書き方がだいぶ違うので注意。

srcsetなどの書き方は image-banenr.liquid あたりを参考にすると良い。

リンクをつける

{%- if block.settings.link != blank -%}
<a href="{{ block.settings.link }}" title="{{ block.settings.title }}">
{%- endif -%}

{%- if block.settings.link != blank -%}
</a>
{%- endif -%}

セクション用CSSの追加

assets/image-carousel.css を作成。

/* Container */
.image-carousel {
  width: 100%;
}

/* Image */
.image-carousel__slide__img {
  width: 100%;
  height: auto;
  display: block;
}

sections/image-carousel.liquid にCSSファイルのリンクを追加する。

{{ 'section-image-carousel.css' | asset_url | stylesheet_tag }}

SwiperのCSSトJavaScriptファイルはCDNリンクでもいいんだけど警告が出るので、圧縮ファイルをダウンロードしてaseetに追加したものをリンクする。

{{ 'swiper-bundle.min.css' | asset_url | stylesheet_tag }}

<script src="{{ 'swiper-bundle.min.js' | asset_url }}" defer></script>

scriptタグでdeferを使ったので、Swiperの呼び出しはDOMContentLoadedイベントで行う。

<script>
  document.addEventListener('DOMContentLoaded', () => {
    new Swiper('#swiper-{{ section.id }}', {
      loop: true,
      pagination: {
        el: '.swiper-pagination',
      },
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    });
  });
</script>

ここまでやると、カルーセルが動くようになる。

あとはスタイルの変更なんかをセクション用CSSでやるだけである。

セクション設定の追加

セクションには個別に設定項目を追加することができる。
各セクションごとに設定を持たせられるので、使いこなせればめちゃくちゃ便利な機能だ。

カルーセルの矢印の表示/非表示をチェックボックスで切り替える、という設定を例にする。

schemaのsettingsブロックに使いたい設定を追加する。
タイプはドキュメントに一覧がある。

  "settings": [
    {
      "type": "checkbox",
      "id": "swiper_navigation_display",
      "default": true,
      "label": "ナビゲーションの矢印を表示する"
    }
  ],

これだけで管理画面には設定項目が表示される。

section.settings に設定が保存されている。
shcemaでつけたIDで値を呼び出すことができる。

{%- if section.settings.swiper_navigation_display == true -%}
  <div class="image-carousel__btn image-carousel__btn--prev swiper-button-prev" aria-label="Prev">
  </div>
  <div class="image-carousel__btn image-carousel__btn--next swiper-button-next" aria-label="Next">
  </div>
{%- endif -%}

Dawnのbase.cssで :empty 擬似要素をdisplay:noneしてあるので、改行を追加している。

テーマエディタとの連動

ナビゲーションの矢印を表示するチェックボックスをON/OFFすると、カルーセルの機能が失われることに気づくと思う。

これは、セクションの編集を行った時にページ全体をリロードしてるっぽく見えるが、実際には操作されたセクションだけ再レンダリングが行われているために、DOMContentLoadedイベントのコールバックが実行されないためである。

解決方法はドキュメントに書いてあるとおり、Shopifyのテーマエディタが発行するカスタムイベントをトリガーにしてJavaScriptを実行するように修正する。

document.addEventListener('DOMContentLoaded', () => {
    const slides = document.querySelectorAll(`#swiper-{{ section.id }} .image-carousel__slide`)
        
    if (!slides.length) return;

    const options = {
      slidesPerView: "auto",
      centeredSlides: true,
      loop: true,
      spaceBetween: 24,
      pagination: {
        el: '.swiper-pagination',
      },
    {%- if section.settings.swiper_navigation_display == true -%}
      navigation: {
        nextEl: '.swiper-button-next',
        prevEl: '.swiper-button-prev',
      },
    {%- endif -%}
    }

    let swiper = new Swiper('#swiper-{{ section.id }}', options);

    {% if request.design_mode %}
    // デザインモード時に実行
      document.addEventListener('shopify:section:unload', (e) => {
        if (swiper && e.detail.sectionId === '{{ section.id }}') {
          console.log('shopify:section:unload')
          swiper.destroy()
        }
      })
      document.addEventListener('shopify:section:load', (e) => {
        if (e.detail.sectionId === '{{ section.id }}'){
          console.log('shopify:section:load')
          swiper = new Swiper('#swiper-{{ section.id }}', options);
        }
      })
    {% endif %}
  });

ブロックの操作

設定済みのブロックを操作したり新しいブロックを追加した時に、カルーセルをそのブロックまで動かすには?

data属性の data-shopify-editor-block がブロックIDの情報を持っているのでparseして比較すればいいんだと思う。

document.addEventListener('shopify:block:select', (e) => {
        if (e.detail.sectionId !== '{{ section.id }}') return;
        const slides = document.querySelectorAll(`#swiper-{{ section.id }} .image-carousel__slide`)
        
        if (!slides)  return;

        const index = Array.from(slides).findIndex((el) => {
          const info = el.getAttribute('data-shopify-editor-block')
          if (!info) return 
          const data = JSON.parse(info)
          return (data.id === e.detail.blockId) 
        })

        if (index >= 0 && swiper) {
          swiper.slideTo(index)
        }
      
      })

選択に合わせてスライドが動けばおk。

翻訳の追加と利用

locales/ja.schema.json に追加したセクションの設定を追加する。
locales/en.default.schema.json にも同じ設定の英語版を追加しておく。

"image_carousel": {
      "name": "画像のカルーセル",
      "settings": {
        "swiper_navigation_display": {
          "label": "ナビゲーションの矢印を表示する"
        }
      },
      "blocks": {
        "slide": {
          "name": "スライド",
          "settings": {
            "image": {
              "label": "画像"
            },
            "title": {
              "label": "見出し"
            },
            "link": {
              "label": "リンク"
            }
          }
        }
      },
      "presets": {
        "name": "画像のカルーセル"
      }
    }

これにより、sections/image-carousel.liquid 内の schema で翻訳が利用できるようになる。

{
  "name": "t:sections.image_carousel.name",
  "tag": "section",
  "class": "section",
....

テーマのHTMLで利用する翻訳は locales/ja.jsonsections内に追加する。
locales/en.default.json にも英語版を追加する。

    "image_carousel": {
      "pagination": "スライドページナビゲーション"
    }
 <div class="image-carousel__pagination swiper-pagination"
    aria-label="{{ 'sections.image_carousel.pagination' | t }}"
></div>

参考

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください