Start here

Developer overview

On this page

AndOr draws its storefront widgets with one theme app extension: an app embed called AndOr Discount Display and nine app blocks. This section is for theme developers who want to place, restyle or listen to those widgets.

The widgets show promotions and upsell offers. For how the two fit together, see Promotions and upsell offers.

Note Most merchants never need code. The app blocks and the app embed are set up in the theme editor. Code is for themes with no slot for a block, for product cards, and for custom styling.

What you can change, and how

You want to Use Page
Add a widget in the theme editor App blocks and the app embed App embed and blocks
Add a widget where the theme has no block slot One of the seven one-line tags One-line tags
Show a badge or sale price on product cards Pasted Liquid recipes Product card recipes
Change colors, corners, spacing --andor-* CSS custom properties Styling tokens
Pick a ready-made look The embed’s Style preset Style presets
Style a state (reached, sold out, applied) data-* attributes and state classes Data attributes and states
React when a widget changes andor: DOM events and pixel events Events
Redraw after an Ajax swap refresh() on the public objects JavaScript API
Know how upsell adds reach the cart The cart update paths Cart updates
Tie a widget you built yourself to an offer The _andor_offer_id line property Measure your own widget

How the widgets render

The widgets render in the light DOM, from Liquid, on the server. There is no shadow root.

  • Classes are the styling surface. Every class starts with andor-, so a theme rule like .price or .badge does not reach into the widget. There is no ::part.
  • Liquid picks the discount. For the sale price, the savings badge, the volume table, the collection banner and the discount callout, the final text is in the HTML the server sent.
  • Some widgets are printed by JavaScript. The countdown, the offers list, the goal bar, the volume picker layouts, the offer picker and the cart claim rows. Liquid still decides which discount applies and prints a skeleton at the finished size. The script only turns those facts into words. It never picks a discount of its own.
  • JavaScript off still tells the truth. The first paint shows the right price, badge and volume table. A widget printed by JavaScript keeps its space and shows nothing. For example, with scripts blocked a goal bar is an empty box, never a wrong “Spend $12.00 more”.

What the widgets read

The widgets read JSON metafields in the app-reserved namespace $app:andor_display. The main keys:

Owner Key What it holds
product discounts deals that target this product
collection discounts deals that target this whole collection
shop shop_discounts storewide deals
shop offers the whole catalog’s live deals
product, collection and shop best_percent the best percentage
product, collection and shop best_amount_each the best per-item amount
product, collection and shop best_ends_at epoch seconds when the two above stop being true

Inside an app block that belongs to AndOr, the namespace resolves directly:

{%- assign andor_none = '' | split: ',' -%}
{%- assign andor_rows = product.metafields["$app:andor_display"].discounts.value | default: andor_none -%}
Liquid

In your own theme code, $app: does not resolve. Use the rendered form, where <app-id> is the app’s numeric id:

{%- assign andor_rows = product.metafields.app--<app-id>--andor_display.discounts.value -%}
Liquid

Tip You do not need to find the app id. The app’s Storefront blocks page renders every recipe with your store’s namespace already filled in. Open Storefront display, then choose See all blocks from the page menu.

Rules that matter when you read the metafields yourself:

  • Combine both owners. A product’s best deal is the better of its own discounts and the shop’s shop_discounts. Storewide deals are not copied onto every product.
  • Test product.gift_card?. Shopify does not discount gift cards, but the shortcut numbers are still written on them. Write the question mark. The bare gift_card is nil and fails silently.
  • A missing key means “nothing”. The app deletes a shortcut key when nothing qualifies. It never writes a zero.
  • Only discounts the merchant turned on are there. A discount that is not switched on in Storefront display is not in the metafields at all.

Network calls

Every call the widgets make goes to the store’s own domain. There are no third-party requests.

  • /cart.js and the /cart/*.js endpoints, to read and change the cart.
  • ?sections=, to redraw Dawn’s cart drawer after an upsell add.
  • Upsell offer counts (views, clicks and adds), sent through your store’s app proxy, only after the shopper’s consent.
  • Error reports from AndOr’s own files, sent through your store’s app proxy. They carry no cart, customer or URL data.

Two things to check first

  1. The discount is switched on in the app. In AndOr, open Storefront display and turn on Show on storefront for the discount. Every widget needs this.
  2. The app embed is on. In the theme editor, open App embeds and switch on AndOr Discount Display. It prints the token layer and loads the shared scripts. Blocks show without it. One-line tags, the cart drawer, the shared look settings, text overrides, translations and the DOM events all need it. See What needs the app embed.

If a widget still does not show, see Widgets not showing.

Debugging

The app embed has a setting Log AndOr display decisions to the browser console. Turn it on while you troubleshoot, and off again after.

Next steps

Last updated

Was this page helpful?

No

Questions? Email andor@backtrackhq.com or use the chat in the app.