Orders & Carts

Commerce uses a single Order (opens new window) element to represent both an in-progress cart and a completed order. Whenever we use the terms “cart” and “order,” we’re talking about the same underlying object—but in two different states.

The lifecycle of an order element looks something like this:

  1. A customer visits your site and is assigned an order number;
  2. Items (purchasables) are added to the cart as line items;
  3. Additional information is collected to satisfy your checkout requirements;
  4. Payment is submitted, completing the order;

However, not all carts will become orders in this way! Commerce also allows store managers to create carts from the control panel; checkout without payment (or with partial payment) is possible via configuration; carts can be abandoned; or a cart can be manually completed via the control panel.

As a type of element, orders use a familiar management interface, including sophisticated permissions, statuses, and custom fields.

# Configuration

The functionality of carts and orders is mostly consistent across Commerce projects, but there are a few ways you can customize them to suit your business needs.

# Store Settings

Each store has the following settings (accessible via

  1. Commerce
  2. System Settings
  3. Stores
  4. Choose a Store
  5. Settings tab
):

  • Auto Set New Cart Addresses, Auto Set Cart Shipping Method Option, Auto Set Payment Source — Whether the respective information should be automatically attached to new carts, for logged-in customers.
  • Allow Empty Cart On Checkout, Allow Checkout Without Payment, Allow Partial Payment On Checkout, Require Shipping Address At Checkout, Require Billing Address At Checkout, Require Shipping Method Selection At Checkout — Choose what requirements a cart must meet to be completed by a customer.
  • Free Order Payment Strategy — Enable only when using a gateway that supports zero-total transactions.
  • Minimum Total Price Strategy — How Commerce handles potentially-negative order totals.
  • Use Billing Address For Tax — By default, Commerce uses the shipping address to calculate taxes. If your store sells only virtual/digital goods, enable this.
  • Validate Business Tax ID as Vat ID — Whether addresses’ Organization Tax ID field must be validated as a VAT ID (opens new window).

A store’s settings only govern carts and orders created and completed within them.

# Global Configuration

Additional settings are available via the global config file:

  • activeCartDuration — How long carts are considered “active.”
  • purgeInactiveCarts — Whether inactive cart elements should be deleted during routine garbage collection.
  • purgeInactiveCartsDuration — How long before an inactive cart is eligible for purging. This is the total time since the last update to the cart, not in addition to the activeCartDuration.
  • loadCartRedirectUrl — Where a customer will be redirected after loading a previous cart into their session.
  • validateCartCustomFieldsOnSubmission — Whether custom fields on a cart are validated whenever it is updated. Enable with caution, as this can affect customers’ ability to add products to their cart without first submitting required field values.

# Field Layout

Orders have a dedicated field layout, which can be used to collect additional information from customers, or to hold information about fulfillment and other back-office processes.

Visit

  1. Commerce
  2. System Settings
  3. Orders
  4. Field Layout
to customize the order field layout.

Add field and tab conditions to expose administrative tools to specific managers, or while an order is specific statuses!

# Carts

As a customer or store manager is building a cart, the goal is to maintain an up-to-date list of items with their relevant costs, discounts, promotions, and metadata. For this reason, the cart will be recalculated each time a change is made.

Once a cart is completed, however, it becomes an order that represents choices explicitly finalized by whoever completed the cart. The order’s behavior changes slightly at this point: the customer will no longer be able to make edits, and changes made by a store manager will not automatically trigger recalculation.

Carts and orders are managed per-store. A customer may have multiple active carts in different stores, each with discrete contents—the cart Commerce loads automatically for a customer depends on what site they’re viewing, in the front-end.

Customers can also switch between active carts for a given site.

Carts and orders are both listed on the Orders index page in the control panel, where you can further limit your view to active carts (updated in the last hour), and inactive carts (older than an hour). You can customize this time limit using the activeCartDuration setting.

Craft automatically deletes inactive carts after 90 days. Disable purging with the purgeInactiveCarts setting, or fine-tune the delay with purgeInactiveCartsDuration.

Your customers’ experience of the cart and checkout can be tailored to your project.

Using the cart in your templates
Dive into developing cart management experiences in Twig.

Use of carts and orders is deeply connected to other Commerce features like addresses, shipping, tax, and so on.

# Orders

An order is a type of element that underpins the shopping and checkout experience, in addition to supporting the wide array of content and query features. You can browse orders in the control panel by navigating to

  1. Commerce
  2. Orders
.

When a cart becomes an order, the following things happen:

  1. The dateOrdered order attribute is set to the current date.
  2. The isCompleted order attribute is set to true.
  3. The default order status is set on the order and any emails for this status are sent.
  4. The order reference number is generated for the order, based on the Order Reference Number Format setting for the store it was placed in.

Instead of being recalculated on each change like a cart, the order will only be recalculated if you manually trigger recalculation.

Adjustments for discounts, shipping, and tax may be applied when an order is recalculated. Each adjustment is related to its order, and can optionally relate to a specific line item.

If you’d like to jump straight to displaying order information in your templates, check out the cart and orders development sections, then review the craft\commerce\elements\Order (opens new window) class reference for a complete list of available methods and properties.

# Order Numbers

There are three ways to identify an order: by order number, short order number, and order reference number.

# Order Number

The order number is a 32-character, alphanumeric hash generated when the cart cookie is first created. It exists even before the cart is saved in the database, and remains the same for the entire life of the order. Order numbers are not sequential!

{{ order.number }}
{# -> 706ffb9c4fa439977908f6a4ad0287af #}

This is different from the order reference number, which is only generated after a cart has been completed and becomes an order.

Use the order number in situations where orders are displayed without authentication—like in a route segment for a template that displays order details after checkout. See the development page for an example of a route and template used to display guest orders.

# Short Order Number

The short order number is the first seven characters of the order number. This is short enough to still be (statistically) unique, but marginally easier for customers to process—although not as friendly as the order reference number.

{{ order.shortNumber }}
{# -> 706ffb9 #}

# Order Reference

The order reference is generated upon completing a cart using the store’s Order Reference Number Format in

  1. Commerce
  2. System Settings
  3. Stores
. It is intended to be a customer-facing alternative to the 32-digit alphanumeric order number.

{{ order.reference }}

The “Order Reference Number Format” is an object template that’s rendered when the order is completed. It can use order attributes along with Twig filters and functions. For example:

{{ dateCompleted|date('Y') }}-{{ id }}

Output:

2024-43

In this example, {{ id }} refers to the order’s element ID, which is not necessarily sequential (nor predictable in length). If you would rather generate a unique sequential number, a simple way would be to use Craft’s seq() Twig function, which returns the next unique number based on the name parameter passed to it.

The seq() function takes the following parameters:

  1. A key name. If this name is changed, a new sequence starting at one is started.
  2. An optional padding character length. For example if the next sequence number is 14 and the padding length is 8, the output will always be at least that many characters: 00000014. You can change the padding value without disrupting the sequence.

For example:

{{ dateCompleted|date('Y') }}-{{ seq(dateCompleted|date('Y'), 8) }}

Output:

2024-00000023

In this example we’ve used the current year as the sequence name so we automatically get a new sequence, starting at 1, when the next year arrives. You could use the store’s handle (like seq("store-order-#{store.handle}")) to keep sequences unique per-store, or a static key (like seq('order-number')) if you want all orders to occupy the same sequential space.

Sequences are global, so constructing keys that will not collide with others you may use in other fields or templates is essential to avoid gaps.

Order references cannot be relied upon for sorting. Use .orderBy('dateCompleted DESC') if you wish to display orders in reverse-chronological order.

# Creating Orders

An order is typically created when a customer adds items to their cart and then checks out. Orders can also be created in the control panel by users with the “Manage Orders” permission.

To create a new order, navigate to

  1. Commerce
  2. Orders
, and choose New Order. This will create a new order that behaves like a cart—as line items are added to and removed from the order, it will automatically recalculate totals and apply matching discounts and other adjustments. Select a customer and populate the Billing Address and Shipping Address to ensure prices (including tax and shipping) can be calculated accurately.

To complete the order, press Mark as completed.

# Custom Line Items 5.1.0+

In addition to selecting from the store’s available purchasables, store managers can create ad-hoc custom line items to represent one-off fees or other order contents.

Custom line items behave exactly the same as line items based on a purchasable, except that their type property is custom, and they do not track a purchasableId. Therefore, their other attributes are never be “refreshed” from a purchasable, they will never be “out of stock,” and they will not be part of the pricing catalog.

Shipping, tax, and other adjustments can still affect custom line items! Any rules and conditions that specify product types, relationships, or other qualities that depend on a preexisting purchasable will never match a custom line item.

# Editing Orders

Completed orders can be edited in the control panel by visiting the order edit page and choosing Edit.

While editing the order, it will refresh subtotals and totals and display any errors. It will not automatically recalculate the order based on system rules like shipping, taxes, or promotions. Choose Recalculate order to have it fully recalculate including those system rules.

Once you’re happy with your changes, choose Update Order to save it to the database. Updating an order after it is completed does not automatically charge or refund the customer! You must take these actions explicitly via the Transactions tab.

# Order Totals

Every order includes a few important totals:

  • order.itemSubtotal is the sum of the order’s line item subtotal amounts.
  • order.itemTotal is the sum of the order’s line item total amounts.
  • order.adjustmentsTotal is the sum of the order’s adjustments.
  • order.total is the sum of the order’s itemSubtotal and adjustmentsTotal.
  • order.totalPrice is the total order price with a minimum enforced by the Minimum Total Price Strategy store setting.

Note that total can be negative!

# Recalculating Orders

Let’s take a closer look at how carts and orders are recalculated.

A cart or order is always in one of three calculation modes:

  • Recalculate All — Active for incomplete carts and orders. This mode refreshes each line item’s details from the related purchasable and re-applies all adjustments to the cart. In other words, it rebuilds and recalculates cart details based on information from purchasables and how Commerce is configured. This mode merges duplicate line items and removes any that are out of stock or whose purchasables were deleted.
  • Adjustments Only doesn’t touch line items, but re-applies adjustments on the cart or order. This can only be set programmatically and is not available from the control panel.
  • None — Skips recalculation entirely; active only on completed orders. Only manual edits or admin-initiated recalculation can modify order details.

Cart/order subtotals and totals are computed values that always reflect the sum of line items. A few examples are totalPrice, itemTotal, and itemSubtotal.

You can manually recalculate an order by choosing “Recalculate order” at the bottom of the order edit screen:

This will set temporarily the order’s calculation mode to Recalculate All and trigger recalculation. You can then apply the resulting changes to the order by choosing “Update Order”, or discard them by choosing “Cancel”.

# Order Notices

Notices are added to carts and orders in circumstances where it or the store’s state results in unexpected changes:

  • A previously-valid coupon or shipping method was removed from the order;
  • A line item’s purchasable was no longer available so that line item was removed from the cart;
  • A line item’s sale price changed for some reason, like a sale ending;

Each notice is an OrderNotice (opens new window) model, containing a customer-facing description of what changed, and a corresponding craft\commerce\elements\Order (opens new window) attribute.

Order Notices in Twig
Learn about how to display and dismiss notices in your storefront.

# Statuses

When a cart is completed, it is assigned the default order status for the store it was placed in, and any relevant emails are sent via the queue.

Order Statuses
Design a custom order management workflow for your store.

# Status Emails

If status emails are set up for a newly-updated order status, messages will be sent when the updated order is saved.

You can manually re-send an order status email at any time. Navigate to an order’s edit screen, then select the desired email from the Send Email menu in the toolbar.

# Querying Orders

You can fetch carts and orders in your templates or PHP code using order queries.

{# Create a new order query #}
{% set myOrderQuery = craft.orders() %}

Once you’ve created the query, you can set parameters on it to narrow down the results, and then execute it by calling .one() or .all() to return one or more order elements.

See Element Queries in the Craft docs to learn about how element queries work.

The customer’s current cart is accessible in most Twig contexts via craft.commerce.carts.cart. In some situations (like order status emails), an order variable will be automatically populated with the correct order. Ad-hoc queries are typically only necessary when displaying inactive carts, a customer’s order history, or for generating custom reports.

# Example

We can display an order with a given order number by doing the following:

  1. Create an order query with craft.orders().
  2. Set the number parameter on it.
  3. Fetch the order with .one().
  4. Output information about the order as HTML.
{# Get the requested order number from the query string #}
{% set orderNumber = craft.app.request.getQueryParam('number') %}

{# Create an order query with the 'number' parameter #}
{% set myOrderQuery = craft.orders()
  .number(orderNumber) %}

{# Fetch the order #}
{% set order = myOrderQuery.one() %}

{# Make sure it exists #}
{% if not order %}
  {% exit 404 %}
{% endif %}

{# Display the order #}
<h1>Order {{ order.getShortNumber() }}</h1>
<!-- ... -->

# Order Query Parameters

Order queries support the following parameters:

Param Description
afterPopulate Performs any post-population processing on elements.
andNotRelatedTo Narrows the query results to only orders that are not related to certain other elements.
andRelatedTo Narrows the query results to only orders that are related to certain other elements.
asArray Causes the query to return matching orders as arrays of data, rather than Order (opens new window) objects.
cache Enables query cache for this Query.
clearCachedResult Clears the cached result (opens new window).
customer Narrows the query results based on the customer’s user account.
customerId Narrows the query results based on the customer, per their user ID.
dateAuthorized Narrows the query results based on the orders’ authorized dates.
dateCreated Narrows the query results based on the orders’ creation dates.
dateOrdered Narrows the query results based on the orders’ completion dates.
datePaid Narrows the query results based on the orders’ paid dates.
dateUpdated Narrows the query results based on the orders’ last-updated dates.
eagerly Causes the query to be used to eager-load results for the query’s source element and any other elements in its collection.
email Narrows the query results based on the customers’ email addresses.
expiryDate Narrows the query results based on the orders’ expiry dates.
fixedOrder Causes the query results to be returned in the order specified by id.
gateway Narrows the query results based on the gateway.
gatewayId Narrows the query results based on the gateway, per its ID.
hasLineItems Narrows the query results to only orders that have line items.
hasPurchasables Narrows the query results to only orders that have certain purchasables.
hasTransactions Narrows the query results to only carts that have at least one transaction.
id
ignorePlaceholders Causes the query to return matching orders as they are stored in the database, ignoring matching placeholder elements that were set by craft\services\Elements::setPlaceholderElement() (opens new window).
inBulkOp Narrows the query results to only orders that were involved in a bulk element operation.
inReverse Causes the query results to be returned in reverse order.
isCompleted Narrows the query results to only orders that are completed.
isPaid Narrows the query results to only orders that are paid.
isUnpaid Narrows the query results to only orders that are not paid.
itemSubtotal Narrows the query results based on the order’s item subtotal.
itemTotal Narrows the query results based on the order’s item total.
language Determines which site(s) the orders should be queried in, based on their language.
limit Determines the number of orders that should be returned.
notRelatedTo Narrows the query results to only orders that are not related to certain other elements.
number Narrows the query results based on the order number.
offset Determines how many orders should be skipped in the results.
orderBy Determines the order that the orders should be returned in. (If empty, defaults to id ASC.)
orderLanguage Narrows the query results based on the order language, per the language string provided.
orderSiteId Narrows the query results based on the order language, per the language string provided.
orderStatus Narrows the query results based on the order statuses.
orderStatusId Narrows the query results based on the order statuses, per their IDs.
origin Narrows the query results based on the origin.
preferSites If unique() (opens new window) is set, this determines which site should be selected when querying multi-site elements.
prepForEagerLoading Prepares the query for lazy eager loading.
prepareSubquery Prepares the element query and returns its subquery (which determines what elements will be returned).
reference Narrows the query results based on the order reference.
relatedTo Narrows the query results to only orders that are related to certain other elements.
render Executes the query and renders the resulting elements using their partial templates.
search Narrows the query results to only orders that match a search query.
shippingMethodHandle Narrows the query results based on the shipping method handle.
shortNumber Narrows the query results based on the order short number.
siteSettingsId Narrows the query results based on the orders’ IDs in the elements_sites table.
storeId Narrows the query results to only orders that are related to the given store.
total Narrows the query results based on the total.
totalDiscount Narrows the query results based on the total discount.
totalPaid Narrows the query results based on the total paid amount.
totalPrice Narrows the query results based on the total price.
totalQty Narrows the query results based on the total qty of items.
totalTax Narrows the query results based on the total tax.
totalWeight Narrows the query results based on the total weight of items.
trashed Narrows the query results to only orders that have been soft-deleted.
uid Narrows the query results based on the orders’ UIDs.
wasCountEagerLoaded Returns whether the query result count was already eager loaded by the query's source element.
wasEagerLoaded Returns whether the query results were already eager loaded by the query's source element.
with Causes the query to return matching orders eager-loaded with related elements.
withAddresses Eager loads the shipping and billing addressees on the resulting orders.
withAdjustments Eager loads the order adjustments on the resulting orders.
withAll Eager loads all relational data (addresses, adjustments, customers, line items, transactions) for the resulting orders.
withCustomFields Sets whether custom fields should be factored into the query.
withCustomer Eager loads the user on the resulting orders.
withLineItems Eager loads the line items on the resulting orders.
withTransactions Eager loads the transactions on the resulting orders.

# afterPopulate

Performs any post-population processing on elements.

# andNotRelatedTo

Narrows the query results to only orders that are not related to certain other elements.

See Relations (opens new window) for a full explanation of how to work with this parameter.

{# Fetch all orders that are related to myCategoryA and not myCategoryB #}
{% set orders = craft.orders()
  .relatedTo(myCategoryA)
  .andNotRelatedTo(myCategoryB)
  .all() %}

# andRelatedTo

Narrows the query results to only orders that are related to certain other elements.

See Relations (opens new window) for a full explanation of how to work with this parameter.

{# Fetch all orders that are related to myCategoryA and myCategoryB #}
{% set orders = craft.orders()
  .relatedTo(myCategoryA)
  .andRelatedTo(myCategoryB)
  .all() %}

# asArray

Causes the query to return matching orders as arrays of data, rather than Order (opens new window) objects.

{# Fetch orders as arrays #}
{% set orders = craft.orders()
  .asArray()
  .all() %}

# cache

Enables query cache for this Query.

# clearCachedResult

Clears the cached result (opens new window).

# customer

Narrows the query results based on the customer’s user account.

Possible values include:

Value Fetches orders…
1 with a customer with a user account ID of 1.
a User (opens new window) object with a customer with a user account represented by the object.
'not 1' not the user account with an ID 1.
[1, 2] with an user account ID of 1 or 2.
['not', 1, 2] not with a user account ID of 1 or 2.
{# Fetch the current user's orders #}
{% set orders = craft.orders()
  .customer(currentUser)
  .all() %}

# customerId

Narrows the query results based on the customer, per their user ID.

Possible values include:

Value Fetches orders…
1 with a user with an ID of 1.
'not 1' not with a user with an ID of 1.
[1, 2] with a user with an ID of 1 or 2.
['not', 1, 2] not with a user with an ID of 1 or 2.
{# Fetch the current user's orders #}
{% set orders = craft.orders()
  .customerId(currentUser.id)
  .all() %}

# dateAuthorized

Narrows the query results based on the orders’ authorized dates.

Possible values include:

Value Fetches orders…
'>= 2018-04-01' that were authorized on or after 2018-04-01.
'< 2018-05-01' that were authorized before 2018-05-01
['and', '>= 2018-04-04', '< 2018-05-01'] that were completed between 2018-04-01 and 2018-05-01.
{# Fetch orders that were authorized recently #}
{% set aWeekAgo = date('7 days ago')|atom %}

{% set orders = craft.orders()
  .dateAuthorized(">= #{aWeekAgo}")
  .all() %}

# dateCreated

Narrows the query results based on the orders’ creation dates.

Possible values include:

Value Fetches orders…
'>= 2018-04-01' that were created on or after 2018-04-01.
'< 2018-05-01' that were created before 2018-05-01.
['and', '>= 2018-04-04', '< 2018-05-01'] that were created between 2018-04-01 and 2018-05-01.
now/today/tomorrow/yesterday that were created at midnight of the specified relative date.
{# Fetch orders created last month #}
{% set start = date('first day of last month')|atom %}
{% set end = date('first day of this month')|atom %}

{% set orders = craft.orders()
  .dateCreated(['and', ">= #{start}", "< #{end}"])
  .all() %}

# dateOrdered

Narrows the query results based on the orders’ completion dates.

Possible values include:

Value Fetches orders…
'>= 2018-04-01' that were completed on or after 2018-04-01.
'< 2018-05-01' that were completed before 2018-05-01
['and', '>= 2018-04-04', '< 2018-05-01'] that were completed between 2018-04-01 and 2018-05-01.
{# Fetch orders that were completed recently #}
{% set aWeekAgo = date('7 days ago')|atom %}

{% set orders = craft.orders()
  .dateOrdered(">= #{aWeekAgo}")
  .all() %}

# datePaid

Narrows the query results based on the orders’ paid dates.

Possible values include:

Value Fetches orders…
'>= 2018-04-01' that were paid on or after 2018-04-01.
'< 2018-05-01' that were paid before 2018-05-01
['and', '>= 2018-04-04', '< 2018-05-01'] that were completed between 2018-04-01 and 2018-05-01.
{# Fetch orders that were paid for recently #}
{% set aWeekAgo = date('7 days ago')|atom %}

{% set orders = craft.orders()
  .datePaid(">= #{aWeekAgo}")
  .all() %}

# dateUpdated

Narrows the query results based on the orders’ last-updated dates.

Possible values include:

Value Fetches orders…
'>= 2018-04-01' that were updated on or after 2018-04-01.
'< 2018-05-01' that were updated before 2018-05-01.
['and', '>= 2018-04-04', '< 2018-05-01'] that were updated between 2018-04-01 and 2018-05-01.
now/today/tomorrow/yesterday that were updated at midnight of the specified relative date.
{# Fetch orders updated in the last week #}
{% set lastWeek = date('1 week ago')|atom %}

{% set orders = craft.orders()
  .dateUpdated(">= #{lastWeek}")
  .all() %}

# eagerly

Causes the query to be used to eager-load results for the query’s source element and any other elements in its collection.

# email

Narrows the query results based on the customers’ email addresses.

Possible values include:

Value Fetches orders with customers…
'foo@bar.baz' with an email of foo@bar.baz.
'not foo@bar.baz' not with an email of foo@bar.baz.
'*@bar.baz' with an email that ends with @bar.baz.
{# Fetch orders from customers with a .co.uk domain on their email address #}
{% set orders = craft.orders()
  .email('*.co.uk')
  .all() %}

# expiryDate

Narrows the query results based on the orders’ expiry dates.

Possible values include:

Value Fetches orders…
'>= 2020-04-01' that will expire on or after 2020-04-01.
'< 2020-05-01' that will expire before 2020-05-01
['and', '>= 2020-04-04', '< 2020-05-01'] that will expire between 2020-04-01 and 2020-05-01.
{# Fetch orders expiring this month #}
{% set nextMonth = date('first day of next month')|atom %}

{% set orders = craft.orders()
  .expiryDate("< #{nextMonth}")
  .all() %}

# fixedOrder

Causes the query results to be returned in the order specified by id.

If no IDs were passed to id, setting this to true will result in an empty result set.

{# Fetch orders in a specific order #}
{% set orders = craft.orders()
  .id([1, 2, 3, 4, 5])
  .fixedOrder()
  .all() %}

# gateway

Narrows the query results based on the gateway.

Possible values include:

Value Fetches orders…
a Gateway (opens new window) object with a gateway represented by the object.

# gatewayId

Narrows the query results based on the gateway, per its ID.

Possible values include:

Value Fetches orders…
1 with a gateway with an ID of 1.
'not 1' not with a gateway with an ID of 1.
[1, 2] with a gateway with an ID of 1 or 2.
['not', 1, 2] not with a gateway with an ID of 1 or 2.

# hasLineItems

Narrows the query results to only orders that have line items.

{# Fetch orders that do or do not have line items #}
{% set orders = craft.orders()
  .hasLineItems()
  .all() %}

# hasPurchasables

Narrows the query results to only orders that have certain purchasables.

Possible values include:

Value Fetches orders…
a PurchasableInterface (opens new window) object with a purchasable represented by the object.
an array of PurchasableInterface (opens new window) objects with all the purchasables represented by the objects.

# hasTransactions

Narrows the query results to only carts that have at least one transaction.

{# Fetch carts that have attempted payments #}
{% set orders = craft.orders()
  .hasTransactions()
  .all() %}

# id

# ignorePlaceholders

Causes the query to return matching orders as they are stored in the database, ignoring matching placeholder elements that were set by craft\services\Elements::setPlaceholderElement() (opens new window).

# inBulkOp

Narrows the query results to only orders that were involved in a bulk element operation.

# inReverse

Causes the query results to be returned in reverse order.

{# Fetch orders in reverse #}
{% set orders = craft.orders()
  .inReverse()
  .all() %}

# isCompleted

Narrows the query results to only orders that are completed.

{# Fetch completed orders #}
{% set orders = craft.orders()
  .isCompleted()
  .all() %}

# isPaid

Narrows the query results to only orders that are paid.

{# Fetch paid orders #}
{% set orders = craft.orders()
  .isPaid()
  .all() %}

# isUnpaid

Narrows the query results to only orders that are not paid.

{# Fetch unpaid orders #}
{% set orders = craft.orders()
  .isUnpaid()
  .all() %}

# itemSubtotal

Narrows the query results based on the order’s item subtotal.

Possible values include:

Value Fetches orders…
100 with an item subtotal of 0.
'< 1000000' with an item subtotal of less than ,000,000.
['>= 10', '< 100'] with an item subtotal of between and 0.

# itemTotal

Narrows the query results based on the order’s item total.

Possible values include:

Value Fetches orders…
100 with an item total of 0.
'< 1000000' with an item total of less than ,000,000.
['>= 10', '< 100'] with an item total of between and 0.

# language

Determines which site(s) the orders should be queried in, based on their language.

Possible values include:

Value Fetches orders…
'en' from sites with a language of en.
['en-GB', 'en-US'] from sites with a language of en-GB or en-US.
['not', 'en-GB', 'en-US'] not in sites with a language of en-GB or en-US.

Elements that belong to multiple sites will be returned multiple times by default. If you only want unique elements to be returned, use unique() (opens new window) in conjunction with this.

{# Fetch orders from English sites #}
{% set orders = craft.orders()
  .language('en')
  .all() %}

# limit

Determines the number of orders that should be returned.

{# Fetch up to 10 orders  #}
{% set orders = craft.orders()
  .limit(10)
  .all() %}

# notRelatedTo

Narrows the query results to only orders that are not related to certain other elements.

See Relations (opens new window) for a full explanation of how to work with this parameter.

{# Fetch all orders that are related to myEntry #}
{% set orders = craft.orders()
  .notRelatedTo(myEntry)
  .all() %}

# number

Narrows the query results based on the order number.

Possible values include:

Value Fetches orders…
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' with a matching order number
{# Fetch the requested order #}
{% set orderNumber = craft.app.request.getQueryParam('number') %}
{% set order = craft.orders()
  .number(orderNumber)
  .one() %}

# offset

Determines how many orders should be skipped in the results.

{# Fetch all orders except for the first 3 #}
{% set orders = craft.orders()
  .offset(3)
  .all() %}

# orderBy

Determines the order that the orders should be returned in. (If empty, defaults to id ASC.)

{# Fetch all orders in order of date created #}
{% set orders = craft.orders()
  .orderBy('dateCreated ASC')
  .all() %}

# orderLanguage

Narrows the query results based on the order language, per the language string provided.

Possible values include:

Value Fetches orders…
'en' with an order language that is 'en'.
'not en' not with an order language that is not 'en'.
['en', 'en-us'] with an order language that is 'en' or 'en-us'.
['not', 'en'] not with an order language that is not 'en'.
{# Fetch orders with an order language that is `'en'` #}
{% set orders = craft.orders()
  .orderLanguage('en')
  .all() %}

# orderSiteId

Narrows the query results based on the order language, per the language string provided.

Possible values include:

Value Fetches orders…
1 with an order site ID of 1.
'not 1' not with an order site ID that is no 1.
[1, 2] with an order site ID of 1 or 2.
['not', 1, 2] not with an order site ID of 1 or 2.
{# Fetch orders with an order site ID of 1 #}
{% set orders = craft.orders()
  .orderSiteId(1)
  .all() %}

# orderStatus

Narrows the query results based on the order statuses.

Possible values include:

Value Fetches orders…
'foo' with an order status with a handle of foo.
'not foo' not with an order status with a handle of foo.
['foo', 'bar'] with an order status with a handle of foo or bar.
['not', 'foo', 'bar'] not with an order status with a handle of foo or bar.
a OrderStatus (opens new window) object with an order status represented by the object.
{# Fetch shipped orders #}
{% set orders = craft.orders()
  .orderStatus('shipped')
  .all() %}

# orderStatusId

Narrows the query results based on the order statuses, per their IDs.

Possible values include:

Value Fetches orders…
1 with an order status with an ID of 1.
'not 1' not with an order status with an ID of 1.
[1, 2] with an order status with an ID of 1 or 2.
['not', 1, 2] not with an order status with an ID of 1 or 2.
{# Fetch orders with an order status with an ID of 1 #}
{% set orders = craft.orders()
  .orderStatusId(1)
  .all() %}

# origin

Narrows the query results based on the origin.

Possible values include:

Value Fetches orders…
'web' with an origin of web.
'not remote' not with an origin of remote.
['web', 'cp'] with an order origin of web or cp.
['not', 'remote', 'cp'] not with an origin of web or cp.
{# Fetch shipped orders #}
{% set orders = craft.orders()
  .origin('web')
  .all() %}

# preferSites

If unique() (opens new window) is set, this determines which site should be selected when querying multi-site elements.

For example, if element “Foo” exists in Site A and Site B, and element “Bar” exists in Site B and Site C, and this is set to ['c', 'b', 'a'], then Foo will be returned for Site B, and Bar will be returned for Site C.

If this isn’t set, then preference goes to the current site.

{# Fetch unique orders from Site A, or Site B if they don’t exist in Site A #}
{% set orders = craft.orders()
  .site('*')
  .unique()
  .preferSites(['a', 'b'])
  .all() %}

# prepForEagerLoading

Prepares the query for lazy eager loading.

# prepareSubquery

Prepares the element query and returns its subquery (which determines what elements will be returned).

# reference

Narrows the query results based on the order reference.

Possible values include:

Value Fetches orders…
'Foo' with a reference of Foo.
'Foo*' with a reference that begins with Foo.
'*Foo' with a reference that ends with Foo.
'*Foo*' with a reference that contains Foo.
'not *Foo*' with a reference that doesn’t contain Foo.
['*Foo*', '*Bar*'] with a reference that contains Foo or Bar.
['not', '*Foo*', '*Bar*'] with a reference that doesn’t contain Foo or Bar.
{# Fetch the requested order #}
{% set orderReference = craft.app.request.getQueryParam('ref') %}
{% set order = craft.orders()
  .reference(orderReference)
  .one() %}

# relatedTo

Narrows the query results to only orders that are related to certain other elements.

See Relations (opens new window) for a full explanation of how to work with this parameter.

{# Fetch all orders that are related to myCategory #}
{% set orders = craft.orders()
  .relatedTo(myCategory)
  .all() %}

# render

Executes the query and renders the resulting elements using their partial templates.

If no partial template exists for an element, its string representation will be output instead.

Narrows the query results to only orders that match a search query.

See Searching (opens new window) for a full explanation of how to work with this parameter.

{# Get the search query from the 'q' query string param #}
{% set searchQuery = craft.app.request.getQueryParam('q') %}

{# Fetch all orders that match the search query #}
{% set orders = craft.orders()
  .search(searchQuery)
  .all() %}

# shippingMethodHandle

Narrows the query results based on the shipping method handle.

Possible values include:

Value Fetches orders…
'foo' with a shipping method with a handle of foo.
'not foo' not with a shipping method with a handle of foo.
['foo', 'bar'] with a shipping method with a handle of foo or bar.
['not', 'foo', 'bar'] not with a shipping method with a handle of foo or bar.
a \craft\commerce\elements\db\ShippingMethod object with a shipping method represented by the object.
{# Fetch collection shipping method orders #}
{% set orders = craft.orders()
  .shippingMethodHandle('collection')
  .all() %}

# shortNumber

Narrows the query results based on the order short number.

Possible values include:

Value Fetches orders…
'xxxxxxx' with a matching order number
{# Fetch the requested order #}
{% set orderNumber = craft.app.request.getQueryParam('shortNumber') %}
{% set order = craft.orders()
  .shortNumber(orderNumber)
  .one() %}

# siteSettingsId

Narrows the query results based on the orders’ IDs in the elements_sites table.

Possible values include:

Value Fetches orders…
1 with an elements_sites ID of 1.
'not 1' not with an elements_sites ID of 1.
[1, 2] with an elements_sites ID of 1 or 2.
['not', 1, 2] not with an elements_sites ID of 1 or 2.
{# Fetch the order by its ID in the elements_sites table #}
{% set order = craft.orders()
  .siteSettingsId(1)
  .one() %}

# storeId

Narrows the query results to only orders that are related to the given store.

Possible values include:

Value Fetches orders…
1 with a storeId of 1.

# total

Narrows the query results based on the total.

Possible values include:

Value Fetches orders…
10 with a total price of .
['and', 10, 20] an order with a total of or .

# totalDiscount

Narrows the query results based on the total discount.

Possible values include:

Value Fetches orders…
10 with a total discount of 10.
[10, 20] an order with a total discount of 10 or 20.

# totalPaid

Narrows the query results based on the total paid amount.

Possible values include:

Value Fetches orders…
10 with a total paid amount of .
['and', 10, 20] an order with a total paid amount of or .

# totalPrice

Narrows the query results based on the total price.

Possible values include:

Value Fetches orders…
10 with a total price of .
['and', 10, 20] an order with a total price of or .

# totalQty

Narrows the query results based on the total qty of items.

Possible values include:

Value Fetches orders…
10 with a total qty of 10.
[10, 20] an order with a total qty of 10 or 20.

# totalTax

Narrows the query results based on the total tax.

Possible values include:

Value Fetches orders…
10 with a total tax of 10.
[10, 20] an order with a total tax of 10 or 20.

# totalWeight

Narrows the query results based on the total weight of items.

Possible values include:

Value Fetches orders…
10 with a total weight of 10.
[10, 20] an order with a total weight of 10 or 20.

# trashed

Narrows the query results to only orders that have been soft-deleted.

{# Fetch trashed orders #}
{% set orders = craft.orders()
  .trashed()
  .all() %}

# uid

Narrows the query results based on the orders’ UIDs.

{# Fetch the order by its UID #}
{% set order = craft.orders()
  .uid('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')
  .one() %}

# wasCountEagerLoaded

Returns whether the query result count was already eager loaded by the query's source element.

# wasEagerLoaded

Returns whether the query results were already eager loaded by the query's source element.

# with

Causes the query to return matching orders eager-loaded with related elements.

See Eager-Loading Elements (opens new window) for a full explanation of how to work with this parameter.

{# Fetch orders eager-loaded with the "Related" field’s relations #}
{% set orders = craft.orders()
  .with(['related'])
  .all() %}

# withAddresses

Eager loads the shipping and billing addressees on the resulting orders.

Possible values include:

Value Fetches addresses
bool true to eager-load, false to not eager load.

# withAdjustments

Eager loads the order adjustments on the resulting orders.

Possible values include:

Value Fetches adjustments
bool true to eager-load, false to not eager load.

# withAll

Eager loads all relational data (addresses, adjustments, customers, line items, transactions) for the resulting orders.

Possible values include:

Value Fetches addresses, adjustments, customers, line items, transactions
bool true to eager-load, false to not eager load.

# withCustomFields

Sets whether custom fields should be factored into the query.

# withCustomer

Eager loads the user on the resulting orders.

Possible values include:

Value Fetches adjustments
bool true to eager-load, false to not eager load.

# withLineItems

Eager loads the line items on the resulting orders.

Possible values include:

Value Fetches line items
bool true to eager-load, false to not eager load.

# withTransactions

Eager loads the transactions on the resulting orders.

Possible values include:

Value Fetches transactions…
bool true to eager-load, false to not eager load.
Parts of this page are generated or assembled by automations. While we greatly appreciate contributions to the documentation, reporting automated content issues will allow us to fix them at the source!