Shopify Flow で Liquid変数を使用する
Liquid変数は Liquid で定義されるプレースホルダーであり、ワークフローの実行時に GraphQL Admin API の値に置き換えられます。変数は、注文番号、注文の価格、顧客名など、ワークフローに含まれるお客様、注文、商品の属性を記述できます。変数を条件内で使用して、ワークフローのロジックを制御したり、アクションのデータを出力したりできます。
このページの内容
Liquid を使用してワークフローに変数を追加する
「変数を追加する」リンクが含まれているテキストフィールドには、Liquid を使用して変数を追加できます。関連フィールドの下にある「変数を追加する」リンクをクリックし、リストから変数を選択します。

「変数を追加する」リストの変数は絞り込まれており、トリガーなど、現在のステップより前のステップによって返される変数のみを使用できます。たとえば、「注文が作成されたとき」トリガーでは、変数として挿入できる注文とストアのリソースが Admin API から提供されます。リストから変数を選択すると、その変数は適切にフォーマットされた Liquid としてテキストボックスに追加されます。
また、テキストフィールドに Liquid を直接記述することもできます。たとえば、変数 {{ order.name }} を使用して、order-123 のような Shopify 管理画面の注文文字列を表示できます。
Flowでは、Liquidに使用されるデータを Admin API を使用して取得するため、変数の構文にはキャメルケースが使用されます。キャメルケースの変数は、firstName や canMarkAsPaid のように、最初の単語は小文字で始まり、その後の単語は大文字で始まります。たとえば、商品が作成された日付にアクセスするには、{{ product.createdAt }} と入力します。キャメルケースを使用しない Shopify テーマで Liquid 構文を使用する場合は、{{ product.created_at }} と入力します。
条件および繰り返しの 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 条件 (または制御フロー) タグがサポートされています。
- if
- unless
- elsif/else
- case/when
- and/or (複数の条件)
Flow では、以下の Liquid 繰り返しタグもサポートされています。
変数へのフィルターの適用
Liquid でフィルターを使用して、変数のデータを変換できます。Flow では、すべてのオープンソースの Liquid フィルターがサポートされています。
たとえば、以下の Liquid は注文名からプレフィックスを削除し、残りの部分を出力します: {{ order.name | remove: "Order-" }}
フィルターで Liquid 変数を使用する場合の考慮事項
フィルターを使用して変数を変換する前に、以下の考慮事項を確認してください。
- Flow では、一部のフィルターで利用できるドット表記はサポートされていません。たとえば、Flow では
{{ order.lineItems | size }}はサポートされていますが、{{ order.lineItems.size }}はサポートされていません。 - Flow では、メタフィールドのドット表記はサポートされていません。たとえば、
{{ order.metafields.custom.hold_note }}は使用できません。代わりに、例で概説されているようにメタフィールドをループ処理する必要があります。 - Flow では、インデックスを使用してリスト内のアイテムにアクセスすることはサポートされていません。たとえば、
{{ order.lineItems[0].title }}は使用できません。代わりに、例で概説されているように項目をループ処理する必要があります。
日付フィルター
標準の 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 }}。この場合、3600 は 1 時間に相当します。 - ISO8601 期間文字列:
{{ "now" | date_minus: "P1Y2D" }}。この場合、P1Y2Dは 1 年と 2 日を意味します。
暗号化フィルター
Flow では、ハッシュ化したり、ハッシュベースのメッセージ認証コード (HMAC) を作成したりするための暗号化フィルターを提供しています。これらのフィルターは、固有の ID やチェックサムを作成する場合や、特定のハッシュ形式を必要とする外部サービスと連携する場合に役立ちます。
ハッシュ化フィルター
Shopify Flow は、以下の種類のハッシュ化フィルターに対応しています。
blake3- BLAKE3 ハッシュを作成します (一般的な使用におすすめです)。sha256- SHA-256 ハッシュを作成します。sha1- SHA-1 ハッシュを作成します。md5- MD5 ハッシュを作成します。
一般的なハッシュ化の目的や新しい実装には、blake3 を使用することをおすすめします。blake3 は、古いアルゴリズムと比較してパフォーマンスとセキュリティが優れています。ただし、sha256、sha1、md5 は、外部サービスとの互換性のために利用できます。
使用例:
{{ "hello world" | blake3 }} は、「hello world」の BLAKE3 ハッシュを返します。
HMAC フィルター
シークレットキーを使用して HMAC を作成するには、以下のいずれかの対応フィルターを使用します。
hmac_sha256- SHA-256 を使用した HMAC を作成します。hmac_sha1- SHA-1 を使用した HMAC を作成します。
使用例:
- 基本:
{{ "message" | hmac_sha256: "secret_key" }} - シークレットを使用 (推奨):
{{ "message" | hmac_sha256: secrets.api_key }}
Shopify Flow で Liquid 変数を使用する例
Liquid 変数の使用方法をよりよく理解するには、以下の例を参考にしてください。
- リソースの URL を出力する
- タグのリストをメタフィールドに変換する
- 注文に関する動的なメールメッセージを作成する
- 在庫が少ない商品に関する動的なメールメッセージを作成する
- 不正注文についてスタッフに通知するための動的なメールメッセージを作成する
- for ループを使用して注文の項目を出力する
- for ループを使用して注文の項目を追加情報を含めて出力する
- for ループと if 文を組み合わせて一部の項目を出力する
リソースの URL を出力する
ワークフローに関係するお客様、注文、商品の URL を出力します。
# Output the base Admin URL for your store
https://admin.shopify.com/store/{{ shop.myShopifyDomain | replace: ".myshopify.com", "" }}
# Assign the base Admin url to a variable named base_url:
{%- capture base_url -%}https://admin.shopify.com/store/{{ shop.myShopifyDomain | replace: ".myshopify.com", "" }}{%- endcapture -%}
# Customer from a Customer trigger:
{{ base_url }}/customers/{{ customer.legacyResourceId }}
# Customer without the base_url:
https://admin.shopify.com/store/{{ shop.myShopifyDomain | replace: ".myshopify.com", "" }}/customers/{{ customer.legacyResourceId }}
# Customer from an Order trigger:
{{ base_url }}/customers/{{ order.customer.legacyResourceId }}
# Order:
{{ base_url }}/orders/{{ order.legacyResourceId }}
# Product:
{{ base_url }}/products/{{ product.legacyResourceId }}
# Product Variant:
{{ base_url }}/products/{{ product.legacyResourceId }}/variants/{{ productVariant.legacyResourceId }}
# Example showing a clickable link in HTML, making use of the URL:
<a href="{{ base_url }}/products/{{ product.legacyResourceId }}">{{ product.title }}</a>タグのリストをメタフィールドに変換する
タグのセットを1行テキストフィールドのリストであるメタフィールドに変換するとします。[商品がストアに追加されたとき] トリガーを使用してワークフローを作成し、[商品のメタフィールドを更新する] アクションを使用します。[商品のメタフィールドを更新する] アクションの [値] セクションに、以下の Liquid コードを追加します。この例では、商品作成時に一度だけ値を設定する必要があり、商品には color:red と color:orange という2つの関連タグが付いていることを前提としています。
| 入力 | 出力 |
|---|---|
| ["red","orange"] |
注文に関する動的なメールメッセージを作成する
お客様が 1 回の注文で 500 ドル以上を使った場合に、従業員にメールを送信するワークフローを作成するとします。[注文が作成されたとき] トリガーを使用してワークフローを作成し、注文の合計が 500 ドルを超えている場合に true となる条件を設定して、[社内メールを送信する] アクションを使用します。[社内メールを送信する] アクションの [メッセージ] セクションで、以下の変数を使用します。
| 入力 | 出力 |
|---|---|
| Jeanne Dupont様 (jeanne@example.com) から 763.42 ドルのご注文がありました。個別に感謝のメッセージをお送りください。 |
在庫が少ない商品に関する動的なメールメッセージを作成する
商品の在庫が少なくなり、追加の在庫を注文する必要がある場合に、スタッフに通知する必要があるとします。[在庫数量が変更されたとき] トリガーで開始するワークフローを作成し、以前の在庫数量が 10 以下の場合に true となる条件を設定します。その後、[社内メールを送信する] アクションの [メッセージ] セクションで、以下の変数を使用します。
| 入力 | 出力 |
|---|---|
| ハイウエストレギンス - 黒を再注文してください。owner@example.com にメールを送信して、注文書を受け取ったかどうかを確認してください。 |
不正注文についてスタッフに通知するための動的なメールメッセージを作成する
リスクレベルが高い注文をキャンセルしたいものの、スタッフに手動でキャンセルしてもらいたいとします。[注文が作成されたとき] トリガーで開始するワークフローを作成し、注文のリスクレベルが「高」と等しい場合に true となる条件を設定します。そして、[社内メールを送信する] アクションの [メッセージ] セクションで、以下の変数を使用します。
| 入力 | 出力 |
|---|---|
| 私たちの Shopifyストアで不正注文のリスクが高い注文を受け付けました。製造に送られる前に、この注文を直ちにキャンセルしたいと考えています。 #1001 Dupont, Jeanne jeanne@example.com 新しい注文状況を確認してください。よろしくお願いします。 |
for ループを使用して注文の項目を出力する
注文を受け付けた際、注文された商品を含むメッセージを送信すると便利です。これは、コードブロックを繰り返し実行する for ループを使用することで実現できます。変数をサポートするテキストフィールドでは、for ループと forloop オブジェクトもサポートされています。
たとえば、注文に含まれるすべての SKU と数量のリストを返すワークフローを作成する場合、[内部メールを送信する] アクションの [メッセージ] セクションで、以下の変数を使用します。
| 入力 | 出力 |
|---|---|
| 注文概要: 8987097979 (50) 8877778887 (3) 888998898B (1) |
for ループを使用して追加情報とともに注文の項目を出力する
メールに、商品名、SKU、アイテムあたりの価格、お客様の配送情報などの詳細情報を追加することにします。[内部メールを送信する] アクションの [メッセージ] セクションで、以下の変数を使用します。
| 入力 | 出力 |
|---|---|
| 注文概要: 商品: High Waist Leggings - Black SKU: 8987097979 価格 (1 個あたり): $8.49 数量: 5 商品: Athletic Socks - Blue SKU: 888998898B 価格 (1 個あたり): $5.61 数量: 2 |
for ループと if 文を組み合わせて一部の項目を出力する
特定の販売元から供給されている販売済みアイテムを追跡する必要があります。[内部メールを送信する] アクションの [メッセージ] セクションで、以下の変数を使用して、for ループに if 文を含めます。
| 入力 | 出力 |
|---|---|
| 販売された Acme の商品: 商品名: High Waist Leggings - Black SKU: 8987097979 |
Shopify Flow の複雑なデータオブジェクト
Flow を使用すると、GraphQL Admin API にあるほぼすべてのデータにアクセスできます。これには、リストやオブジェクトなどの複雑なデータオブジェクトが含まれます。ただし、これらのオブジェクトで実行できることにはいくつかの制限があります。このセクションでは、これらの制限の概要と、その対処方法の例を説明します。
リストやオブジェクトを直接呼び出す代わりに、リストをループ処理して、必要なフィールドのみを含めるようにしてください。
たとえば、{{ 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 %}
json
{
"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 %}
]
}