Skip to content

Product add-ons

The add-ons widget never shows anything, on any product

Section titled “The add-ons widget never shows anything, on any product”

Same self-hiding shape as the bundle/volume/mix-match widgets - <storesynk-addons> sets [ss-empty] in every “nothing to say” case, so they all look identical:

  1. No namespace configured. The widget needs the Storesynk app’s concrete metafield namespace (app--<numeric-app-id>) - Storefront queries can’t use the $app: shorthand. Set app-namespace="app--…" on <storesynk-store> or namespace on the widget; neither warns SSK-211 and the widget stays ss-empty with no network request at all (that absence is the diagnostic).
  2. Not inside the page’s <storesynk-product>. It consumes productContext for the product id (SSK-102); outside a product it renders nothing, silently.
  3. No template. Its first element child is the per-offer template (SSK-107); <addon-list>’s first child must be (or contain) a <storesynk-product> row card (SSK-107).
  4. No live offer - by design. Only a status: active offer inside its date window with at least one resolvable add-on row qualifies. A deleted/unpublished add-on product drops its row (not the offer); the offer hides only when zero rows resolve. If the app says an offer exists, check its status, dates, and that the add-on products are published to the headless channel.
  5. Another offer won the overlap rule - by design. When several live offers match a product page the widget renders exactly ONE: the first match by specificity, products > collections > all, ties broken by list order. Seeing offer A on a page you expected offer B on usually means A targets the product directly while B targets a collection (or “all”).

The offer shows the wrong one of two overlapping offers

Section titled “The offer shows the wrong one of two overlapping offers”

That’s the deterministic overlap rule above, not a race: products-targeted offers always beat collections-targeted ones, which beat all-products ones. Reorder or retarget the offers in the app to change the winner.

The title renders but the rows / checkboxes / prices are blank

Section titled “The title renders but the rows / checkboxes / prices are blank”

show-addons-title / show-addons-subtitle / <addon-list> consume the offer context that only <storesynk-addons> provides (SSK-105). <select-addon> / show-addon-price / show-addon-original-price consume the per-clone row context that <addon-list> attaches to each row-card clone - authored outside the row-card template they sit on the detached template forever and are never touched (SSK-105). Author exactly one row card and let the engine clone it; the card carries no handle/product-id (it is fed via provideProduct(), the third sanctioned storesynk-product nesting - SSK-103 exempts it).

Ticking ON needs a purchasable variant: while the row card’s current variant is sold out or the selection resolves to no variant, the wrapper carries [ss-out-of-stock] / [ss-unavailable] and the control aria-disabled - style those states. Ticking OFF always works (a ticked row is never disabled). If nothing at all reacts, the addons chunk never armed: the page is missing its <storesynk-store> boot (SSK-101/206) or the elements script (SSK-401).

show-addon-original-price hides (hidden + [ss-empty]) when the offer takes nothing off the price - discount type none, free_shipping, or 0%. Nothing to strike through means nothing renders; that’s by design. show-addon-price likewise hides while the card resolves no variant.

Ticked add-ons don’t ride the Add to cart / arrive as separate full-price lines

Section titled “Ticked add-ons don’t ride the Add to cart / arrive as separate full-price lines”

There is deliberately no add-addons button: the page’s standard <add-to-cart> sends ONE multi-line updateCart - the untagged host line plus one line per ticked row, stamped _ss_addons (the app entry id) / _ss_addons_host (the host product gid). If the add-ons don’t ride along, the <add-to-cart> and the widget are not in the SAME <storesynk-product> scope (a widget inside a nested card belongs to that card). If the lines land but no discount applies, the app’s Discount Function isn’t installed/active for the shop, something stripped the line attributes, or the Function’s validation failed - it requires an untagged host line of the host product in the cart and rejects quantities above the configured row quantity (any violation forfeits the whole offer’s discount, by design: that strictness is what makes 100%-off gifts abuse-safe). The widget’s prices are advisory either way; checkout is authoritative.

Preselected rows are a merchant setting: they start ticked in the client’s initial state AND the SSR zero-interaction render (so adoption repaints nothing), and they ride the standard add button unless the shopper unticks them. Untick always works.


Imported from the Storesynk skill v0.1.0 (references/known-issues.md). To change this page, change it there.