6.x common.inc drupal_alter($type, &$data)
7.x module.inc drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL)

Passes alterable variables to specific hook_TYPE_alter() implementations.

This dispatch function hands off the passed-in variables to type-specific hook_TYPE_alter() implementations in modules. It ensures a consistent interface for all altering operations.

A maximum of 2 alterable arguments is supported (a third is supported for legacy reasons, but should not be used in new code). In case more arguments need to be passed and alterable, modules provide additional variables assigned by reference in the last $context argument:

$context = array(
  'alterable' => &$alterable,
  'unalterable' => $unalterable,
  'foo' => 'bar',
drupal_alter('mymodule_data', $alterable1, $alterable2, $context);

Note that objects are always passed by reference in PHP5. If it is absolutely required that no implementation alters a passed object in $context, then an object needs to be cloned:

$context = array(
  'unalterable_object' => clone $object,
drupal_alter('mymodule_data', $data, $context);


$type: A string describing the type of the alterable $data. 'form', 'links', 'node_content', and so on are several examples. Alternatively can be an array, in which case hook_TYPE_alter() is invoked for each value in the array, ordered first by module, and then for each module, in the order of values in $type. For example, when Form API is using drupal_alter() to execute both hook_form_alter() and hook_form_FORM_ID_alter() implementations, it passes array('form', 'form_' . $form_id) for $type.

$data: The variable that will be passed to hook_TYPE_alter() implementations to be altered. The type of this variable depends on the value of the $type argument. For example, when altering a 'form', $data will be a structured array. When altering a 'profile', $data will be an object.

$context1: (optional) An additional variable that is passed by reference.

$context2: (optional) An additional variable that is passed by reference. If more context needs to be provided to implementations, then this should be an associative array as described above.

$context3: (optional) An additional variable that is passed by reference. This parameter is deprecated and will not exist in Drupal 8; consequently, it should not be used for new Drupal 7 code either. It is here only for backwards compatibility with older code that passed additional arguments to drupal_alter().

85 calls to drupal_alter()
actions_list in includes/actions.inc
Discovers all available actions by invoking hook_action_info().
ajax_render in includes/ajax.inc
Renders a commands array into JSON.
archiver_get_info in includes/common.inc
Retrieves a list of all available archivers.
batch_process in includes/form.inc
Processes the batch.
comment_view in modules/comment/comment.module
Generate an array for rendering the given comment.

... See full list

3 string references to 'drupal_alter'
drupal_theme_initialize in includes/theme.inc
Initializes the theme system by loading the theme.
module_implements in includes/module.inc
Determines which modules are implementing a hook.
_drupal_bootstrap_full in includes/common.inc


includes/module.inc, line 1050
API for loading and interacting with Drupal modules.


function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL, &$context3 = NULL) {

  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['functions'] =& drupal_static(__FUNCTION__);
  $functions =& $drupal_static_fast['functions'];

  // Most of the time, $type is passed as a string, so for performance,
  // normalize it to that. When passed as an array, usually the first item in
  // the array is a generic type, and additional items in the array are more
  // specific variants of it, as in the case of array('form', 'form_FORM_ID').
  if (is_array($type)) {
    $cid = implode(',', $type);
    $extra_types = $type;
    $type = array_shift($extra_types);

    // Allow if statements in this function to use the faster isset() rather
    // than !empty() both when $type is passed as a string, or as an array with
    // one item.
    if (empty($extra_types)) {
  else {
    $cid = $type;

  // Some alter hooks are invoked many times per page request, so statically
  // cache the list of functions to call, and on subsequent calls, iterate
  // through them quickly.
  if (!isset($functions[$cid])) {
    $functions[$cid] = array();
    $hook = $type . '_alter';
    $modules = module_implements($hook);
    if (!isset($extra_types)) {

      // For the more common case of a single hook, we do not need to call
      // function_exists(), since module_implements() returns only modules with
      // implementations.
      foreach ($modules as $module) {
        $functions[$cid][] = $module . '_' . $hook;
    else {

      // For multiple hooks, we need $modules to contain every module that
      // implements at least one of them.
      $extra_modules = array();
      foreach ($extra_types as $extra_type) {
        $extra_modules = array_merge($extra_modules, module_implements($extra_type . '_alter'));

      // If any modules implement one of the extra hooks that do not implement
      // the primary hook, we need to add them to the $modules array in their
      // appropriate order. module_implements() can only return ordered
      // implementations of a single hook. To get the ordered implementations
      // of multiple hooks, we mimic the module_implements() logic of first
      // ordering by module_list(), and then calling
      // drupal_alter('module_implements').
      if (array_diff($extra_modules, $modules)) {

        // Merge the arrays and order by module_list().
        $modules = array_intersect(module_list(), array_merge($modules, $extra_modules));

        // Since module_implements() already took care of loading the necessary
        // include files, we can safely pass FALSE for the array values.
        $implementations = array_fill_keys($modules, FALSE);

        // Let modules adjust the order solely based on the primary hook. This
        // ensures the same module order regardless of whether this if block
        // runs. Calling drupal_alter() recursively in this way does not result
        // in an infinite loop, because this call is for a single $type, so we
        // won't end up in this code block again.
        drupal_alter('module_implements', $implementations, $hook);
        $modules = array_keys($implementations);
      foreach ($modules as $module) {

        // Since $modules is a merged array, for any given module, we do not
        // know whether it has any particular implementation, so we need a
        // function_exists().
        $function = $module . '_' . $hook;
        if (function_exists($function)) {
          $functions[$cid][] = $function;
        foreach ($extra_types as $extra_type) {
          $function = $module . '_' . $extra_type . '_alter';
          if (function_exists($function)) {
            $functions[$cid][] = $function;

    // Allow the theme to alter variables after the theme system has been
    // initialized.
    global $theme, $base_theme_info;
    if (isset($theme)) {
      $theme_keys = array();
      foreach ($base_theme_info as $base) {
        $theme_keys[] = $base->name;
      $theme_keys[] = $theme;
      foreach ($theme_keys as $theme_key) {
        $function = $theme_key . '_' . $hook;
        if (function_exists($function)) {
          $functions[$cid][] = $function;
        if (isset($extra_types)) {
          foreach ($extra_types as $extra_type) {
            $function = $theme_key . '_' . $extra_type . '_alter';
            if (function_exists($function)) {
              $functions[$cid][] = $function;
  foreach ($functions[$cid] as $function) {
    $function($data, $context1, $context2, $context3);


Elijah Lynn’s picture

For those new to Drupal drupal_alter() is how you create a hook for your module that others can use.

@see http://erikwebb.net/blog/drupal-design-patterns/hooks for a very basic example.

emarchak’s picture

The post in question is archived at on his github.

afinnarn’s picture

Elijah Lynn’s picture

I meant for the above to say that drupal() alter is how you create your own alter hook for other modules to alter your data.

derek.deraps’s picture

DrCord’s picture

this link does not work

kari.kaariainen’s picture

Page not found. What Elijah posted earlier can be found though: http://erikwebb.net/blog/drupal-design-patterns/hooks.

DrCord’s picture

Here's the example that got me the rest of the way to working:

Elijah Lynn’s picture

Just getting up to speed on D8. drupal_alter() has been removed.

https://www.drupal.org/node/2301577 (removed here)
https://api.drupal.org/api/drupal/core%21core.api.php/group/extending/8 (docs on extending and altering D8)

Elijah Lynn’s picture

It appears to have been replaced by \Drupal\Core\Extension\ModuleHandler::alter which implements the Drupal/Core/Extension/ModuleHandlerInterface::alter() interface.


Elijah Lynn’s picture

And I finally arrived at the replacement for drupal_alter() in Drupal 8.

\Drupal::moduleHandler()->alter($type, &$data, &$context1 = NULL, &$context2 = NULL)

https://www.drupal.org/node/1894902 (Module/hook system functions replaced with module_handler and module_installer service)

Elijah Lynn’s picture

Drupal::moduleHandler() is what you actually call, then call the alter() on that, I was confusing the class before. https://api.drupal.org/api/drupal/core%21lib%21Drupal.php/function/Drupa...

tyler.frankenstein’s picture

Thank you for pointing me in the right direction, I've added a complete example here:


2pha’s picture

Thankyou :)

lolandese’s picture

To find old broken links use http://web.archive.org.
For the link mentioned above it becomes: