Cart Hooks
Eight hooks from a customer filling a cart to the order being placed. The add gates, the pricing chain and the checkout step.
Overview
Cart pricing is a three-stage chain and each stage has its own filter. The raw inputs come first, then the priced lines, then the summary. Knowing the order puts your rule on the right link.
Picking the wrong link fails quietly. Change a total on the item filter and the summary works it out again, writing over you.
Reference
Stopping something going in the cart
Runs before the product is written into the cart, with the product and cycle already validated.
Hook::add('gate:order.cart_add', 10, function ($product, $cycle, $item) {
// The core checks stock; add your own business rule.
if (Acme::limitReached($product['id'] ?? 0))
return 'The daily order limit for this product is spent.';
return null;
});Changing the raw inputs
Runs on the raw order inputs, before pricing starts.
Hook::add('filter:order.cart_inputs', 10, function (&$inputs, $ucid) {
// The HEAD of the chain: a line added here gets priced by the core.
if (Acme::freeSslCampaign())
$inputs[] = ['group' => 'product', 'product_id' => Acme::SSL_ID, 'cycle' => 'annually'];
});Changing the priced lines
Runs after the lines were priced, before the summary is built.
Hook::add('filter:order.cart_items', 10,
function (&$items, $user_id, $user_currency, $dealership) {
// Change a line price here; the GRAND total is built in the next stage.
foreach ($items as &$i)
if (Acme::bundleEligible($i)) $i['price'] = Acme::bundlePrice($i);
});Changing the cart summary
Runs after the price summary was built — the final figures the customer sees are here.
Hook::add('filter:order.cart_totals', 10,
function (&$summary, $items, $subtotal, $selectedCoupons, $ctx) {
// The END of the chain: what you write here is what the customer sees.
if (Acme::minimumOrder() > (float) $summary['subtotal'])
$summary['acme_notice'] = Acme::minimumNotice();
});Stopping the checkout step
Runs before the order is placed. A guest never reaches here: the sign-in check runs earlier.
Hook::add('gate:order.checkout', 10, function ($member, $cartItems) {
// The lines are NOT priced yet: keep amount-based rules out of here.
if (Acme::fraudScore((int) ($member['id'] ?? 0)) > 80)
return 'Your order wants a review; our team will be in touch.';
return null;
});Learning that an order was placed
Runs after the order was placed. Its invoice is unpaid at this point.
Free; on a stored card the real gateway module's name.Hook::add('action:order.checkout_completed', 10,
function ($order_id, $invoice_id, $pmethod, $member) {
// The invoice is NOT paid yet: leave opening services to the payment hook.
Crm::orderPlaced($order_id, $pmethod, (string) ($member['email'] ?? ''));
});Changing the coupon discount
Runs after the coupon discount was worked out.
Hook::add('filter:order.coupon_discount', 10, function (&$discount) {
Acme::capCouponDiscount($discount);
});Changing the order number
Runs after the order number was produced.
Hook::add('filter:order.number', 10, function (&$number) {
// Uniqueness is YOURS to keep: a clash breaks the order.
$number = Acme::prefix() . '-' . $number;
});Pitfalls
Pricing runs in three stages: inputs, lines, summary. Touching the grand total at the line stage is wasted — the summary stage works it out again. A line price belongs on the item filter, a final figure on the summary filter, and a new product on the input filter.
The checkout gate hands you the raw cart lines: no amounts, discounts or tax yet. Writing "stop orders above this amount" here means reading a field that is not there.
On the order-completed hook the invoice is unpaid. Opening a service, switching an add-on on or delivering to the customer here means an order that never pays is delivered anyway.
The order number filter hands you a number already produced. Once you change it the core does not check it again: produce a clashing one and the order record breaks. Adding your own prefix is safe; producing the number from scratch is not.
Related Articles
- Order Flow Hooks
- Invoice Lifecycle Hooks
- Currency and Coupon Hooks
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.