Shopifyで商品コレクションをランダムソートする [WareHouseテーマ]

「Shopifyでコレクションをランダム出力したい」とご依頼いただいたのですが、かなり地獄のようなハマり方をしてしまったので、メモとして残しておきます。どなたか参考になりましたら幸いです。

ちなみにWareHouseテーマご利用のショップ様でしたので他のテーマでは試していませんが、テーマ独自の変数などは使用していないので恐らく問題ないだろうと思います。

Shopifyは配列のランダムソートに対応していない

長年開発者からの要望があるにも関わらず、Shopifyは配列のランダムソートには標準対応していません。

そこで手初めにAIにランダムソートをどう実現するか聞いてみたのですが、「randomフィルターを使えば一発解決です!」などと、存在しないフィルターを提示してきましたので彼と信頼関係を築くことはできませんでした。

考えられるコレクションのランダム化

1. 自分でWebComponentsを作成

今回はいろいろ制約があったので採用しなかったのですが、メンテナンス面を考えればこちらの方が良いように感じています。

Shopifyから渡される商品データ(COLLECTION.products | json)はオリジナルデータとしてそのまま保持しておき、表示部分は自分で作成してしまう方法です。

メリットは、表示に関する処理をすべてJavaScript(WebComponents)に任せることで役割が分担され、メンテナンス性や今後の拡張性が高くなること。

デメリットとしては、テーマ独自のコレクションフィルターを利用するページでは、それらに手動で対応させないといけなくなるのだろうな、、というところです。

2. liquid変数だけで商品を並び替え

実際に採用したのがこちらです。

手順としては、

  1. 商品がもつ一意の値(IDなど)だけの配列を作る(ID配列)
  2. ID配列をシャッフルしてランダムID配列を作成する
  3. ランダムID配列をループ処理。IDが一致する商品データがあれば、あとの処理に渡す

という流れです。コードを見ながらもう少しくわしく解説します。

商品コレクションのランダム表示(liquidファイル編集)

{%- assign original_products = YOUR_COLLECTION.products -%}
{%- assign limit = original_products.size -%}<!-- OR Your_Settings_Number -->

<!-- random_ids に一意のID+ , を追加していく(文字列)-->            
{%- assign random_ids = "" -%}
{%- for item in original_products -%}
  <!-- ふつうに重複が起こるのでユニークな配列にしてからチェックする-->
  {%- assign current = random_ids | split: "," | uniq -%}
  {%- if current.size >= limit -%}
    {%- break -%}
  {%- endif -%}

  {%- assign idx = "now" | date: "%N"| plus: 0 | modulo: limit -%}
  {%- assign chosen_item = original_products[idx] -%}
  <!-- vendorを使用していますが、一意の値ならなんでもOK。-->
  {%- assign random_ids = random_ids | append: chosen_item.vendor | append: "," -%}
{%- endfor -%}

<!-- 文字列を配列にする -->
{%- assign random_ids_array = random_ids | split: "," | uniq -%}
   
<!-- ランダムID配列をループ & IDに一致するProductをレンダリング-->
{%- for _id in random_ids_array -%}
  {%- assign product = original_products | find: "vendor", _id -%}
  {%- if product != nil -%}
    {%- render 'product-item', product: product -%}
  {%- endif -%}
{%- endfor -%}