Controlling hook implementation order and priorityfor Drupal 8 , 9 , 10 , and 11

Last updated :  

Picture a dozen tenants in that same office building all receiving the exact same memo at the same time, and imagine you're the building manager who needs one tenant to read it before the others, or one tenant to be quietly skipped entirely for this particular memo. That's exactly the control hook_module_implements_alter() gives you over a regular hook — it doesn't change what any implementation does, it changes the guest list and the order they're called in.

What you'll learn in this lesson

  • Why the order hook implementations run in sometimes matters
  • How hook_module_implements_alter() lets you reorder or remove implementations for a specific hook
  • The &$implementations array's actual shape, and how to manipulate it safely

Why implementation order is sometimes a real problem

By default, Drupal calls hook implementations from different modules in the order those modules happen to be loaded — essentially alphabetical, with a few core-module exceptions. Most of the time this doesn't matter: your hook_node_view() implementation adds a sidebar block, mine adds a different one, and it makes no difference who runs first. But sometimes it does. A logging module's hook_form_alter() might need to run after a validation module's implementation has already reshaped the form, or you might need your module's cache-tag-adding hook to run last so it sees every tag added by everyone else first.

The hook that controls other hooks

/**
 * Implements hook_module_implements_alter().
 */
function example_module_module_implements_alter(&$implementations, $hook) {
  // Only touch the specific hook we care about — this alter fires for
  // *every* hook Drupal is about to invoke, so an unguarded change here
  // would affect the entire site, not just the one hook you meant to fix.
  if ($hook == 'form_alter') {
    // Move our own module's implementation to the very end of the list,
    // so it sees the form after every other module has already altered it.
    $group = $implementations['example_module'];
    unset($implementations['example_module']);
    $implementations['example_module'] = $group;
  }
}

The $implementations parameter arrives as an associative array keyed by module name, and PHP arrays preserve insertion order — which is exactly what Drupal iterates over to decide call order. Removing a key and re-adding it moves that module to the end; unsetting a key entirely removes that module's implementation from running at all for this specific hook invocation.

The $hook guard clause is not optional. This function runs once for every hook Drupal is about to invoke across the entire request lifecycle — omit the if ($hook == '...') check and you'll be reordering or dropping implementations for hooks you never intended to touch, which produces bugs that are miserable to trace back to their source.

Removing an implementation entirely

Sometimes the goal isn't reordering but suppression — a contributed module's hook_form_alter() implementation conflicts with something your site needs, and you don't have the option of patching that module's code. Unsetting its key from $implementations for that one hook stops it from running, without disabling the module or touching its files:

if ($hook == 'form_alter' && isset($implementations['some_conflicting_module'])) {
  unset($implementations['some_conflicting_module']);
}

Quick check: your hook_module_implements_alter() implementation reorders things for node_presave, but you're seeing it also affect user_login behavior on your site. What did you most likely forget? (Answer: the if ($hook == 'node_presave') guard — without it, every hook invocation runs through your alter logic, including ones you never meant to touch.)

Key takeaways

  • hook_module_implements_alter(&$implementations, $hook) runs before every single hook invocation site-wide — always guard your logic with an if ($hook == '...') check.
  • The $implementations array is keyed by module name; PHP's array insertion order is what determines call order.
  • Unset-then-reassign a key to move a module's implementation to the end; unset it permanently (for that hook) to suppress it entirely.
  • Reach for this hook only when call order or exclusion genuinely matters — reordering hooks you don't need to touch adds fragility for no benefit.

Coming up next

Now that you can control which implementations run and in what order, it's time to look at one of the single most widely implemented hooks in all of Drupal: Implementing hook_form_alter, which lets any module reach into any form on the site.