Cart predicate language
Cart predicates are boolean expressions evaluated against the current resolved checkout context. A matching expression makes a rule eligible; it does not guarantee that the rule wins later discount, shipping, or gateway selection.
The full cart context is used by cart discounts, shipping methods, absolute and relative shipping-method rates, and payment gateways. A cart discount’s line-item target uses a smaller context documented separately below.
See Predicate language first for the common operators and authoring model.
Top-level cart fields
| Field | Type | Notes |
|---|---|---|
customer | customer | Always present; its strings are empty for an anonymous cart. |
shipping_address | address or null | Guard against null before reading nested fields. |
billing_address | address or null | Guard against null before reading nested fields. |
total | money | Current cart total. |
subtotal | money | Current cart subtotal. |
currency_code | string | Cart currency, for example EUR. |
store | store | Store context. |
price_channel | price channel | Price-channel context. |
line_items | collection of line items | Supports .any(...), .Contains(...) where applicable, and .count(). |
Customer, address, and money fields
Customer
customer.idcustomer.emailcustomer.groupcustomer.groups
Thor evaluates the full cart predicate once with an empty customer.group, then once for every group the customer belongs to. This preserves simple rules such as customer.group == "cusgrp_...". Prefer customer.groups.Contains("cusgrp_...") in new predicates because it expresses membership directly.
For anonymous carts, customer.id and customer.email are empty strings and customer.groups is empty; customer itself is not null.
Money
Both subtotal and total expose cent_amount and currency_code. Amounts are integer minor units and should normally be paired with a currency check when a rule can run in more than one currency.
Shipping and billing addresses expose the same fields:
| Field | Field | Field |
|---|---|---|
first_name | last_name | email |
phone | company | address1 |
address2 | city | zip_code |
province | state | country_code |
Country codes are stored as ISO 3166-1 alpha-2 strings such as DK and DE.
Store and price channel
store.idis a typed store ID with thestore_prefix.price_channel.idis a typed channel ID with thech_prefix.- If either context value is absent, its
idis an empty string rather thannull.
Line-item fields
Each entry in line_items exposes:
| Field | Type / nested fields |
|---|---|
line_item_id | Cart line-item ID (cli_...) |
currency_code | string |
quantity | integer |
amount.unit_price | cent_amount, currency_code |
amount.original_unit_price | cent_amount, currency_code |
variant | id, name, sku, weight_in_kg |
product | id, name, tags, categories, collections |
Each entry in product.categories and product.collections exposes id. Weight is a decimal number of kilograms. Unit prices are integer minor units.
Line-item target predicates
A cart discount can target selected line items with the predicate on LineItemTargetInput. This predicate is evaluated directly against each line item.
Therefore the root fields are line_item_id, currency_code, quantity, amount, variant, and product. Do not start with line_items.any(...); Thor is already iterating the cart’s line items. Give the target an explicit predicate. Use true when every line item should be eligible.
Typed ID prefixes in this context
| Resource | Prefix | Example |
|---|---|---|
| Customer | cus_ | cus_... |
| Customer group | cusgrp_ | cusgrp_... |
| Store | store_ | store_... |
| Price channel | ch_ | ch_... |
| Cart line item | cli_ | cli_... |
| Product | product_ | product_... |
| Product variant | vid_ | vid_... |
| Category | cat_ | cat_... |
| Collection | col_ | col_... |
See Typed IDs for the complete handling guidance.
Validation checklist
- Use snake_case property names and
==, not=or===. - Guard
shipping_addressandbilling_addressagainstnull. - Treat strings as case-sensitive; use uppercase currency and country codes.
- Compare monetary values in minor units and weights in kilograms.
- Use real typed IDs returned by Thor and the correct prefix, especially
ch_for channels andvid_for variants. - Test authenticated and anonymous carts, zero and multiple customer groups, missing addresses, and more than one line item.
- Remember that a matching predicate only makes a rule eligible; discount grouping, priority, availability, and later checkout selection still apply.