9

Sometimes when I try to apply a hook, just to realise it's supposed to be in a module file.

Is there a way of knowing what hooks can be implemented in a theme's template.php file, or one in a module?

  • 4
    Generally when a hook is not available to be overridden in a theme it is for good reason. Themes should only be for code relating the display of the content and functionality that the modules provide. Code that adds/removes/changes functionality or content usually should be in a module. Also think about the fact that if you change themes you lose any customisations made in template.php, so if you are making changes that you would likely want to keep if you ever changed themes then that would definitely want to go in a module. – rooby May 6 '15 at 6:45
10

Generally speaking, only alter hooks can be implemented by themes, which means hooks like hook_form_alter() and hook_menu_alter(), or in short all those hooks that are invoked through drupal_alter() in Drupal 7 and lower (ModuleHandler()::alter() or ThemeManager::alter() in Drupal 8).

Other hooks, which are invoked by module_invoke_all() (ModuleHandler::invokeAll() in Drupal 8), don't get invoked for themes simply for fact the code doesn't check if the currently enabled theme defines any hook.

  foreach (module_implements($hook) as $module) {
    $function = $module . '_' . $hook;
    if (function_exists($function)) {
      $result = call_user_func_array($function, $args);
      if (isset($result) && is_array($result)) {
        $return = array_merge_recursive($return, $result);
      }
      elseif (isset($result)) {
        $return[] = $result;
      }
    }
  }

In Drupal 8, where the ModuleHandler class invokes hooks implemented from modules and the ThemeManager class invokes hooks implemented by themes, only the first class implements invoke() and invokeAll(). This means that in Drupal 8 theme hooks aren't invoked, by Drupal core.

This is valid for Drupal core hooks, and mostly all the hooks used by third-party modules. It is then up to a module to verify a hook is implemented by a theme too, and invoke it. This is what the Views module does.

  // Let modules modify the view just prior to rendering it.
  foreach (module_implements('views_pre_render') as $module) {
    $function = $module . '_views_pre_render';
    $function($this);
  }

  // Let the themes play too, because pre render is a very themey thing.
  foreach ($GLOBALS['base_theme_info'] as $base) {
    $function = $base->name . '_views_pre_render';
    if (function_exists($function)) {
      $function($this);
    }
  }
  $function = $GLOBALS['theme'] . '_views_pre_render';
  if (function_exists($function)) {
    $function($this);
  }

For hooks used by third-party modules, you need to check the code used to invoke them. Chances are that only alter hooks are invoked for themes, but in some cases also other hooks could be implemented by themes.
Keep in mind that in the case of themes, not all the enabled themes are checked for hook implementations, contrary to what happens with modules. Only the currently used theme and the base themes are checked, as done from the Views module.

  • hook_entity_view_alter() doesn't work in themes. – dxvargas Apr 29 at 11:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.