Problem/Motivation

After template became the default for theme hooks in #2226207: Make 'template' the default output option for hook_theme() template_preprocess() and other non-hook-specific preprocess functions run even for theme hooks implemented as theme functions. Documentation and comments in the Theme Registry say this shouldn't be the case. The cause is all theme registry entries mistakenly getting a template key/value and the preprocess functions getting added based on the existence of the 'template' key.

Proposed resolution

Don't add a template entry for every theme hook in the registry. Then template_preprocess will not get added to the list of preprocess functions for these hooks.

Remaining tasks

Resolve any remaining issues with the attached patch.

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug because functionality different to documented intention
Issue priority Normal
Prioritized changes The main goal of this issue is a bugfix.
Disruption Not disruptive, fixes unintended behavior.
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Antti J. Salminen’s picture

Status: Active » Needs review
Antti J. Salminen’s picture

Issue summary: View changes
lauriii’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

I don't understand how this would fix the bug?

lauriii’s picture

Assigned: Unassigned » lauriii
Antti J. Salminen’s picture

It's not visible in the patch but this if has an elseif that takes care of defaulting to 'template'.

The problem is that that the elseif is reached almost always. Only case where it won't be is when there is a theme function defined in hook_theme AND that theme function does not exist. So effectively 99.9% of the time it all amounts to "if there is no 'template' set a 'template'".

lauriii’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests +Twig
FileSize
1.37 KB
2.33 KB
lauriii’s picture

Assigned: lauriii » Unassigned
star-szr’s picture

+++ b/core/modules/system/tests/themes/test_basetheme/test_basetheme.theme
@@ -27,3 +27,9 @@ function test_basetheme_views_post_render(ViewExecutable $view) {
+function test_basetheme_preprocess_theme_test_function_suggestions($variables) {

Super duper minor and doesn't really apply here but &$variables :)

Looks good!

star-szr’s picture

Only one other thing:

+++ b/core/modules/system/src/Tests/Theme/RegistryTest.php
@@ -99,6 +99,11 @@ public function testMultipleSubThemes() {
+    $preprocess_functions = $registry_base_theme->get()['theme_test_function_suggestions']['preprocess functions'];
+    $this->assertIdentical([
+      'test_basetheme_preprocess_theme_test_function_suggestions',
+    ], $preprocess_functions);

This should probably have an inline comment about what it's testing…

lauriii’s picture

Fixing!

lauriii’s picture

Fixing more stuff!

The last submitted patch, 6: template_preprocess-2493989-should-fail-5.patch, failed testing.

The last submitted patch, 6: template_preprocess-2493989-5.patch, failed testing.

The last submitted patch, 10: template_preprocess-2493989-9.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 11: template_preprocess-2493989-11.patch, failed testing.

Antti J. Salminen’s picture

Status: Needs work » Needs review
FileSize
2.04 KB
2.73 KB

Let's try with the initial patch and lauriii's tests.

star-szr’s picture

Adding some feedback from IRC so it's here too.

  1. +++ b/core/lib/Drupal/Core/Theme/Registry.php
    @@ -456,12 +456,14 @@ protected function processExtension(array &$cache, $name, $type, $theme, $path)
    -        if (isset($info['function']) && !function_exists($info['function'])) {
    -          throw new \BadFunctionCallException(sprintf(
    -            'Theme hook "%s" refers to a theme function callback that does not exist: "%s"',
    -            $hook,
    -            $info['function']
    -          ));
    +        if (isset($info['function'])) {
    +          if (!function_exists($info['function'])) {
    +            throw new \BadFunctionCallException(sprintf(
    +                'Theme hook "%s" refers to a theme function callback that does not exist: "%s"',
    +                $hook,
    +                $info['function']
    +              ));
    +          }
    

    Might be clearer for the elseif after this to instead do:

    if (!isset($info['function']) && !isset($info['template'])) {

  2. +++ b/core/modules/system/src/Tests/Theme/RegistryTest.php
    @@ -99,6 +99,11 @@ public function testMultipleSubThemes() {
    +
    +    $preprocess_functions = $registry_base_theme->get()['theme_test_function_suggestions']['preprocess functions'];
    +    $this->assertIdentical([
    +      'test_basetheme_preprocess_theme_test_function_suggestions',
    +    ], $preprocess_functions, "Theme functions doesn't have template preprocess function");
    
    +++ b/core/modules/system/tests/themes/test_basetheme/test_basetheme.theme
    @@ -27,3 +27,9 @@ function test_basetheme_views_post_render(ViewExecutable $view) {
    +
    +/**
    + * Implements hook_preprocess_HOOK() for theme_test_function_suggestions theme functions.
    + */
    +function test_basetheme_preprocess_theme_test_function_suggestions(&$variables) {
    +}
    

    I think we should add in the theme_test module (or wherever) template_preprocess_theme_test_function_suggestions() to make sure that still works.

    Because that's what didn't work with lauriii's approach and is still pretty important. We just don't want the template_preprocess() function itself running for theme functions.

Antti J. Salminen’s picture

So this should test for the template_preprocess_hook as well, seems like a very good idea.

As for the elseif, I agree that clarity is key but isn't the if...elseif already pretty simple and arguably easier to read with just a single test per conditional?

slashrsm’s picture

Status: Needs review » Reviewed & tested by the community

Found this when playing with bootstrap which does some altering on theme registry, which eventually broke all theme hook that use functions.

Patch looks good to me. I agree if/elseif should be pretty clear and self-explanatory.

Thank you for fixing this. Great job!

slashrsm’s picture

Status: Reviewed & tested by the community » Needs work

Meh... I noticed something else.

+++ b/core/lib/Drupal/Core/Theme/Registry.php
@@ -456,12 +456,14 @@ protected function processExtension(array &$cache, $name, $type, $theme, $path)
+                'Theme hook "%s" refers to a theme function callback that does not exist: "%s"',
+                $hook,
+                $info['function']
+              ));
+          }

Indentation seems to be a bit off here.

slashrsm’s picture

Status: Needs work » Needs review
FileSize
3.48 KB
marcingy’s picture

Status: Needs review » Reviewed & tested by the community

I was discussing this issue with @slashrsm around bootstrap and patch looks good.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 21: 2493989_21.patch, failed testing.

Status: Needs work » Needs review

bill richardson queued 21: 2493989_21.patch for re-testing.

Antti J. Salminen’s picture

Title: template_preprocess() is called even for theme hooks implemented as functions » template_preprocess() and other preprocess functions are called even for theme hooks implemented as functions
Issue summary: View changes
FileSize
3.47 KB

Just a reroll to make it apply again. Issue summary updates.

tim.plunkett’s picture

Priority: Normal » Major
Status: Needs review » Reviewed & tested by the community
star-szr’s picture

+1, thanks!

lauriii’s picture

+1 for RTBC

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed to 8.0.x, thanks!

  • catch committed 47295c1 on 8.0.x
    Issue #2493989 by Antti J. Salminen, lauriii, slashrsm:...

Status: Fixed » Closed (fixed)

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