Hook

A hook is a named extension point that lets a module add to or change Drupal's behavior without editing core or another module's code.

Learn DrupalDrupal glossary

A hook is a named extension point in Drupal. When Drupal reaches that point, for example when a node is deleted or a form is about to be shown, it asks every enabled module whether it has an implementation, and runs each one it finds. Modules use hooks to add to or change what core and other modules do, without editing their code.

How hooks work in Drupal 11

Each hook has a name, a fixed list of parameters and a defined return value. The documentation names a hook with the prefix hook_, such as hook_form_alter. Core documents its hooks in the Hooks topic on api.drupal.org and in *.api.php files, and a module can define hooks of its own for other modules to use.

Drupal 11.1 introduced object-oriented hook implementations. You write a class in the Drupal\my_module\Hook namespace and mark a method with the Drupal\Core\Hook\Attribute\Hook attribute. The attribute takes the short hook name without the hook_ prefix. Classes in that namespace are registered as autowired services, so you can inject what you need through the constructor. The method name is free, but the parameters must match the hook.

The older procedural style still works. You put a function in the module's .module file, named after the module and the hook, so hook_form_alter in a module called my_module becomes my_module_form_alter(). Some hooks stay procedural, including install, update, schema and uninstall hooks, hook_hook_info() and hook_module_implements_alter().

Code that wants to call a hook uses the module handler service: invoke() and invokeAll() collect results, and alter() lets every module change a piece of data. A module can also be a hook author. It picks a unique name that starts with the module name, documents the hook in an .api.php file and calls it.

Order of implementations

Implementations run by module weight, lower numbers first, and modules with the same weight run alphabetically by machine name. Drupal 11.2 added an order argument on #[Hook]. The #[ReorderHook] and #[RemoveHook] attributes change the order of another module's implementation or skip it. Before 11.2 you used hook_module_implements_alter().

How a Drupal hook runsDrupal reaches an extension point, asks every enabled module for an implementation, and runs each one it finds by module weight, then alphabetically by machine name, unless an implementation is reordered (Drupal 11.2 and later). An implementation is either a method with the Hook attribute in a class, or a procedural function in the module file.Extension pointA node is deleted, or aform is about to be shownasks everyEnabled modulesEach may implementthe hookruns themIn this orderModule weight, thenmachine name, unlessreordered (11.2+)Two ways to write an implementationClass method (Drupal 11.1 and later)#[Hook('form_alter')] in theDrupal\my_module\Hook namespaceProcedural functionmy_module_form_alter() in themodule's .module fileThe hook_ prefix belongs to the documentation name; the attribute takes the short name.
How Drupal runs a hook, and the two ways to write an implementation.

Example

This class adds a CSS class to the user login form. The hook is hook_form_alter, which Drupal calls for every form before it is rendered, so the method checks the form ID first.

<?php

        namespace Drupal\my_module\Hook;

        use Drupal\Core\Form\FormStateInterface;
        use Drupal\Core\Hook\Attribute\Hook;

        class FormHooks {

          #[Hook('form_alter')]
          public function formAlter(array &$form, FormStateInterface $form_state, string $form_id): void {
            if ($form_id === 'user_login_form') {
              $form['#attributes']['class'][] = 'login-form';
            }
          }

        }

The same thing as a procedural hook is a function called my_module_form_alter() in my_module.module, with the same parameters.

Common mistakes

  • Running a hook twice. A module that supports Drupal 10.1 to 11.0 and 11.1 or later keeps a small procedural function in the .module file marked with #[LegacyHook]. Without that marker, Drupal 11.1 and later run both the old function and the new method.
  • Defining an implementation conditionally. Object-oriented hooks do not support implementations that exist only under a condition. Put the condition inside the method instead.
  • Expecting an .api.php file to do something. Drupal never loads these files, so copying a function from one into the wrong place changes nothing until you rename it and add it to your module.
  • Altering a form without checking the form ID. hook_form_alter runs for all forms. A more specific variant, hook_form_FORM_ID_alter, runs after it for one form.
  • Assuming a hook runs first. Another module may implement the same hook, and weight and name decide the order.

For marketing and content teams

When a developer says a behavior "is done in a hook", they mean custom module code that reacts to something that happens on the site, such as saving or deleting content. That is useful to know when you ask for a change: a rule like "do this whenever an article is published" is a typical hook job, and it belongs in a custom module, not in the theme or in a one-off setting. Ask for it to be documented, because the code is easy to forget until the day it needs to change.

Related ideas are covered in module, Form API and cron, which has its own hook, hook_cron.

Sources

Questions about Drupal hooks

The hook is the extension point that Drupal or a module defines, such as hook_form_alter. An implementation is your module's code that answers it. Drupal calls every implementation it finds, in every enabled module, each time the hook runs.

Yes. A function named after the module and the hook, placed in the .module file, is still discovered and called. Drupal 11.1 added class methods with the #[Hook] attribute as the preferred way. Both styles can live side by side in one module.

By default Drupal orders implementations by module weight, then by module name. Drupal 11.2 and later let you pass an order argument to #[Hook]. The #[ReorderHook] attribute changes the order of another module's implementation.

The Hooks topic on api.drupal.org lists the hooks Drupal core defines, and core modules document their own hooks in files ending in .api.php. Those files are documentation only; Drupal never loads them.

Related terms

All Drupal terms from A to Z