Build

Product card recipes

On this page

Product card recipes are short pieces of Liquid you paste into your theme’s product card. Shopify gives apps no block slot inside a product card, so this is how a collection, search or home page card shows an AndOr badge or sale price.

Tip Card recipes need no JavaScript and no stylesheet. They work with the app embed off, and they are correct with scripting disabled.

On Horizon: use the app blocks

Do not paste card recipes on Horizon. Horizon builds its product cards from blocks, so there is no snippets/card-product.liquid to paste into. In the theme editor, add the AndOr Sale price or AndOr Savings badge app block to the product card instead. See Horizon.

The recipes

# Recipe Lines Reads
1 Percentage badge, over the image 6 best_percent
2 Percentage badge, next to the title 6 best_percent
3 Crossed-out original price 10 best_percent, price
4 Badge that hides when the sale ends 9 best_percent, end
5 Price with expiry, the complete one 21 both owners
6 Storewide sale banner 7 shop scalars only
7 “Use code X” chip 12 the discounts array
8 “Ends in Xh” urgency text 9 best_ends_at
18 Volume discount hint on a card file + 2 both arrays

The numbers have gaps on purpose. Removed recipes keep their number, so “recipe 18” always means the same recipe.

Every recipe except 5 adds markup beside what your theme already renders. Recipe 5 replaces a price line and comes with a wrapper to do it.

Copy them from the app

  1. In AndOr, open Storefront display and choose See all blocks.

    The Storefront blocks page opens.

  2. Open Product cards: pasted recipes, pick a recipe and copy it.

    The copy has your store’s real metafield namespace filled in. The versions on this page say app--<app-id>--andor_display and render nothing until you swap in the real value.

  3. Open the theme code and find the file the recipe names.

    In Shopify admin, go to Online Store, then Themes, then Edit code in the theme’s menu. On Dawn most recipes go in snippets/card-product.liquid.

  4. Paste where the recipe says, then press Save.

  5. Check a collection page. A discounted product shows the recipe. Products with no discount look exactly as before.

To undo, delete the lines you pasted and press Save. No app data is affected.

Five things before you paste

  1. Copy the namespace from the app. The real namespace has a numeric app id in the middle and differs per store. $app:andor_display only works inside AndOr’s own blocks, not in your theme code.
  2. Never name a metafield key size, first or last. Those are Liquid filters. When such a metafield is missing, Liquid applies the filter to the namespace and returns a count instead of nothing. None of AndOr’s keys use these names.
  3. A missing metafield renders nothing, never “0% off”. The app deletes a shortcut key when nothing qualifies. | plus: 0 turns a missing best_percent into 0, and the > 0 test is the whole check. best_ends_at is the other way round: missing means “does not end”, so it reads | default: 9999999999.
  4. A printed percentage is floored, never rounded. A real 12.5% discount must never show as 13%. Every recipe prints {{ andor_percent | floor }} and keeps the full value for math.
  5. Colors are literal on purpose. Each recipe hard-codes #c0392b so it works with the app embed off. To follow the app’s color, swap the literal for the token, with the literal as fallback:
style="background:var(--andor-color-accent, #c0392b);
  color:var(--andor-color-on-accent, #ffffff)"
Liquid

One more rule: keep the gift_card? guard. Shopify does not discount gift cards, and the question mark matters.

Recipe 1: percentage badge over the image

Puts a “20% OFF” chip in the corner of the card image. Paste it inside the card’s image wrapper in snippets/card-product.liquid, after all the images, just before the wrapper’s closing tag.

{% comment %} AndOr Discount Display: badge over the image. {% endcomment %}
{% assign andor_item = card_product | default: product %}
{% assign andor_percent = andor_item.metafields.app--<app-id>--andor_display.best_percent.value | plus: 0 %}
{% if andor_percent > 0 and andor_item.gift_card? != true %}
  <span class="andor-badge" style="position:absolute;top:0.5rem;left:0.5rem;bottom:auto;right:auto;width:auto;height:auto;z-index:2;background:#c0392b;color:#ffffff;border-radius:0.25em;padding:0.15em 0.55em;font-size:0.85em;font-weight:600">{{ andor_percent | floor }}% OFF</span>
{% endif %}
Liquid

A Dawn collection grid with the pasted savings badge in the top left corner of a product card image

Three ways it can look broken, and the fix for each:

  • The chip fills the whole card (size). Dawn stretches every direct child of the image wrapper. The recipe’s inline width:auto;height:auto and the two auto offsets undo that. Keep all four if you restyle it.
  • The image vanishes on hover (order). A card has two images and Dawn swaps them with an img + img rule. Pasting between them breaks it. Paste after every <img>.
  • The chip flies to the corner of the page (place). The wrapper is not positioned. Add position:relative to the element you pasted into:
.card__media { position: relative; }
CSS

The chip lands top-left. The app offers the other three corners beside the recipe. Each corner sets two offsets and sets the opposite two to auto:

Corner What the style attribute says
Top left top:0.5rem;left:0.5rem;bottom:auto;right:auto
Top right top:0.5rem;right:0.5rem;bottom:auto;left:auto
Bottom left bottom:0.5rem;left:0.5rem;top:auto;right:auto
Bottom right bottom:0.5rem;right:0.5rem;top:auto;left:auto

Recipe 2: percentage badge next to the title

The same number, inline, with no positioning. Paste it right after the product title link in snippets/card-product.liquid. It also works on a product page in sections/main-product.liquid.

{% comment %} AndOr Discount Display: badge next to the title. {% endcomment %}
{% assign andor_item = card_product | default: product %}
{% assign andor_percent = andor_item.metafields.app--<app-id>--andor_display.best_percent.value | plus: 0 %}
{% if andor_percent > 0 and andor_item.gift_card? != true %}
  <span class="andor-badge" style="display:inline-block;background:#c0392b;color:#ffffff;border-radius:0.25em;padding:0.15em 0.55em;font-size:0.85em;font-weight:600">Save {{ andor_percent | floor }}%</span>
{% endif %}
Liquid

If your theme names the card’s product differently

card_product | default: product covers Dawn, Studio and themes built from them. card_product must come first. On a product page, product is in scope everywhere, so a related-products card would show the page’s discount.

Other themes loop the card’s product into their own name, such as item. Find it in the section’s {% render %} call, then change the andor_item line:

{% assign andor_item = item | default: product %}
Liquid

A Dawn product card with the pasted savings badge next to the product title

Two symptoms point to this line:

  • On a collection page, nothing renders on any card.
  • On a product page, every related-products card shows the page product’s discount.

Recipe 4: badge that hides when the sale ends

Recipe 2 plus an end-date check. Paste it anywhere recipe 2 goes.

{% comment %} AndOr Discount Display: badge that expires. {% endcomment %}
{% assign andor_item = card_product | default: product %}
{% assign andor_percent = andor_item.metafields.app--<app-id>--andor_display.best_percent.value | plus: 0 %}
{% comment %} The key is ABSENT when the sale does not end, so the default has to be far future. {% endcomment %}
{% assign andor_ends = andor_item.metafields.app--<app-id>--andor_display.best_ends_at.value | default: 9999999999 %}
{% assign andor_now = 'now' | date: '%s' | plus: 0 %}
{% if andor_percent > 0 and andor_ends > andor_now and andor_item.gift_card? != true %}
  <span class="andor-badge" style="display:inline-block;background:#c0392b;color:#ffffff;border-radius:0.25em;padding:0.15em 0.55em;font-size:0.85em;font-weight:600">Save {{ andor_percent | floor }}%</span>
{% endif %}
Liquid

A Dawn collection grid with the pasted savings badge in the top left corner of a product card image

The check runs when the page is built. A sale that ends while a shopper looks at a served page stays on screen until they navigate.

The other recipes

Copy these from the app. Each one names its file and spot.

  • Recipe 3, crossed-out original price. The struck original beside the discounted price. It adds a price, so delete your theme’s price line or use recipe 5.
  • Recipe 5, price with expiry. Saved as snippets/andor-card-price.liquid and rendered inside a {% capture %} wrapper. Either the sale price or your theme’s price renders, never both. It reads the product and the shop, so storewide sales count too.
  • Recipe 6, storewide sale banner. One line across the top of every page, in layout/theme.liquid just after <body>. It reads the shop metafields only, so it stays blank unless a storewide sale is live.
  • Recipe 7, “Use code X” chip. Under the price on a product page. It reads the discounts array and checks both start and end dates.
  • Recipe 8, “Ends in Xh” urgency text. Shows “Ends in under Xh” for the last 48 hours. It does not tick. For a live clock, use the AndOr Countdown block.
  • Recipe 18, volume discount hint. Saved as snippets/andor-card-tiers.liquid, then rendered twice in the card: an “UP TO 30% OFF” chip over the image and an info button beside the title that lists each step’s price.

What card recipes do not do

  • No variant-scoped deals. A deal for some variants only is left out of the shortcut numbers. A card has no variant picker, so it says less rather than promising a price on every variant.
  • No fixed-amount deals by default. best_amount_each is in shop currency and the recipes have no script to convert it.
  • No translation. “Save”, “OFF”, “Use code” and “Ends in under” are literals. Edit them in your copy.
  • Nothing follows a variant picker. For that, use the app blocks or the one-line tags.

Next steps

Last updated

Was this page helpful?

No

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