12

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?

1
  • 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
    Commented May 6, 2015 at 6:45

1 Answer 1

13

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 contributed 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 contributed modules, you need to check the code used to invoke hooks. Chances are that, for themes, only the alter hooks are invoked; in some cases, 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.

7
  • hook_entity_view_alter() doesn't work in themes.
    – dxvargas
    Commented Apr 29, 2019 at 11:16
  • At least in D7 alter-hooks in themes are only invoked if the theme has already been initialized in the same request (ie. by calling theme()). If it hasn’t been initialized no alter hooks in any theme will be executed. Commented Apr 8, 2020 at 9:24
  • @zwirbeltier Theme hooks are invoked for the theme used to render the page. theme() doesn't change the theme used for the page, but it invokes a function to render data. It doesn't change the theme, for example, from Garland to Minelli.
    – avpaderno
    Commented Apr 8, 2020 at 9:40
  • @kiamlaluno: If you look at the code in drupal_alter() you see that it only invokes alter-hooks in the theme if drupal_theme_initialize() was called before. If it wasn’t then there is no active theme (yet) and thus no hooks called. At least in D7 there is no guarantee when drupal_theme_initialize() is called the first time in a request. Commented Apr 8, 2020 at 12:45
  • @zwirbeltier The theme set from Drupal is already initialized when a page is rendered. If a module sets a theme for a page without calling the appropriate function, it's its responsability to initialize it.
    – avpaderno
    Commented Apr 8, 2020 at 13:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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