Change record status: 
Project: 
Introduced in branch: 
11.2.x
Introduced in version: 
11.2.0
Description: 

The #[Hook] attribute has an order argument to allow hook implementations to be ordered.

The order parameter accepts the following simple ordering options.
\Drupal\Core\Hook\Order\Order::First
\Drupal\Core\Hook\Order\Order::Last

The order parameter also accepts the following complex ordering options which also accept parameters.
\Drupal\Core\Hook\Order\OrderBefore
\Drupal\Core\Hook\Order\OrderAfter

OrderBefore() and OrderAfter() accept the following parameters:
modules: an array of modules to order before or after.
classesAndMethods: an array of arrays of classes and methods to order before or after.

See multiple ordering operations below for information on how multiple modules implementing Order::First is resolved.

Examples

Order the hook first

#[Hook('some_hook', order: Order::First)]

Order the hook last

#[Hook('some_hook', order: Order::Last)]

Order the hook before another module's implementation

#[Hook('some_hook', order: new OrderBefore(['other_module']))]

Order the hook after another module's implementation

#[Hook('some_hook', order: new OrderAfter(['other_module']))]

Order the hook before another module's implementation by specifying class and method

#[Hook('some_hook', 
  order: new OrderBefore(
    classesAndMethods: [
      [Foo::class, 'someMethod'],
      [Bar::class, 'someOtherMethod'],
    ]
  )
)]

Order the hook after another module's implementation by specifying class and method

#[Hook('some_hook', 
  order: new OrderAfter(
    classesAndMethods: [
      [Foo::class, 'someMethod'],
      [Bar::class, 'someOtherMethod'],
    ]
  )
)]

Multiple ordering operations

By default hooks are ordered in module order which is defined by module weight, then alphabetically.
Ordering operations are applied by module order as well. Reorder operations happen after all Order operations have been applied and they occur in module order as well.
Order operations are applied sequentially and apply to the current order. If multiple modules say they want their hook to run first, the one that is last in module order will be first.

For example if we have modules A, B, and C that implement some_hook.
Default order:

  • A::some_hook
  • B::some_hook
  • C::some_hook

If B and C both apply Order::First then the final order will be:

  • C::some_hook
  • B::some_hook
  • A::some_hook

We start with A, then B, then C. When B's order operation is applied B says it wants to be first so we get B, A, C. Then C's order operation is applied and C says it wants to be first so we end up with C, B, A.

hook_module_implements_alter

If you ordered your hooks using hook_module_implements_alter see hook_module_implements_alter requires the #[LegacyModuleImplementsAlter] attribute and ordering must be done using new functionality for more information.

Impacts: 
Module developers
Site templates, recipes and distribution developers