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?
Drupal Answers is a question and answer site for Drupal developers and administrators. It only takes a minute to sign up.
Sign up to join this communitySometimes 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?
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.
theme()
). If it hasn’t been initialized no alter hooks in any theme will be executed.
– zwirbeltier
Apr 8 '20 at 9:24
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.
– kiamlaluno♦
Apr 8 '20 at 9:40
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.
– zwirbeltier
Apr 8 '20 at 12:45