Skip to main content

Nunjucks Theme Pitfalls

Shipping checklist for Nunjucks theme authors. These caused real production bugs. Also see Nunjucks Theme API, Products & Catalog, Shortcodes & Tags, Policy & Legal Pages.

1. autoescape is false

Join Markt runs Nunjucks with autoescape: false. Do not put HTML fields (product.description, seo_description) into attributes:
Do instead — strip HTML for meta, or encode with json:

2. Never put | json inside x-data="..."

Put boot data in a JSON script; read it in JS / x-init. Prefer lean fields (no description HTML):

3. Never dump full products into <head> scripts

Full catalog JSON (with HTML descriptions) in <head> can break out of <script>.
  • Lean only: id, name, slug, image, minPrice / maxPrice, variant id / price / name
  • Prefer end of <body>

4. Do not re-register Alpine.data('cartPage')

components/cart-page.njk → platform injects markt-cart-client, which owns cartPage + checkout(). A theme stub registered later overwrites it → cart checkout dies. Do not redefine cartPage. Use the injected client only.

5. Cart API payload must be lean

GET /api/v1/cart?storeId=&shopId=&cart=cart must be:
Do not nest full product / variant blobs (URL size / empty parse). Do not replace localStorage / appCart with [] when fullCart is empty unless the platform explicitly cleared lines — otherwise the drawer looks empty after add-to-cart. POST /api/v1/checkout needs real productId (+ variantId, quantity). Passing only { name } caused checkout “Unknown Product” (fixed in platform createV1Checkout — still send ids from themes).

6. Visibility rules

Treat on-hold / private in the theme even if cache briefly leaks rows. Public catalog cache is ~120s — visibility changes can lag until revalidate.

7. Catalog data sources

Do not loop raw products for homepage cards when groups exist (duplicates).

8. Checkout cart lines (platform)

createV1Checkout must pass full cart lines into createOrder: productId, variantId, name, quantity, price (line id may be productId:variantId). Name-only cart lines → Unknown Product with a correct total. Fixed on the platform; theme authors should still always send product ids from appCart.items.
Seller text lives in Configure → store policies. Filenames must match the router: Do not use Vite paths (/privacy, /refunds) or wrong filenames (privacy.njk, refunds.njk) — they will not resolve. Full guide: Policy & Legal Pages.