Orders and account
The Commerce extension exposes the signed-in customer's order history through the user.orders collection and the visitor's own details through {currentUser.*} tokens. Use them to build account pages, billing lists, and single-order views. The order loop and the order detail tokens only populate when the commerce extension is enabled and a customer session is present.
The current visitor
{currentUser.*} reads the customer record for the visitor making the request. The value resolves on every page and block. A key that has no stored value renders empty.
| Token | Meaning |
|---|---|
{currentUser.isLoggedIn} | True when the visitor is a signed-in customer. |
{currentUser.is_guest} | True when the visitor is a guest. |
{currentUser.id} | The customer record id. |
{currentUser.status} | The customer status value, for example guest. |
{currentUser.first_name} | Given name. |
{currentUser.last_name} | Family name. |
{currentUser.nickname} | Display nickname. |
{currentUser.username} | Username. |
{currentUser.email} | Email address. |
{currentUser.phone} | Phone number. |
{currentUser.name} | Full name. |
Additional stored attributes are available by their own key, for example {currentUser.company} when the customer record carries a company attribute. Attribute names resolve case-insensitively.
Add .letter(<n>) to read the first characters of a field, or .letter(<n>, "last") to read the final characters.
<span>{currentUser.first_name.letter(1)}</span>
<span>{currentUser.first_name.letter(2, "last")}</span>
Use {if ...} to branch on the visitor state.
{if currentUser.isLoggedIn}
<p>Welcome back, {currentUser.first_name}</p>
{else}
<p>Sign in to see your orders.</p>
{/if}
Order history
{each user.orders as=order} walks the signed-in customer's orders, most recent first. Wrap the loop in {if user.orders} so an empty list shows a message instead of an empty section.
| Field | Meaning |
|---|---|
{order.order_number} | The public order number. |
{order.created_at} | The order date. |
{order.status} | The order status. |
{order.total} | The order grand total. |
{order.currency_symbol} | Symbol for the order's currency. |
{if user.orders}
<div class="orders">
{each user.orders as=order}
<a href="/user/billing/orders/{order.order_number}" class="order">
<span>Order #{order.order_number}</span>
<span>{order.created_at}</span>
<span>Status: {order.status}</span>
<span>{order.currency_symbol} {order.total}</span>
</a>
{/each}
</div>
{else}
<p>No orders found.</p>
{/if}
Search and paging
The orders list is paged. The runtime reads q, page, and perPage from the request query string, and the following tokens report the current state.
| Token | Meaning |
|---|---|
{user.orders_count} | Total orders matching the current search. |
{user.orders_page} | Current page number. |
{user.orders_pages} | Total number of pages. |
{user.orders_prev_page} | Previous page number; empty on the first page. |
{user.orders_next_page} | Next page number; empty on the last page. |
{user.orders_query} | The current search text. |
{if user.orders_prev_page} and {if user.orders_next_page} gate the pager controls, and {if user.orders} reports whether any order matched.
<div class="pager">
{if user.orders_prev_page}
<a href="?page={user.orders_prev_page}">Previous</a>
{/if}
<span>Page {user.orders_page} of {user.orders_pages}</span>
{if user.orders_next_page}
<a href="?page={user.orders_next_page}">Next</a>
{/if}
</div>
Single order
When the page URL carries an order number, for example /user/billing/orders/{order_number}, the order detail tokens are available directly as {order.*}. The line items are exposed as the order.order_items collection.
| Token | Meaning |
|---|---|
{order.id} | Order id. |
{order.order_number} | Public order number. |
{order.created_at} | Order date. |
{order.status} | Order status. |
{order.currency} | Currency code. |
{order.currency_code} | Currency code. |
{order.currency_symbol} | Currency symbol. |
{order.subtotal} | Subtotal before shipping and tax. |
{order.shipping_amount} | Shipping amount. |
{order.tax_amount} | Tax amount. |
{order.grand_total} | Grand total. |
{order.total_paid} | Amount paid. |
{order.customer_name} | Customer name. |
{order.customer_email} | Customer email. |
{order.payment_method} | Payment method label. |
{order.billing_address.street} | Billing street. |
{order.billing_address.city} | Billing city. |
{order.billing_address.state} | Billing region. |
{order.billing_address.zip} | Billing postal code. |
{order.billing_address.country} | Billing country. |
{order.shipping_address.street} | Shipping street. |
{order.shipping_address.city} | Shipping city. |
{order.shipping_address.state} | Shipping region. |
{order.shipping_address.zip} | Shipping postal code. |
{order.shipping_address.country} | Shipping country. |
The line item fields inside {each order.order_items as=item}:
| Field | Meaning |
|---|---|
{item.id} | Line item id. |
{item.product_id} | Product id; empty when the line is not a product. |
{item.sku} | Product SKU. |
{item.name} | Product name. |
{item.image} | Product image URL; empty when none. |
{item.is_subscription} | True when the line is a subscription. |
{item.quantity} | Quantity ordered. |
{item.price} | Unit price. |
{item.line_total} | Line total. |
{if order.order_items} guards the item list, with {if item.image} and {if item.is_subscription} available inside the loop.
<h1>Order #{order.order_number}</h1>
<p>Placed {order.created_at}</p>
<p>Status: {order.status}</p>
{if order.order_items}
{each order.order_items as=item}
<div class="line">
{if item.image}<img src="{item.image}" alt="{item.name}">{/if}
<span>{item.name}</span>
<span>Qty {item.quantity}</span>
<span>{order.currency_symbol} {item.line_total}</span>
</div>
{/each}
{else}
<p>No items found for this order.</p>
{/if}
<p>Subtotal: {order.currency_symbol} {order.subtotal}</p>
<p>Shipping: {order.currency_symbol} {order.shipping_amount}</p>
<p>Tax: {order.currency_symbol} {order.tax_amount}</p>
<p>Total: {order.currency_symbol} {order.grand_total}</p>

