Order Configuration Hooks

276 visitas Markdown

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

gateorder.item_configure
ClientOrder the choices are gathered

Runs before the configured product is written into the cart, with the choices already gathered.

Parameters 3
$productarrayThe product record: id, type, name, add-ons, requirements, subdomains, options.
$cyclestringThe chosen billing cycle, already validated.
$optionsarrayThe gathered configuration, about to become the cart line's options: the domain choice (none, owned, register, transfer, subdomain), the add-ons, the custom fields. Every choice the customer made is here.
Return 1
stringA non-empty string stops the action; the text is shown to the customer as the error.
Listener
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

filterorder.configure_data
ClientOrder the whole page

Runs after the configuration page's data was built.

Parameters 2
$dataarrayrefThe page's whole template data: the product, the prices (raw amounts by cycle), the add-ons, the domain options. The prices arrive unformatted and are formatted on screen.
$ctxarrayThe context: the raw product record, its type, its id and the edit mark. A filled edit means the customer is editing a cart line rather than adding a new product.
Return 1
voidThe value changes by reference; the return is not read.
Listener
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

filterorder.configure_addon_data
ClientOrder the context is a copy

Runs after the add-on purchase screen's data was built.

Parameters 2
$dataarrayrefThe page's whole template data. This is the one to change.
$ctxarrayrefThe context: the raw add-on record, the service list and the options. The lists are copies: passed by reference and yet a change here never reaches the screen.
Return 1
voidThe value changes by reference; the return is not read.
Listener
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

gateorder.domain_add
ClientOrder the extension is validated

Runs before a domain is written into the cart.

Parameters 2
$tldRowarrayThe extension record: id, name, status, privacy, DNS management, forwarding add-ons. Already confirmed to be on sale.
$itemarrayThe line about to be written: the action (register or transfer), the full name, its parts, the years. The years is always 1 here; the term changes during configuration.
Return 1
stringA non-empty string stops the action; the text is shown to the customer as the error.
Listener
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

gateorder.service_addon_add
ClientOrder ownership is validated

Runs before an add-on is attached to a service, with ownership already confirmed.

Parameters 3
$servicearrayThe service the add-on attaches to: id, owner, product, type, status, term, due date.
$addonarrayThe add-on definition: id, name, type (select, radio, checkbox, quantity), status, properties.
$itemarrayThe line about to be written: the service, the add-on, the option, the quantity and upgrade_of. Above zero, upgrade_of marks an upgrade of an existing add-on rather than a new purchase.
Return 1
stringA non-empty string stops the action; the text is shown to the customer as the error.
Listener
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

filterorder.services_items
Orders::buildServices() the last stop before provisioning

Runs after payment, immediately before services are built from the order lines.

Parameters 2
$ctxarrayrefThe provisioning context: the order, the invoice, the owner, the currency, the status, the payment method, the languages, the time.
$itemsarrayrefThe product and domain lines about to be built. Dropping one here means that service is never built — even though the customer paid for it.
Return 1
voidThe value changes by reference; the return is not read.
Listener
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

actionorder.affiliate_changed
AdminOrders zero means removed

Runs after an order's affiliate changed.

Parameters 2
$order_idintThe order id.
$affiliate_idintThe new affiliate. 0 means the affiliate was removed, not that a new one arrived.
Return 1
voidThe return is ignored.
Listener
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

actionorder.service.deleted
AdminOrders the order stays

Runs after a service was removed from an order. The order record stays where it is.

Parameters 2
$order_idintThe order id.
$service_idintThe id of the removed service.
Return 1
voidThe return is ignored.
Listener
Hook::add('action:order.service.deleted', 10, function ($order_id, $service_id) {
    Audit::orderLineRemoved((int) $order_id, (int) $service_id);
});

Pitfalls

Dropping a line at provisioning refunds nothing

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.

On the add-on screen the context is a copy

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.

Adding an add-on can be an upgrade

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.

The configuration screen also opens in edit mode

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.

¿Le ha resultado útil?

¡Gracias por sus comentarios!

¿Todavía necesita ayuda?

Nuestro equipo de soporte está disponible las 24 horas para ayudarle con lo que no encuentre aquí.