Skip to content

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.

TokenMeaning
{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.

html
<span>{currentUser.first_name.letter(1)}</span>
<span>{currentUser.first_name.letter(2, "last")}</span>

Use {if ...} to branch on the visitor state.

html
{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.

FieldMeaning
{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.
html
{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.

TokenMeaning
{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.

html
<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.

TokenMeaning
{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}:

FieldMeaning
{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.

html
<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>