Checkout
The checkout template renders the order summary and the controls that collect shipping, payment, and any extra checkout fields. It exposes the line items, the totals, the applied coupons, the shipping and payment options, and a set of extension points where add-on fields are injected. All of these tokens and loops are populated only when the commerce extension is enabled.
Amounts such as {checkout.subtotal} and {checkout.total} are formatted numbers with no currency symbol. Print {checkout.currency_symbol} in front of them so the amount reads as currency.
Line items
{checkout.items} is a collection of the products in the order. Loop over it with {each checkout.items as=item} and read each line with {item.*}.
| Field | Meaning |
|---|---|
{item.id} | Line item id. |
{item.product_id} | Product id. |
{item.name} | Product name. |
{item.image} | Product image URL. |
{item.image_avif} | AVIF source for the product image, when available. |
{item.unit_price} | Price for one unit. |
{item.quantity} | Quantity ordered. |
{item.line_total} | Price for the full line. |
{item.variant} | Selected variant label, when the product has variants. |
{item.index} | Position of the item in the loop, counting from 1. |
{each checkout.items as=item}
<div class="line">
<img src="{item.image}" alt="{item.name}">
<span class="name">{item.name}</span>
<span class="qty">{item.quantity}</span>
<span class="total">{checkout.currency_symbol}{item.line_total}</span>
</div>
{/each}
Totals and currency
These tokens describe the whole order. Pair each amount with {checkout.currency_symbol}.
| Token | Meaning |
|---|---|
{checkout.currency_symbol} | Currency symbol for the order. |
{checkout.currency} | Currency code. |
{checkout.subtotal} | Sum of the line items before tax, shipping, and discounts. |
{checkout.tax} | Tax amount. |
{checkout.shipping} | Shipping amount. |
{checkout.coupon_discount_total} | Total discount applied by all coupons. |
{checkout.total} | Final amount due. |
<div class="summary">
<div class="row">
<span>Subtotal</span>
<span>{checkout.currency_symbol}{checkout.subtotal}</span>
</div>
<div class="row discounts">
<span>Discounts</span>
<span>- {checkout.currency_symbol}{checkout.coupon_discount_total}</span>
</div>
<div class="row total">
<span>Total</span>
<span>{checkout.currency_symbol}{checkout.total}</span>
</div>
</div>
Coupons
{checkout.coupons} is a collection of the coupons applied to the order. Loop over it with {each checkout.coupons as=coupon} and read each entry with {coupon.*}. Use {checkout.coupon_discount_total} for the combined discount.
| Field | Meaning |
|---|---|
{coupon.code} | Coupon code. |
{coupon.description} | Coupon description, when set. |
{coupon.target_scope} | What the coupon discounts, such as the subtotal. |
{coupon.discount_amount} | Amount this coupon removed. |
{coupon.allow_stack} | Whether the coupon can combine with others. |
{each checkout.coupons as=coupon}
<div class="coupon">
<span class="code">{coupon.code}</span>
<span class="description">{coupon.description}</span>
<span class="amount">- {checkout.currency_symbol}{coupon.discount_amount}</span>
{if coupon.allow_stack}
<span class="stackable">Can combine</span>
{/if}
</div>
{/each}
Price summary
{checkout.price_summary} is a collection of prepared rows for the order summary: subtotal, shipping, tax, discounts, and the total, each already formatted and classified. Loop over it with {each checkout.price_summary as=item}. This is the preferred way to render the full breakdown, because each row carries the label, the display amount, and a class that marks discounts.
| Field | Meaning |
|---|---|
{item.label} | Row label, such as Subtotal or Tax. |
{item.amount} | Raw amount value. |
{item.display_amount} | Amount already formatted with the currency symbol. |
{item.amount_class} | Class name for the amount, used to style discounts. |
{item.is_discount} | True when the row is a discount. |
{item.is_free} | True when the row is free. |
{item.is_pending} | True when the row is waiting to be calculated. |
{each checkout.price_summary as=item}
<div class="row {item.amount_class}">
<span>{item.label}</span>
<span>{item.display_amount}</span>
</div>
{/each}
Checkout extension points
Add-on fields are grouped by the position they should appear on the checkout page. Each position is its own loop, named {each checkout.attributes_<position> as=attr}. The loop renders nothing when no field is assigned there, so each block can stay in the template.
| Position token | Where the fields appear |
|---|---|
{each checkout.attributes_above_shipping_address as=attr} | Above the shipping address form. |
{each checkout.attributes_below_shipping_address as=attr} | Below the shipping address form. |
{each checkout.attributes_above_shipping_methods as=attr} | Above the shipping method list. |
{each checkout.attributes_below_shipping_methods as=attr} | Below the shipping method list. |
{each checkout.attributes_above_payment_method as=attr} | Above the payment method list. |
{each checkout.attributes_below_payment_method as=attr} | Below the payment method list. |
{each checkout.attributes_order_summary as=attr} | Inside the order summary. |
Each attr exposes the prepared field and its metadata.
| Field | Meaning |
|---|---|
{attr.html} | Ready-to-render markup for the field. |
{attr.id} | Field id. |
{attr.code} | Field code. |
{attr.label} | Field label. |
{attr.input_type} | Input type, such as text or select. |
{attr.placeholder} | Placeholder text. |
{attr.default_value} | Default value. |
{attr.required} | Whether the field is required. |
Render the prepared markup with {attr.html}, or use the individual fields to build custom markup.
{each checkout.attributes_above_shipping_address as=attr}
{attr.html}
{/each}
{each checkout.attributes_below_payment_method as=attr}
<div class="extra-field" data-code="{attr.code}">
{attr.html}
</div>
{/each}
Shipping methods
{shipping_methods} is the collection of available shipping options. Loop over it with {each shipping_methods as=method} and use {method.code} as the radio value.
| Field | Meaning |
|---|---|
{method.code} | Shipping method code, used as the submitted value. |
{method.name} | Method name. |
{method.description} | Method description, when set. |
{method.price} | Shipping price. |
{method.is_free} | True when the method is free. |
{method.is_selected} | True when the method is the current selection. |
{each shipping_methods as=method}
<label>
<input type="radio" name="shipping_method" value="{method.code}">
<span>{method.name}</span>
<span>{method.description}</span>
{if method.is_free}
<span>Free</span>
{else}
<span>{method.price}</span>
{/if}
</label>
{/each}
Payment methods
{payment_methods} is the collection of available payment options. Loop over it with {each payment_methods as=payment} and use {payment.code} as the radio value.
| Field | Meaning |
|---|---|
{payment.code} | Payment method code, used as the submitted value. |
{payment.name} | Payment method name. |
{payment.icon_svg} | Inline icon markup for the method, when available. |
{payment.is_selected} | True when the method is the current selection. |
{each payment_methods as=payment}
<label>
<input type="radio" name="payment_method" value="{payment.code}">
{if payment.icon_svg}
{payment.icon_svg}
{/if}
<span>{payment.name}</span>
</label>
{/each}
Checking before rendering
Guard sections with the checkout flags when you only want them to appear once the order has content.
| Condition | True when |
|---|---|
{if checkout.has_items} | The order has at least one line item. |
{if checkout.has_shipping_methods} | At least one shipping method is available. |
{if checkout.has_coupons} | At least one coupon is applied. |
{if checkout.has_coupons}
<div class="coupons">
{each checkout.coupons as=coupon}
<span>{coupon.code}</span>
{/each}
</div>
{/if}

