Shopify FlowのLiquid変数
このページはMar 28, 2024に印刷されています。最新のバージョンについては、https://help.shopify.com/ja/manual/shopify-flow/reference/variablesをご覧ください。
変数は、ワークフローの実行時に値に置き換えられるプレースホルダーです。これらの変数には、ワークフローに関係するお客様、注文、商品の属性が付与されています。たとえば、注文番号、注文価格、顧客名などの変数があります。条件 で変数を使用し、ワークフローのロジックを管理することや、1つのアクション でデータを出力することができます。
Liquidについて Liquidとは、さまざまなアクションで変数を使用したり、Flowでコードを記述したりするためのテンプレート言語です。Flowでは、オープンソースライブラリー に最も近いタイプのLiquidを使用します。Shopifyテーマでは、別のタイプのLiquid を使用します。このタイプのLiquidはテーマ固有のもので、Flowでサポートされているものよりも多くの絞り込みとタグ、および変数を使用するためのさまざまな構文が含まれています。
Liquid変数 [変数を追加する] のリンクを含むテキストフィールドにLiquid変数を追加することができます。関連するフィールドの下にある [変数を追加する] のリンクをクリックして、リストから変数を選択します。
[変数を追加] リストの変数は、トリガーなど現在のステップより前のステップで返された変数だけが表示されるように絞り込まれます。たとえば、[注文が作成されたとき] トリガーによって、注文およびショップのリソースが表示されるので、注文またはショップの設定に関連した変数を使用し、GraphQL Admin API でアクセスできるようにします。リストから変数を選択すると、変数が適切にフォーマットされてテキストボックスに追加されます。
また、テキストブロックに直接Liquidを書き込むことができます。たとえば、変数{{ order.name }}
を使用し、管理画面に表示される注文文字列 (注文-123など) を表示することができます。
Flowでは、Liquidで使用したデータの回収にGraphQL Admin APIを使用するため、変数の構文に「キャメルケース」を使用します。たとえば、商品が作成された日付を取得するには、{{ product.createdAt }}
と入力します。ShopifyテーマでLiquid構文を使用している場合は、{{ product.created_at }}
と入力します。
条件Liquidタグと繰り返しLiquidタグ 以下の手順を実行するために、Liquidタグを使用することもできます。
条件文を書く (注文合計が100ドルを超えているかの判断など)
さまざまなオブジェクトを繰り返す (注文の各項目に関するデータ出力など)
Liquidタグ を使用して後述の条件文を記述することや、オブジェクトを繰り返すことができます。
たとえば、以下のLiquidでは注文合計が100ドルを超える注文番号が表示されます。
{% if order . totalPriceSet . shopMoney . amount > 100 %}
Order number: {{ order . name }}
{% endif %}
forループ を使用して、注文の項目など、さまざまなオブジェクトを繰り返すことができます。たとえば、以下のLiquidでは注文の各項目名が表示されます。
{% for li in order . lineItems %}
{{ li . title }}
{% endfor %}
Flowでは、以下のLiquid条件 (または制御フロー) タグをサポートしています。
Flowでは、以下のLiquidの繰り返しタグもサポートしています。
フィルター 絞り込みを使用してLiquidのデータを変更できます。Flowは、オープンソースLiquid の絞り込みすべてに対応しています。
たとえば、以下のLiquidでは特定の注文名プリフィックスを除外しそれ以外を出力します。 {{ order.name | remove: "Order-" }}
Liquidの標準絞り込みに加えて、Flowでは、予定時刻 トリガーやデータ取得 機能に対応するため、他の日付と関連した日付を取得する日付の絞り込み機能を提供しています。date_minus
、date_plus
。
今後の日付を1日戻す:{{ "now" | date_plus: "1 day" }}
過去の日付を1日戻す:{{ "now" | date_minus: "1 day" }}
これらの絞り込みでは、期間としてsecond
、minute
、day
、week
、month
、year
に対応しています。単数形 (second
など) および複数形 (seconds
など) の両方に対応しています。この形式に、正数 (秒数) を入力することもできます。例:{{ "now" | date_minus: 3600 }}
ISO8601の期間文字列を入力することもできます。P1Y2D
は1年と2日を意味します。{{ "now" | date_minus: "P1Y2D" }}
絞り込みでLiquid変数を使用する際の考慮事項
Flowでは、一部の絞り込みで利用可能なドット表記に対応していません。たとえば、フローは{{ order.lineItems | size }}
に対応していますが、{{ order.lineItems.size }}
には対応していません。
Flowでは、メタフィールドのドット表記に対応していません。たとえば、{{ order.metafields.custom.hold_note }}
を使用することはできません。例に示されているメタフィールドをループ処理する必要があります。
Flowでは、インデックスを使用してリスト内のアイテムにアクセスできません。たとえば、{{ order.lineItems[0].title }}
を使用することはできません。代わりに、例に示されているとおり項目をループ処理する必要があります。
ストアの例 Liquid変数の使用方法をよりよく理解するために、以下の用例を考慮してください。
メタフィールド値を出力する メールで注文のメタフィールドの値を出力するとします。メタフィールドは文字列で、custom
のネームスペースとhold_note
のキーが含まれます。このメタフィールドの値はPlease wait to deliver this order until April 1.
です。[注文が作成されたとき] トリガーを使用してワークフローを作成し、[内部メールを送信する] アクションを使用します。[内部メールを送信する] アクションの [メッセージ] セクションに、以下の変数を使用できます。
注文のメタフィールドを出力する変数の使用例
入力
出力
{% assign hold_note = order.metafields | where: "namespace", "custom" | where: "key", "hold_note" | first %} 注文には{{ hold_note.value }}の保留メモが付きます。
注文には、「この注文の配達は4月1日までお待ちください」という保留メモが付きます。
タグリストをメタフィールドに変換する タグセットを単一行テキストフィールドのリスト であるメタフィールドに変換したいとします。[商品がストアに追加されたとき] トリガーを使用してワークフローを作成し、[商品のメタフィールドを更新する] アクションを使用します。[商品のメタフィールドを更新する] アクションの [値] セクションに、以下のLiquidコードを追加します。この例では、商品が作成された際に1度だけ値を設定する必要がある場合、および商品にcolor:red
とcolor:orange
の関連タグがある場合を想定しています。
単一行テキストフィールドのリストを設定するLiquidの例
入力
出力
{% capture mf_value %} {%- for tags_item in product.tags -%} {%- if tags_item contains "color:" -%} "{{- tags_item | remove_first: "color:" | strip -}}" {%- endif -%} {%- endfor -%} {% endcapture -%} [{{mf_value | remove_last: ","}}]
["赤"、"オレンジ"]
注文に関する動的なメールメッセージを作成する お客様が500ドルを超える注文をしたときに従業員にメールを送信するワークフローを作成するとします。[注文が作成されたとき] トリガーを使用するワークフローを作成し、注文合計が500ドルより多い場合にtrueとする条件を設定して、[内部メールを送信する] アクションを使用します。[内部メールを送信する] アクションの [メッセージ] セクションに、以下の変数を使用できます。
お客様の詳細情報を知らせるために使用する変数の例。
入力
出力
{{ order.customer.firstName }} {{ order.customer.lastName }}({{ order.customer.email }})に、 {{ order.totalPriceSet.shopMoney.amount }}ドルの注文に関するサンキュー通知を送信してください。
Jeanne Dupont (jeanne@example.com) に763.42ドルの注文に関するサンキュー通知を送ってください。
在庫が少なくなっている商品に関する動的なメールメッセージを作成する あなたは、商品在庫が少なくなり在庫を増やすための入荷が必要になったタイミングでスタッフメンバーに通知をする必要があると考えます。[在庫数量が変更されたとき] トリガーで起動するワークフローを作成し、[数量が変わる前の商品バリエーションの在庫数量] が10以下の場合にtrueとなる条件を設定します。[内部メールを送信する] アクションの [メッセージ] セクションに、以下の変数を使用できます。
アイテムの詳細情報を知らせるために使用する変数の例。
入力
出力
{{ product.title }}を再入荷してください。owner@store.comにメールを送信して先方が注文書を受け取ったかどうかを確認してください。
ハイウエストレギンス - 黒を再入荷してください。owner@example.comにメールを送信して先方が注文書を受け取ったかどうかを確認してください。
不正注文についてスタッフに通知する動的メールメッセージを作成する あなたは、リスクレベルの高い注文をキャンセルする場合に、スタッフの手動による注文のキャンセルを希望します。[注文が作成されたとき] トリガーで起動するワークフローを作成し、注文のリスクレベルが「高」と一致する場合にtrueとなる条件を設定します。[内部メールを送信する] アクションの [メッセージ] セクションに、以下の変数を使用できます。
不正注文に関する情報を知らせるために使用する変数の例。
入力
出力
Shopifyストアが、不正注文のリスクが高い注文を受け取りました。この注文内容が製造工程に送られる前に、以下の注文を即座にキャンセルしたいと思います。 {{ order.name }} {{ order.billingAddress.lastName }},{{ order.billingAddress.firstName }} {{ order.email }} その後の注文状況を確認してください。よろしくお願いします。
Shopifyストアが、不正注文のリスクが高い注文を受け取りました。この注文内容が製造工程に送られる前に、以下の注文を即座にキャンセルしたいと思います。 #1001 Dupont, Jeanne jeanne@example.com その後の注文状況を確認してください。よろしくお願いします。
forループを使用して注文の項目を出力する 注文を受け付けた際には、注文の商品情報を含むメッセージを送信すると便利です。それを行うのに、for loop
を使用すると、コードブロックを繰り返し実行してくれます。変数に対応しているテキストフィールドは、for loopsおよびforloopオブジェクト にも対応しています。
たとえば、注文内のすべてのSKUと数量のリストを返すワークフローを作成するとします。[内部メールを送信する] アクションの [メッセージ] セクションに、以下の変数を使用できます。
for loopを使用して注文情報を知らせる例。
入力
出力
注文サマリー: {% for a in order.lineItems %} SKU: {{a.sku}} ({{a.quantity}}), {% endfor %}
注文サマリー: 8987097979 (50) 8877778887 (3) 888998898B (1)
forループを使用して注文の項目を詳細情報と共に出力する メールに商品名、SKU、アイテムごとの価格、お客様の配送情報などの詳細情報を追加することにしたとします。[内部メールを送信する] アクションの [メッセージ] セクションに、以下の変数を使用できます。
for loopを使用して、より広範囲の注文情報を知らせる例。
入力
出力
注文サマリー: {% for a in order.lineItems %} 商品: {{a.title}} SKU: {{a.sku}} 価格 (単価): {{a.originalUnitPriceSet.shopMoney.amount}}ドル 数量: {{a.quantity}} {% endfor %}
注文サマリー: 商品: ハイウエストレギンス - 黒 SKU: 8987097979 価格 (単価): $8.49 数量: 5 商品: アスレチックソックス - 青 SKU: 888998898B 価格 (単価): 5.61ドル 数量: 2
forループとif文を組み合わせて項目を出力する 特定の販売元から仕入れて販売したアイテムを追跡する必要があるとします。[内部メールを送信する] アクションの [メッセージ] セクションで、以下の変数を使用してfor loop
にif
文を加えることができます。
特定の販売元の注文情報を知らせるためにif文とfor loopを使用する例。
入力
出力
販売済みのAcme商品: {% for x in order.lineItems %} {% if x.vendor == 'acme-vendor' %} 商品名: {{x.title}} SKU: {{x.sku}} {% endif %} {% endfor %}
販売済みのAcme商品: 商品名: ハイウエストレギンス - 黒 SKU: 8987097979
Shopify Flowの複雑なデータオブジェクト Flowを使用すると、GraphQL Admin API 内のほとんどすべてのデータにアクセスできます。これには、リストやオブジェクトなどの複雑なデータオブジェクトが含まれます。ただし、これらのオブジェクトで行えることにはいくつかの制限があります。このセクションでは、それらの制限について概説し、その対応方法に関する例を挙げます。
注意
Liquidでは、{{ order.lineItems }}
と入力するなどして、リストまたはオブジェクトを直接呼び出すことでリスト/配列またはオブジェクトを出力することはできません。この制限が設定されている理由は、GraphQLが大量のデータを返すとワークフローにエラーが発生する可能性があるからです。さらに、新しいフィールドを導入すると、一部のワークフローが壊れる可能性があります。
リストとオブジェクトを直接呼び出す代わりに、リストをループ処理して、必要なフィールドのみを含める必要があります。
たとえば、{{ order.lineItems }}
を直接呼び出す代わりに、以下の形式で特定のフィールドを呼び出します。これには、配列またはオブジェクトを直接呼び出すことによって加えられるすべてのフィールドが含まれています。必要なフィールドをコピーして貼り付けてください。
{% for li in order . lineItems %}
{% comment %} li.contract - omitted {% endcomment %}
{% for ca in li . customAttributes %}
{{ ca . key }}
{{ ca . value }}
{% endfor %}
{% for da in li . discountAllocations %}
{{ da . allocatedAmountSet . presentmentMoney . amount }}
{{ da . allocatedAmountSet . presentmentMoney . currencyCode }}
{{ da . allocatedAmountSet . shopMoney . amount }}
{{ da . allocatedAmountSet . shopMoney . currencyCode }}
{% endfor %}
{{ li . discountedTotalSet . presentmentMoney . amount }}
{{ li . discountedTotalSet . presentmentMoney . currencyCode }}
{{ li . discountedTotalSet . shopMoney . amount }}
{{ li . discountedTotalSet . shopMoney . currencyCode }}
{{ li . discountedUnitPriceSet . presentmentMoney . amount }}
{{ li . discountedUnitPriceSet . presentmentMoney . currencyCode }}
{{ li . discountedUnitPriceSet . shopMoney . amount }}
{{ li . discountedUnitPriceSet . shopMoney . currencyCode }}
{% comment %} li.duties - omitted {% endcomment %}
{{ li . fulfillableQuantity }}
{{ li . fulfillmentService . callbackUrl }}
{{ li . fulfillmentService . fulfillmentOrdersOptIn }}
{{ li . fulfillmentService . handle }}
{{ li . fulfillmentService . id }}
{{ li . fulfillmentService . inventoryManagement }}
{% comment %} rest of location omitted {% endcomment %}
{{ li . fulfillmentService . location . name }}
{{ li . fulfillmentService . productBased }}
{{ li . fulfillmentService . serviceName }}
{% for sm in li . fulfillmentService . shippingMethods %}
{{ sm . code }}
{{ sm . label }}
{% endfor %}
{{ li . fulfillmentService . type }}
{{ li . fulfillmentStatus }}
{{ li . id }}
{{ li . image . altText }}
{{ li . image . height }}
{{ li . image . id }}
{% comment %} li.image.metafield omitted {% endcomment %}
{% comment %} li.image.privateMetafield omitted {% endcomment %}
{{ li . image . width }}
{{ li . merchantEditable }}
{{ li . name }}
{{ li . nonFulfillableQuantity }}
{{ li . originalTotalSet . presentmentMoney . amount }}
{{ li . originalTotalSet . presentmentMoney . currencyCode }}
{{ li . originalTotalSet . shopMoney . amount }}
{{ li . originalTotalSet . shopMoney . currencyCode }}
{{ li . originalUnitPriceSet . presentmentMoney . amount }}
{{ li . originalUnitPriceSet . presentmentMoney . currencyCode }}
{{ li . originalUnitPriceSet . shopMoney . amount }}
{{ li . originalUnitPriceSet . shopMoney . currencyCode }}
{% comment %} rest of product omitted {% endcomment %}
{{ li . product . title }}
{{ li . quantity }}
{{ li . refundableQuantity }}
{{ li . requiresShipping }}
{{ li . restockable }}
{{ li . sellingPlan . name }}
{{ li . sku }}
{% for tl in li . taxLines %}
{{ tl . priceSet . presentmentMoney . amount | json }}
{{ tl . priceSet . presentmentMoney . currencyCode | json }}
{{ tl . priceSet . shopMoney . amount | json }}
{{ tl . priceSet . shopMoney . currencyCode | json }}
{{ tl . rate | json }}
{{ tl . ratePercentage | json }}
{{ tl . title | json }}
{% endfor %}
{{ li . taxable }}
{{ li . title }}
{{ li . totalDiscountSet . presentmentMoney . amount }}
{{ li . totalDiscountSet . presentmentMoney . currencyCode }}
{{ li . totalDiscountSet . shopMoney . amount }}
{{ li . totalDiscountSet . shopMoney . currencyCode }}
{{ li . unfulfilledDiscountedTotalSet . presentmentMoney . amount }}
{{ li . unfulfilledDiscountedTotalSet . presentmentMoney . currencyCode }}
{{ li . unfulfilledDiscountedTotalSet . shopMoney . amount }}
{{ li . unfulfilledDiscountedTotalSet . shopMoney . currencyCode }}
{{ li . unfulfilledOriginalTotalSet . presentmentMoney . amount }}
{{ li . unfulfilledOriginalTotalSet . presentmentMoney . currencyCode }}
{{ li . unfulfilledOriginalTotalSet . shopMoney . amount }}
{{ li . unfulfilledOriginalTotalSet . shopMoney . currencyCode }}
{{ li . unfulfilledQuantity }}
{% comment %} rest of variant omitted {% endcomment %}
{{ li . variant . title }}
{{ li . variantTitle }}
{{ li . vendor }}
{% endfor %}
{
"lineItems": [
{% for li in order . lineItems %}
{% if forloop.first != true %} ,{% endif %}
{
"contract": {
{% comment %} rest of contract omitted {% endcomment %}
"id": {{ li . contract . id | json }}
},
"customAttributes": [
{% for ca in li . customAttributes %}
{% if forloop.first != true %} ,{% endif %}
{
"key":{{ ca . key | json }} ,
"value":{{ ca . value | json }}
}
{% endfor %}
],
"discountAllocations": [
{% for da in li . discountAllocations %}
{% if forloop.first != true %} ,{% endif %}
"allocatedAmountSet": {
"presentmentMoney" : {
"amount": {{ da . allocatedAmountSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ da . allocatedAmountSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ da . allocatedAmountSet . shopMoney . amount | json }} ,
"currencyCode": {{ da . allocatedAmountSet . shopMoney . currencyCode | json }}
}
}
{% endfor %}
],
"discountedTotalSet": {
"presentmentMoney" : {
"amount": {{ li . discountedTotalSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ li . discountedTotalSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ li . discountedTotalSet . shopMoney . amount | json }} ,
"currencyCode": {{ li . discountedTotalSet . shopMoney . currencyCode | json }}
}
},
"discountedUnitPriceSet": {
"presentmentMoney" : {
"amount": {{ li . discountedUnitPriceSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ li . discountedUnitPriceSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ li . discountedUnitPriceSet . shopMoney . amount | json }} ,
"currencyCode": {{ li . discountedUnitPriceSet . shopMoney . currencyCode | json }}
}
},
"duties": [
{% for duty li . duties %}
{% if forloop.first != true %} ,{% endif %}
{
{% comment %} rest of duties omitted {% endcomment %}
"id": {{ duty . id | json }}
}
{% endfor %}
],
"fulfillableQuantity": {{ li . fulfillableQuantity | json }} ,
"fulfillmentService": {
"callbackUrl":{{ li . fulfillmentService . callbackUrl | json }} ,
"fulfillmentOrdersOptIn": {{ li . fulfillmentService . fulfillmentOrdersOptIn | json }} ,
"handle": {{ li . fulfillmentService . handle | json }} ,
"id": {{ li . fulfillmentService . id | json }} ,
"inventoryManagement": {{ li . fulfillmentService . inventoryManagement | json }} ,
{% comment %} fulfillmentService.inventoryManagement - omitted {% endcomment %}
"productBased": {{ li . fulfillmentService . productBased | json }} ,
"serviceName": {{ li . fulfillmentService . serviceName | json }} ,
"shippingMethods": [
{% for sm in li . fulfillmentService . shippingMethods %}
{% if forloop.first != true %} ,{% endif %}
{
"code": {{ sm . code | json }} ,
"label": {{ sm . label | json }}
}
{% endfor %}
],
"type": {{ li . fulfillmentService . type | json }}
},
"fulfillmentStatus": {{ li . fulfillmentStatus | json }} ,
"id": {{ li . id | json }} ,
"image": {
"altText": {{ li . image . altText | json }} ,
"height": {{ li . image . height | json }} ,
"id": {{ li . image . id | json }} ,
{% comment %} li.image.metafield omitted {% endcomment %}
{% comment %} li.image.privateMetafield omitted {% endcomment %}
"width":{{ li . image . width | json }}
},
"merchantEditable": {{ li . merchantEditable | json }} ,
"name": {{ li . name | json }} ,
"nonFulfillableQuantity": {{ li . nonFulfillableQuantity | json }} ,
"originalTotalSet": {
"presentmentMoney" : {
"amount": {{ li . originalTotalSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ li . originalTotalSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ li . originalTotalSet . shopMoney . amount | json }} ,
"currencyCode": {{ li . originalTotalSet . shopMoney . currencyCode | json }}
}
},
"originalUnitPriceSet": {
"presentmentMoney" : {
"amount": {{ li . originalUnitPriceSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ li . originalUnitPriceSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ li . originalUnitPriceSet . shopMoney . amount | json }} ,
"currencyCode": {{ li . originalUnitPriceSet . shopMoney . currencyCode | json }}
}
},
"product": {
{% comment %} rest of Product omitted {% endcomment %}
"title": {{ li . product . title | json }}
},
"quantity": {{ li . quantity | json }} ,
"refundableQuantity": {{ li . refundableQuantity | json }} ,
"requiresShipping": {{ li . requiresShipping | json }} ,
"restockable": {{ li . restockable | json }} ,
"sellingPlan": {
"name": {{ li . sellingPlan . name | json }}
},
"sku": {{ li . sku | json }} ,
"taxLines": [
{% for tl in li . taxLines %}
{% if forloop.first != true %} ,{% endif %}
{
"priceSet": {
"presentmentMoney" : {
"amount": {{ tl . priceSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ tl . priceSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ tl . priceSet . shopMoney . amount | json }} ,
"currencyCode": {{ tl . priceSet . shopMoney . currencyCode | json }}
}
},
"rate": {{ tl . rate | json }} ,
"ratePercentage": {{ tl . ratePercentage | json }} ,
"title": {{ tl . title | json }}
}
{% endfor %}
],
"taxable":{{ li . taxable | json }} ,
"title":{{ li . title | json }} ,
"totalDiscountSet": {
"presentmentMoney" : {
"amount": {{ li . totalDiscountSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ li . totalDiscountSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ li . totalDiscountSet . shopMoney . amount | json }} ,
"currencyCode": {{ li . totalDiscountSet . shopMoney . currencyCode | json }}
}
},
"unfulfilledDiscountedTotalSet": {
"presentmentMoney" : {
"amount": {{ li . unfulfilledDiscountedTotalSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ li . unfulfilledDiscountedTotalSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ li . unfulfilledDiscountedTotalSet . shopMoney . amount | json }} ,
"currencyCode": {{ li . unfulfilledDiscountedTotalSet . shopMoney . currencyCode | json }}
}
},
"unfulfilledOriginalTotalSet": {
"presentmentMoney" : {
"amount": {{ li . unfulfilledOriginalTotalSet . presentmentMoney . amount | json }} ,
"currencyCode": {{ li . unfulfilledOriginalTotalSet . presentmentMoney . currencyCode | json }}
},
"shopMoney": {
"amount": {{ li . unfulfilledOriginalTotalSet . shopMoney . amount | json }} ,
"currencyCode": {{ li . unfulfilledOriginalTotalSet . shopMoney . currencyCode | json }}
}
},
"unfulfilledQuantity": {{ li . unfulfilledQuantity | json }} ,
"variant": {
{% comment %} rest of variant omitted {% endcomment %}
"title": {{ li . variant . title | json }}
},
"variantTitle": {{ li . variantTitle | json }} ,
"vendor": {{ li . vendor | json }}
}
{% endfor %}
]
}