Card template
Replace the product card with your own HTML. You edit it in the panel (Appearance → Advanced → Card template) with a live preview, and it supports variables, conditionals and iteration over the product's badges.
Example
<a class="mi-card" href="{{url}}">
{{#if image}}<img src="{{image}}" alt="{{name}}" loading="lazy">{{/if}}
{{#if brand}}<span class="mi-marca">{{brand}}</span>{{/if}}
<h3>{{name}}</h3>
<p class="mi-precio">
{{price}}
{{#if on_sale}}<s>{{price_original}}</s> -{{sale_pct}} %{{/if}}
</p>
{{#each badges}}<span class="mi-badge">{{.}}</span>{{/each}}
</a> The “Add to cart” button is injected automatically after your HTML if you have it enabled — no need to include it in the template. Your card's styles go in the Custom CSS.
Variables
| Variable | Content |
|---|---|
| {{name}} | Product name. |
| {{url}} | URL of the product page. |
| {{image}} | URL of the main image. |
| {{brand}} | Brand. |
| {{category}} | Main category. |
| {{price}} | Current price, formatted. |
| {{price_original}} | Price before the discount. NOTE: if the product is NOT on sale this is the same value as {{price}}, not empty — wrap it in {{#if on_sale}} if you don't want it repeated. |
| {{sale_pct}} | The discount NUMBER, with no sign and no symbol: “24”, not “-24%”. You write the format: -{{sale_pct}} %. Empty when the product is not on sale. |
| {{currency}} | Currency symbol/code. |
| {{reference}} | Internal reference (SKU). |
A variable with no value for a product is replaced with empty text — it never breaks the render.
Conditionals and iteration
{{#if field}}…{{/if}}
renders the block only if the field has a value. Available fields:
on_sale · available · image · brand · category · badges · sale_pct · name · url · price · price_original · currency · reference.
No nesting of conditionals. The most useful one is
{{#if price}}:
in a search engine with no price for that shopper (B2B without a group tariff, price on request), a bare
{{price}}
renders nothing, but the markup around it still does — wrap it and the card stays clean.
{{#each badges}}{{.}}{{/each}}
iterates the product's badges (sale, out of stock, new…) as configured in the panel.
Limits and safety
- Up to 20,000 characters.
- The template is NOT sanitized on the server: the server only checks its size and stores it as-is. The sanitizing happens in the widget at render time (and in the panel preview, with the same code): it strips
<script>,<style>,<iframe>,on*=attributes with any separator, and every URL attribute whose scheme is not in the whitelist (http, https, mailto, tel, data:image and relative paths), both before and after the variables are resolved. It is not a complete HTML sanitizer: review the template the way you would review code that runs in your store. JS goes in its own editor and CSS in its own. - If the store hides prices (B2B catalogs), the price variables are emptied automatically.