Order Configuration Hooks
The eight hooks on the screens where a customer makes choices while ordering: configuring, adding a domain, adding an add-on, and provisioning.
Overview
The configuration screen is where a customer shapes a product to suit them: the domain choice, add-ons, the term, custom fields. The hooks here touch both the screen and whether a choice is allowed.
The last hook differs: it runs after payment, immediately before the services are built. It is the final stop between an order line and a service.
Reference
Stopping a configuration
Runs before the configured product is written into the cart, with the choices already gathered.
none, owned, register, transfer, subdomain), the add-ons, the custom fields. Every choice the customer made is here.Hook::add('gate:order.item_configure', 10, function ($product, $cycle, $options) {
// Every choice sits in $options: check your business rule here.
if (($options['domain']['option'] ?? '') === 'owned'
&& !Acme::domainReachable($options['domain']['name'] ?? ''))
return 'The domain you entered cannot be reached.';
return null;
});Changing the configuration screen
Runs after the configuration page's data was built.
edit mark. A filled edit means the customer is editing a cart line rather than adding a new product.Hook::add('filter:order.configure_data', 10, function (&$data, $ctx) {
// A filled edit means they are editing a cart line, not adding a product.
if (!empty($ctx['edit'])) return;
$data['acme_hint'] = Acme::upsellHint((int) ($ctx['id'] ?? 0));
});Changing the add-on screen
Runs after the add-on purchase screen's data was built.
Hook::add('filter:order.configure_addon_data', 10, function (&$data, &$ctx) {
// The lists inside $ctx are COPIES: change $data instead.
$data['services'] = Acme::filterServices($data['services'] ?? []);
});Stopping a domain going in the cart
Runs before a domain is written into the cart.
register or transfer), the full name, its parts, the years. The years is always 1 here; the term changes during configuration.Hook::add('gate:order.domain_add', 10, function ($tldRow, $item) {
// An extra check on transfers; none needed on a registration.
if (($item['action'] ?? '') === 'transfer' && Acme::recentlyRegistered($item['domain'] ?? ''))
return 'A newly registered domain cannot transfer for 60 days.';
return null;
});Stopping an add-on going in the cart
Runs before an add-on is attached to a service, with ownership already confirmed.
select, radio, checkbox, quantity), status, properties.upgrade_of. Above zero, upgrade_of marks an upgrade of an existing add-on rather than a new purchase.Hook::add('gate:order.service_addon_add', 10, function ($service, $addon, $item) {
// Above zero, upgrade_of marks an UPGRADE, not a new purchase.
if ((int) ($item['upgrade_of'] ?? 0) > 0) return null;
if (($service['status'] ?? '') !== 'active')
return 'An add-on wants a live service to attach to.';
return null;
});Changing the services about to be built
Runs after payment, immediately before services are built from the order lines.
Hook::add('filter:order.services_items', 10, function (&$ctx, &$items) {
// DROPPING a line builds nothing: where the customer paid, make it good by hand.
foreach ($items as &$i)
$i['options']['acme_batch'] = Acme::batchFor((int) ($ctx['order_id'] ?? 0));
});Following an affiliate change
Runs after an order's affiliate changed.
0 means the affiliate was removed, not that a new one arrived.Hook::add('action:order.affiliate_changed', 10, function ($order_id, $affiliate_id) {
// 0 means the affiliate was REMOVED; the commission may want taking back.
if ($affiliate_id === 0) Acme::revokeCommission((int) $order_id);
});Following a service removed from an order
Runs after a service was removed from an order. The order record stays where it is.
Hook::add('action:order.service.deleted', 10, function ($order_id, $service_id) {
Audit::orderLineRemoved((int) $order_id, (int) $service_id);
});Pitfalls
The service-building filter runs after payment completed. Drop a line and that service is never built, while the customer has paid and the invoice stands. To prevent something, do it at the cart or checkout gate.
The second parameter is passed by reference and the lists inside it are copies: a change there never reaches the screen and your listener looks like it did nothing. What you mean to change is in the first parameter.
Where upgrade_of on the add-on line is above zero the customer is not buying something new but upgrading what they have. A rule saying "they already have this, block a second" also blocks the upgrade.
A filled edit in the screen filter's context means the customer is editing a cart line rather than adding a product. Showing an upsell or a welcome note in edit mode asks again about a choice they already made.
Related Articles
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.