はじめに
アウトドア用品のセレクトショップ hinataストア の運用チームで開発をやっている氏家です。 hinataストアはShopifyテーマによって構築されており、Liquidのコードを変更して様々な機能を実装しています。
最近、外部から出力してきたJSONファイルをLiquidで扱いたい場面がありました。 なるべくLiquidで完結させたかったのでLiquidでのJSONの扱い方について調べていたのですが、 少し苦戦したので備忘録も兼ねてブログを書いています。
前提: Liquid ではJSONを扱えない
.json
ファイルをLiquidでインポートしてパースすることができればいいのですが、実際には難しいです。
以下のようにJSON形式の単なる文字列を .liquid ファイルで定義してみても、
snippets/hoge.liquid
{ "hoge": "hoge" }
theme.liquid
<script> {%- capture hoge -%} {% render "hoge" %} {%- endcapture -%} console.log(`1. {{ hoge }}`); console.log(`2. {{ hoge.value }}`); console.log(`3. {{ hoge.hoge }}`); </script>
出力
1. { "hoge": "hoge" } 2. 3.
オブジェクト的な使い方はできません。 JSON形式の文字列を直接渡した場合も同様です。
theme.liquid
<script> {% assign hoge = '{ "hoge": "hoge" }' %} console.log(`1. {{ hoge }}`); console.log(`2. {{ hoge.value }}`); console.log(`3. {{ hoge.hoge }}`); </script>
出力
1. { "hoge": "hoge" } 2. 3.
split
などのstring filterを使ってパースする方法も考えられますが、実装がかなり重たくなってしまいそうです。
1. メタオブジェクトを使う
Shopifyに追加された「メタオブジェクト」を使用し、JSON形式のフィールドを定義して設定することができます(まだ一部のストアではメタオブジェクトが利用できないかもしれません)。
メタオブジェクトとして設定されたJSONは、Liquid上では metaObject
という型で評価されます。
そのため、cart
や product
といったオブジェクトと同様にメンバを参照することができます。
theme.liquid
<script> {% assign hoge = shop.metaobjects.test_object.test_object.hoge.value %} console.log(`1. {{ hoge }}`); console.log(`2. {{ hoge.hoge }}`); </script>
出力
1. {"hoge"=>"hoge"} 2. hoge
メタオブジェクトの詳しい解説は以下のブログが参考になります。
2. メタフィールドを使う
メタオブジェクト同様、メタフィールドでもJSONを扱うことが出来ます。
JSONをどのリソースのメタフィールドに設定すれば分からないときは、API経由(もしくはメタフィールド更新用のShopifyアプリ)で shop.metafields
に保存する方法があります。
今回はShopify GraphQL Admin API でメタフィールドを設定します。
APIを叩く環境は何でもいいですが、Shopify GraphiQL App
というShopifyアプリを入れておくと簡単に叩けて便利です。
Shopify GraphiQL App — Install
1, ShopifyストアのストアIDを取得
リクエスト
{ shop { id } }
レスポンス
{ "data": { "shop": { "id": "gid://shopify/Shop/xxxxxxxxxxx" } }, "extensions": { "cost": { "requestedQueryCost": 1, "actualQueryCost": 1, "throttleStatus": { "maximumAvailable": 10000, "currentlyAvailable": 9999, "restoreRate": 500 } } } }
2, 1で取得したIDを元に metafieldsSet
Mutation を叩く
リクエスト
mutation metafieldsSet { metafieldsSet(metafields: [ { namespace: "custom", key: "test", ownerId: "gid://shopify/Shop/xxxxxxxxxxx", type: "json", value: "{\"hoge\": \"hoge\"}" } ]) { metafields { value ownerType key namespace type id } userErrors { field message } } }
valueに渡すJSONは↓のサービスなどで文字列をエスケープする必要があります。
Free Online JSON Escape / Unescape Tool - FreeFormatter.com
レスポンス
{ "data": { "metafieldsSet": { "metafields": [ { "value": "{\"hoge\":\"hoge\"}", "ownerType": "SHOP", "key": "test", "namespace": "custom", "type": "json", "id": "gid://shopify/Metafield/23866410696888" } ], "userErrors": [] } }, "extensions": { "cost": { "requestedQueryCost": 10, "actualQueryCost": 10, "throttleStatus": { "maximumAvailable": 10000, "currentlyAvailable": 9990, "restoreRate": 500 } } } }
ownerType
が SHOP
になっていることから、 shop.metafields
に設定されていることがわかります。
3, Liquidから呼び出す
theme.liquid
<script> {% assign hoge = shop.metafields.custom.test.value %} console.log(`1. {{ hoge }}`); console.log(`2. {{ hoge.hoge }}`); </script>
出力
1. {"hoge"=>"hoge"} 2. hoge
JSONの値が配列だった場合は通常通り for in
などでループ処理すればパースできます。
まとめ
LiquidでJSONをオブジェクトとして扱う方法を紹介しました。 JSON形式のコンテンツを表示させたいときなどに参考にしてみてください。
メタオブジェクトの登場により、assets
配下に静的ファイルを置いたり、セクションを作成してノーコードで値を設定できるようにしなくても、
簡単にコンテンツを管理できるようになった気がします。
他にも様々な使い方ができそうなので、画期的なアイデアを見つけたらまたブログにしたいと思います。
vivit では新しいことにチャレンジし、ともにプロダクトを成長させていけるエンジニアを募集中です!
少しでも興味を持って頂いた方は、是非カジュアル面談にお越しください。