Should themes be able to implement hooks, e.g. hook_system_info_alter()?

Created on 20 June 2013, over 11 years ago
Updated 6 November 2024, about 2 months ago

Problem/Motivation

Currently ModuleHandler::alter() invokes alter hook implementations in the theme layer once it has been initialized.

      // 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)) {
            $this->alterFunctions[$cid][] = $function;
          }
          if (isset($extra_types)) {
            foreach ($extra_types as $extra_type) {
              $function = $theme_key . '_' . $extra_type . '_alter';
              if (function_exists($function)) {
                $this->alterFunctions[$cid][] = $function;
              }
            }
          }
        }
      }

This is something that always bothered. If themes are themes and not modules (and also handled differently and not just a special type of module) why do we allow them to implement alter hooks? And if we want them to implement alter hooks why do we make the whole thing so fragile that it is never known whether a given hook is actually safe to implement in the theme or not. There are various cases in which this concept totally fails. Here is just one:

A theme implements hook_system_info_alter() (yes, as silly as that is):
Now, due to the fact that the system info is only built once and then goes into the cache until it gets rebuilt for the next time this can lead to a few interesting scenarios. Imagine you clear the cache of your site while on the backend. The front-end theme implements hook_system_info_alter(). However, since we were on the backend theme during the system info rebuild that hook implementation from our front-end theme is never invoked. Right, so now you got some sort of Russian roulette for your site which causes your site to behave differently based on whether your cache was rebuilt with the front-end theme loaded or not.

The same basically applies to every alter hook that is related to some sort of caching.

Another scenario:

Some random API function, that might be called from anywhere in your code and at any time (e.g. module A might use it in some random preprocess hook and module B uses it in hook_boot()), internally invokes an alter hook. Now, when invoked in hook_boot() it will not invoke the theme-level alter hook implementation as themes are simply not loaded yet during hook_boot(). However, when invoked in that preprocess hook the theme most likely will be initialized and the hook gets invoked successfully leading into two different results. Shit just got real.

Or, probably even worse:

Theme A is active, and we invoke a few alter hooks for it. Suddently, Module B comes in and changes the active theme to Theme C. Now, all further alter hooks are invoked for Theme C. What?

Proposed resolution

So, how do we identify whether an alter hook is appropriate to be implemented by a theme? Simple answer: We can't. At least not adequately. We really need either black or white here. And since we can't give themes the same privileges and not load them as early in the bootstrap as modules (at least in terms of hooks) as they need to be swappable (for example to allow for backend themes) for me the answer would be to completely disallow alter hooks in themes and just remove those lines from ModuleHandler::alter().

Thoughts?

📌 Task
Status

Active

Version

11.0 🔥

Component

theme system

Created by

🇦🇹Austria fubhy

Live updates comments and jobs are added and updated live.
  • API change

    Changes an existing API or subsystem. Not backportable to earlier major versions, unless absolutely required to fix a critical bug.

Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇨🇦Canada Liam Morland Ontario, CA 🇨🇦

    This may already have been partially done. I've been trying to get hook_system_info_alter() to run in a theme but it has not worked.

    It needs to be better documented which hooks work in modules vs. themes. It appears to be that hook_system_info_alter() does not work, but hook_form_system_theme_settings_alter(), hook_form_FORM_ID_alter(), and hook_preprocess_HOOK() do.

Production build 0.71.5 2024