Data

Data serializers

Turning Shopify objects into JSON React can use.

snippets/json--*.liquid turn Shopify objects into JSON React can use. Each one outputs a bare value, or null when its subject is blank, so they compose.

json--sectionThe standard payload: settings, blocks, plus opt-in resources
json--productProduct, with variants / media / selling_plans toggles
json--variant, json--product-variantsVariants
json--selling-plan, json--selling-plan-groups, json--selling-plan-allocationsSubscriptions
json--collection, json--article, json--cart, json--line-itemResources
json--filters, json--paginateCollection filtering and paging
json--image, json--mediaReal CDN URLs, srcset, focal point
json--customer, json--link-list, json--shop, json--routesThe rest

Opting into resources

1{% render 'react-section', component: 'main-product', section: section,
2 with_product: product %}

The with_ prefix is deliberate. {% render %} gets a clean scope, but global objects still reach it — so a plain product parameter would silently populate on product templates and nowhere else. Prefixing means a resource is included only when you asked for it, and payload size stays something you control.

Parameter
with_product, with_collection, with_articleResources
with_cart, with_customer, with_menuThe rest
product_variants, product_media, product_selling_plansDefault true
collection_limitProducts to include. Omit for none
image_widthWidth for base image src values

Watch the size

The payload is inline in the HTML on every page load.

3-variant product~12 KB
Same, with subscriptions~19 KB
Each extra variant~1.5 KB
Each subscription allocation~650 bytes

A 50-variant product on a 4-plan group is over 100 KB of HTML. For grids, pass product_variants: false, product_media: false and fetch the rest from {product.url}.js when you actually need it.

Money

Integers are in the shop's minor unit; *_formatted is the display string.

Do maths on the integer, render the string. Never re-format cents in JavaScript — currencies with non-decimal subunits break, and a store selling in JPY or KWD will be wrong in a way nobody notices until a customer complains.

1const total = lines.reduce((sum, line) => sum + line.final_line_price, 0)
2<span>{cart.total_price_formatted}</span>

formatMoney from @/framework is available where you genuinely have to build a string client-side — it uses Intl.NumberFormat with the shop's currency.

Subscriptions

Shopify splits this in two, and so do the snippets:

  • selling_plan_groups on the product — the catalogue: names, picker options, discounts as rules.
  • selling_plan_allocations on each variant — the resolved prices.

Join on selling plan id and render the allocation's price. Don't apply price_adjustments yourself:

1const price = variant.selling_plan_allocations
2 .find((a) => a.selling_plan_id === plan.id)
3 .price_formatted // "$21.25", discount already applied

Empty arrays on stores without subscriptions, so it costs nothing until used.