case study · liquid · metafields · pricing
Promo pricing with an ownership guard
Background. A home-goods client ran rotating percentage promotions on
curated product sets. Editing compare_at_price on hundreds of variants for
every campaign wasn’t viable, and pricing apps fought their theme. The pattern
that stuck: a sync writes promo_* metafields per product, and the theme
renders sale pricing from them — one source of truth, no variant surgery.
How it works on the demo store. Six ceramics carry
custom.promo_percentage: 20 plus custom.promo_owner_product_id, and a real
automatic discount (20% off the same collection) backs them — so the price you
see struck through on the collection page is exactly what checkout charges.
The theme computes the promo in the price snippet and reuses the theme’s own
on-sale markup, so promo pricing is visually indistinguishable from native
sales. A date window (promo_starts_at / promo_ends_at) is honored when
present.
The ownership guard — the part that earns its case study. When a merchant
duplicates a product, Shopify copies its metafields. But the duplicate is
not a member of the discount’s collection, so checkout won’t apply the
promo. Without a guard, the duplicate’s product page advertises −20% and the
checkout silently refuses it — a support ticket, or worse, a pricing-law
problem. The fix is one field: the sync stamps promo_owner_product_id with
the product it wrote to, and the theme suppresses the promo whenever that
field names a different product:
assign promo_owner = product.metafields.custom.promo_owner_product_id.value
if promo_owner != blank
assign self_gid = 'gid://shopify/Product/' | append: product.id
if promo_owner != self_gid
assign promo_active = false
endif
endif
See the guard live. The demo store has the failure case staged: Ribbed Ceramic Vase shows −20% ($44.00 → $35.20). Its duplicate, Ribbed Ceramic Vase (Copy), carries the very same promo metafields — and shows no promo, because the guard catches the mismatch. Add each to the cart and walk to checkout to see the totals agree with what the pages promised.