Problem/Motivation

#2228093: Modernize theme initialization removed the ability for themes to implement system-wide alter hooks and instead limits to a certain "whitelist" due to the nature of the caching system in 8.x. This "whitelist" does not contain hook_registry_theme_alter().

This is a critical hook that should allow themes to alter the theme registry before any rendering happens.

This blocks the port of Bootstrap which uses this hook to implement it's dynamic file system for splitting out complex code as well as altering existing theme hooks to counter many core theme system issues that have not been addressed. Bootstrap currently has > 50k installs in 7.x.

Proposed resolution

Add this alter hook back.

Sadly its a bit tricky because of the following reasons:

  1. The ThemeManager depends on the registry (for theme()), but the Registry now depends on the ThemeManager for executing the alter "hook",
    so we need setter injection in order to resolve the circular dependency
  2. The theme registry is built by theme, so we want to alter by the theme of the registry object. Therefore we need ThemeManager::alterByTheme($theme, ...)

Remaining tasks

User interface changes

None.

API changes

Allows themes to implement hook_registry_theme_alter() again.

Comments

fabianx’s picture

#2228093: Modernize theme initialization said that hook_theme_registry_alter() was allowed, is that a bug in the code?

dawehner’s picture

Status: Active » Needs review
StatusFileSize
new5.32 KB

Number two.

Status: Needs review » Needs work

The last submitted patch, 2: 2448847-1.patch, failed testing.

fabianx’s picture

Title: [regression] Themes unable to implement hook_registry_theme_alter() » [regression] Themes unable to implement hook_theme_registry_alter()
webchick’s picture

Hm. Can you explain how this meets the definition of critical? https://www.drupal.org/node/45111

Critical bugs include those that:

Render a system unusable and have no workaround.
Cause loss of data.
Expose security vulnerabilities.
Cause tests to fail in HEAD on the automated testing platform, since this blocks all other work.

Note especially this part:

Regressions in functionality are not automatically considered critical. Even if the bug existed before, it should be prioritized according to its impact.

I find it a bit difficult to believe that it's impossible to theme at all without this being fixed, but it sounds solidly major since it falls under "Issues that have significant repercussions but do not render the whole system unusable (or have a known workaround) are marked major."

markhalliwell’s picture

Issue summary: View changes
markhalliwell’s picture

Issue summary: View changes
dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new10.91 KB
new6.62 KB

Let's try that.

Status: Needs review » Needs work

The last submitted patch, 8: 2448847-8.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new9.54 KB
new4.48 KB

Another one.

fabianx’s picture

  1. +++ b/core/lib/Drupal/Core/Theme/Registry.php
    @@ -328,7 +342,12 @@ protected function build() {
    +    $this->themeManager->alterForTheme($this->theme, 'theme_registry', $cache);
    +    $this->processExtension($cache, $this->theme->getName(), 'theme', $this->theme->getName(), $this->theme->getPath());
    ...
    +    // Let modules alter the registry.
    +    $this->moduleHandler->alter('theme_registry', $cache);
    +    $this->themeManager->alterForTheme($this->theme, 'theme_registry', $cache);
    

    This looks duplicated.

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -397,12 +407,7 @@ protected function initTheme(RouteMatchInterface $route_match = NULL) {
    -  public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
    +  public function alterForTheme(ActiveTheme $theme, $type, &$data, &$context1 = NULL, &$context2 = NULL) {
         // Most of the time, $type is passed as a string, so for performance,
    

    Missing doxy

  3. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -446,4 +450,14 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
    +   *
    +   * @todo Should we cache some of these information?
    

    This todo should be at alterForTheme.

dawehner’s picture

StatusFileSize
new11.85 KB
new6.32 KB

And here is a test.

fabianx’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Theme/Registry.php
@@ -328,7 +345,12 @@ protected function build() {
+    $this->processExtension($cache, $this->theme->getName(), 'theme', $this->theme->getName(), $this->theme->getPath());
+
+    // Let modules alter the registry.
+    $this->moduleHandler->alter('theme_registry', $cache);

These lines are still duplicated - unless I am missing something.

The last submitted patch, 12: 2448847-11.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new11.85 KB
new969 bytes

You are absolute right.

Status: Needs review » Needs work

The last submitted patch, 15: 2448847-15.patch, failed testing.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new11.79 KB
new599 bytes

Maybe this helps a lot.

dawehner’s picture

Issue summary: View changes

Adapted the issue summary.

kim.pepper’s picture

Status: Needs review » Needs work
  1. +++ b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php
    @@ -122,4 +122,22 @@ public function setActiveTheme(ActiveTheme $active_theme);
    +   * @param string|array $type
    

    Docs missing

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php
    @@ -122,4 +122,22 @@ public function setActiveTheme(ActiveTheme $active_theme);
    +   * @return
    

    Docs missing

  3. +++ b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php
    @@ -122,4 +122,22 @@ public function setActiveTheme(ActiveTheme $active_theme);
    +   * @see ::alter() for more information.
    

    Should not contain trailing text.

  4. +++ b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php
    @@ -122,4 +122,22 @@ public function setActiveTheme(ActiveTheme $active_theme);
    +   *   (optional) An additional variable that is passed by reference.   to be altered.    A string describing the type of the alterable $data.
    +   * @return
    

    Formatting was mixed up here.

  5. +++ b/core/modules/system/tests/themes/test_theme/test_theme.theme
    @@ -84,3 +84,10 @@ function test_theme_theme_test_function_suggestions__theme_override($variables)
    + * Implements hook_theme_registry_alter()
    

    Needs full stop.

Also, needs an update to the change notice because we are changing the API.

(Reviewed with @jibran & @dashaforbes) during critical office hours)

jibran’s picture

@dawehner thanks for the patch. During our review we discussed why this is breaking a circular dependency.
theme manager is only using $themeRegistry in ThemeManager::theme() function. So for all normal workflow we can safely assume that theme registry will be available for theme function.
I can only come up with one scenario in which theme registry will not be available for theme function.
When we are rebuilding the container and before building theme registry we hit some actual circular dependency in that case we try to render the theme for displaying error/exception when there is no theme registry. It'd be good if we can add test for this and handle this boundary case.

dawehner’s picture

@dawehner thanks for the patch. During our review we discussed why this is breaking a circular dependency.

Oh, its not that hard as you think:

The @theme.manager service needs the @theme.registry service, and the other way round.

dawehner’s picture

Also, needs an update to the change notice because we are changing the API.

Do we? We have an alter hook, which is still documented in theme.api.php, yes, the ThemeManagerInterface
changed, but IMHO this is not something we need a dedicated change record for

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new11.74 KB
new1.86 KB

.

larowlan’s picture

Status: Needs review » Reviewed & tested by the community

When we are rebuilding the container and before building theme registry we hit some actual circular dependency in that case we try to render the theme for displaying error/exception when there is no theme registry

All bets are off when we get an error that early, an invalid constraint plugin will manifest as a twig error, but actually, its unrelated.
Not sure we should babysit this.
Boldy setting to rtbc

fabianx’s picture

RTBC + 1

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Theme/Registry.php
@@ -326,9 +343,9 @@ protected function build() {
+    $this->themeManager->alterForTheme($this->theme, 'theme_registry', $cache);

+++ b/core/lib/Drupal/Core/Theme/ThemeManagerInterface.php
@@ -122,4 +122,22 @@ public function setActiveTheme(ActiveTheme $active_theme);
+   * Provides an alter hook for a specific theme.

I think it is worth documenting that the theme's base themes hooks will be invoked as well. Because that is the first thing I wondered when thinking about the patch.

dawehner’s picture

Status: Needs work » Needs review
StatusFileSize
new12.14 KB
new960 bytes

That is a good idea!

jibran’s picture

Status: Needs review » Reviewed & tested by the community

Back to RTBC.

arlinsandbulte’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new12.14 KB

Simple grammar edit to #27:

- * Similar to ::alter it invokes also the alter hooks for the base themes.
+ * Similar to ::alter it also invokes the alter hooks for the base themes.

tim.plunkett’s picture

Status: Needs review » Reviewed & tested by the community

Thanks, that reads better.

arlinsandbulte’s picture

StatusFileSize
new12.14 KB

I just can't leave well enough alone. Added a comma to my edit for even better, proper grammar:

- * Similar to ::alter it also invokes the alter hooks for the base themes.
+ * Similar to ::alter, it also invokes the alter hooks for the base themes.

Leaving at RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

This issue addresses a critical bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 08ce5a7 and pushed to 8.0.x. Thanks!

  • alexpott committed 08ce5a7 on 8.0.x
    Issue #2448847 by dawehner, arlinsandbulte: [regression] Themes unable...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

xjm’s picture