Updated: Comment #206

Problem/Motivation

Twig debugging output is supposed to show all template suggestions. Currently, the debug output does not show all the template suggestions that the Drupal render system knows about.

Here are a few examples where this feature fails:

  • Views (a core feature used in many places) templates do not show any template suggestions. For example, go to /admin/content and look at the Filter form at the top of the page; Twig debug shows: 'views_exposed_form', but Drupal's theme system is given this list of suggestions: ['views_exposed_form__content__page_1', 'views_exposed_form__page_1', 'views_exposed_form__default', 'views_exposed_form__content__page', 'views_exposed_form__page', 'views_exposed_form__content', 'views_exposed_form'] (defined in Drupal\views\Form\ViewsExposedForm::buildForm()).
  • Using the default Bartik theme, use Drupal's search and look at the list of search results. Twig debug shows: x item-list--search-results.html.twig, x item-list--search-results.html.twig, * item-list.html.twig, but Drupal's theme system is given this list of suggestions: ['item_list__search_results__node_search', 'item_list__search_results'] (defined in Drupal\search\Controller\SearchController::view()).

The underlying cause of this issue is when #theme is set as an array of suggestions. The twig_debug output only works* when #theme is a string or when suggestions are added via suggestions_alter hooks.

* where "works" is defined as super buggy output, showing duplicates and out-of-order suggestions. See #2752443: Incorrect order and duplicate theme hook suggestions

When #theme is set as an array of suggestions, Drupal\Core\Theme\ThemeManager::render() will call the theme suggestions alter hooks with the base hook and will conditionally add an entry from the #theme array if that entry is actually implemented in the system. If none of #theme array suggestion entries are implemented, only the base hook is sent to the theme suggestions alter hooks and the code handling the twig debug comments code.

Here's a specific example of what Drupal core does now:

  1. #theme is set to ['item_list__search_results__node_search', 'item_list__search_results'] in Drupal\search\Controller\SearchController::view()
  2. Drupal\Core\Theme\ThemeManager::render() will look for implementations of the theme suggestions in the #theme entry.
    • If the only implemented Twig template is item-list.html.twig (like in the Stable themes), the theme suggestion alter hooks will be passed this list of suggestions: item_list, [list of suggestions from hook_theme_suggestions_item_list() (if this function existed)]
    • If the item-list--search-results.html.twig Twig template is implemented (like most core themes), the theme suggestion alter hooks will be passed this list of suggestions: item_list, [list of suggestions from hook_theme_suggestions_item_list()], item_list__search_results
  3. The twig_render_template() generates the Twig debugging comments by looking at the list of theme suggestions returned by the theme suggestion alter hooks (passed in $variables['theme_hook_suggestions']). But it doesn't know about the item_list__search_results__node_search suggestion in Step 1, so the list is wrong.

Proposed resolution

Theoretically, we could fix this by #2923506: Deprecate and discourage use of the "array of theme hooks" feature, but that is a loooong road of deprecations that is completely stalled. And since the "array of theme hooks" feature has been in core since 6.x and has been used frequently in contrib and in core 9.1.x and earlier, we need to fix the bug now.

To minimize the possible side effects to changing how Twig chooses templates, we should not modify any existing lines of code inside Drupal\Core\Theme\ThemeManager::render() and only add code to generate a proper list of theme suggestions. OMG. No. This is technically possible, but a "proper list of theme suggestions" requires super ugly code if we're not going to modify existing lines of code. See comment #204 for proof in the form of a patch that implements this option.

Instead of conditionally appending suggestions from #theme on to the end of the suggestions from hook_theme_suggestions_HOOK(), we should always append those suggestions so that hook_theme_suggestions_alter() and hook_theme_suggestions_HOOK_alter() can see them.

Extending the example above, no matter what item_list Twig templates are implemented, the theme suggestion alter hooks will be passed this list of suggestions: item_list, [list of suggestions from hook_theme_suggestions_item_list()], item_list__search_results, item_list__search_results__node_search

This will make it easy to output an accurate suggestion list in twig debugging comments.

We will need to add extensive tests to make sure we aren't breaking anything.

This solution also fixes #2752443: Incorrect order and duplicate theme hook suggestions.

Remaining tasks

  1. Final polishing and reviews
  2. Commit

User interface changes

Twig debug output will display all templates suggestions, no matter the source of those suggestions.

API changes

The theme suggestions from #theme will always be added to the end of the hook_theme_suggestions_HOOK() list of suggestions before sending them to hook_theme_suggestions_alter() and hook_theme_suggestions_HOOK_alter().

Release notes snippet

Previously, theme suggestions from #theme (like views_exposed_form__content__page) were only sometimes added to the $suggestions variable passed to hook_theme_suggestions_alter() and hook_theme_suggestions_HOOK_alter(). Now those suggestions are always passed to alter hooks.

CommentFileSizeAuthor
#245 2118743-nr-bot.txt90 bytesneeds-review-queue-bot
#234 2118743-231.patch81.59 KBGiuseppe87
#190 interdiff_of_patch_189_to_190.txt348 bytesjoseph.olstad
#190 2118743-190.patch25.68 KBjoseph.olstad
#183 interdiff_181-183.txt11.59 KBshaal
#183 2118743-183-twig-debug-info.patch24.28 KBshaal
#181 interdiff_180-181.txt1.09 KBshaal
#181 2118743-181-twig-debug-info.patch21.23 KBshaal
#180 2118743-180-twig-debug-info.patch21.74 KBBen Buske
#179 2118743-179-twig-debug-info.patch21.63 KBshaal
#178 2118743-178-twig-debug-info.patch21.82 KBshaal
#178 2118743-139-178.interdiff.txt38.33 KBshaal
#139 2118743-139-twig-debug-info.patch21.48 KBmikeker
#139 2118743-136-139.interdiff.txt1.42 KBmikeker
#136 2118743-136-twig-debug-info.patch21.47 KBmikeker
#136 2118743-134-136.interdiff.txt1.08 KBmikeker
#134 2118743-134-twig-debug-info.patch21.56 KBmikeker
#134 2118743-124-134.interdiff.txt919 bytesmikeker
#127 views-template-suggestions-2839945-2.patch805 bytesbapi_22
#124 2118743-twig-debug-info.patch21.29 KBmikeker
#124 2118743-119-124.interdiff.txt6.81 KBmikeker
#119 2118743-119-twig-debug-info.patch21.02 KBmikeker
#113 2118743-109-113.interdiff.txt2.74 KBmikeker
#113 2118743-113-twig-debug-info.patch20.99 KBmikeker
#109 2118743-109-twig-debug-info.patch22.19 KBmikeker
#109 2118743-93-109.interdiff.txt8.26 KBmikeker
#107 core-8.3.0-twig_debug_not_display-suggestions-array-2118743-107.patch18.84 KBB-Prod
#93 interdiff.txt2.73 KBAntti J. Salminen
#93 twig_debug_output_does-2118743-93.patch18.96 KBAntti J. Salminen
#89 interdiff.txt1.35 KBlauriii
#89 twig_debug_output_does-2118743-89.patch18.89 KBlauriii
#87 interdiff.txt2.12 KBlauriii
#87 twig_debug_output_does-2118743-87.patch18.93 KBlauriii
#82 twig_debug_output_does-2118743-82.patch18.56 KBlauriii
#80 twig_debug_output_does-2118743-78.patch18.57 KBAntti J. Salminen
#77 interdiff.txt2.08 KBAntti J. Salminen
#77 twig_debug_output_does-2118743-77.patch18.56 KBAntti J. Salminen
#73 http___d8_dev_.png266.65 KBjoelpittet
#73 http___d8_dev_.png294.86 KBjoelpittet
#72 twig_debug_output_does-2118743-72.patch18.4 KBlauriii
#62 2118743-62.patch18.19 KBhussainweb
#62 interdiff-59-62.txt813 byteshussainweb
#59 2118743-59.patch18.08 KBhussainweb
#56 interdiff.txt8.53 KBAntti J. Salminen
#56 2118743-56.patch17.82 KBAntti J. Salminen
#46 interdiff-2118743-45-46.txt6.31 KBAntti J. Salminen
#46 2118743-46.patch17.57 KBAntti J. Salminen
#45 interdiff.txt655 bytesrteijeiro
#45 2118743-45.patch15.23 KBrteijeiro
#43 interdiff-2118743-27-42.txt14.03 KBAntti J. Salminen
#43 2118743-42.patch15.22 KBAntti J. Salminen
#43 2118743-42-testonly.patch11.57 KBAntti J. Salminen
#41 2118743-40.patch15.35 KBAntti J. Salminen
#41 2118743-40-testonly.patch10.37 KBAntti J. Salminen
#35 2118743-35.patch11.66 KBAntti J. Salminen
#35 2118743-35-testonly.patch8.68 KBAntti J. Salminen
#33 2118743-33.patch8.51 KBAntti J. Salminen
#33 2118743-33_testonly.patch5.53 KBAntti J. Salminen
#27 2118743-27.patch2.97 KBjjcarrion
#23 interdiff.txt479 bytesbotanic_spark
#23 2118743-23.patch2.93 KBbotanic_spark
#20 interdiff.txt826 bytesbotanic_spark
#20 2118743-20.patch3.58 KBbotanic_spark
#16 interdiff.txt1.38 KBdawehner
#16 2118743-16.patch2.98 KBdawehner
#13 theme-2118743-13.patch1.6 KBlauriii
#13 interdiff-2118743-11-13.txt1.49 KBlauriii
#11 theme-2118743-11.patch1.47 KBlauriii
#3 theme-change-twig-debug-theme-call-to-theme-hooks-2118743-3.patch2.46 KBoetseli
#1 theme-2118743-1.patch1.66 KBdawehner

Issue fork drupal-2118743

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner’s picture

Status: Active » Needs review
FileSize
1.66 KB

Thank you for creating the issue.

Before

:

<div class="view-content">
      

<!-- THEME DEBUG -->
<!-- CALL: theme('views_view_unformatted') -->
<!-- BEGIN OUTPUT from 'core/modules/views/templates/views-view-unformatted.html.twig' -->
  <div class="views-row views-row-1 views-row-odd views-row-first views-row-last">
    

<!-- THEME DEBUG -->
<!-- CALL: theme('node') -->
<!-- FILE NAME SUGGESTIONS:
   * node--article.html.twig
   * node--1.html.twig
   * node--view--frontpage.html.twig
   * node--view--frontpage--page-1.html.twig
   x node.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/node.html.twig' -->
<article id="node-1" class="node node-article promoted view-mode-teaser contextual-region clearfix" data-history-node-id="1" data-edit-entity="node/1" role="article" about="/d8/node/1" typeof="schema:Article">

  <header>
    
          <h2>
        <a href="/d8/node/1">test</a>
      </h2>
        <div data-contextual-id="node:node:1:" class="contextual-render-processed contextual" role="form" style="top: 30px;"><button class="trigger focusable visually-hidden" type="button" aria-pressed="false">Open test configuration options</button><ul class="contextual-links" hidden=""><li class="quick-edit"><a href="" role="button" aria-pressed="false">Quick edit</a></li><li class="node-edit odd first"><a href="/d8/node/1/edit?destination=node">Edit</a></li><li class="node-delete even last"><a href="/d8/node/1/delete?destination=node">Delete</a></li></ul></div><span property="schema:name" content="test" class="rdf-meta"></span>

          <div class="meta submitted">
        

<!-- THEME DEBUG -->
<!-- CALL: theme('user') -->
<!-- BEGIN OUTPUT from 'core/modules/user/templates/user.html.twig' -->
<article data-edit-entity="user/1" class="profile" typeof="schema:Person" about="/d8/user/1">
  </article>

<!-- END OUTPUT from 'core/modules/user/templates/user.html.twig' -->


        <span rel="schema:author">Submitted by <a href="/d8/user/1" title="View user profile." class="username" lang="" about="/d8/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</a> on Wed, 10/23/2013 - 15:27</span><span property="schema:dateCreated" content="2013-10-23T15:27:52+00:00" class="rdf-meta"></span>
      </div>
      </header>

  <div class="content clearfix">
            <div class="field field-node--body field-name-body field-type-text-with-summary field-label-hidden edit-processed edit-field" data-edit-id="node/1/body/und/teaser"><div class="field-items"><div class="field-item even" property="schema:text"><p>test</p></div></div></div>
  </div>

      <footer class="link-wrapper">
      <ul class="links inline"><li class="node-readmore odd first"><a href="/d8/node/1" rel="tag" title="test">Read more<span class="visually-hidden"> about test</span></a></li><li class="comment-add even last"><a href="/d8/node/1#comment-form" title="Add a new comment to this page.">Add new comment</a></li></ul>
    </footer>
  
</article>

<!-- END OUTPUT from 'core/themes/bartik/templates/node.html.twig' -->


  </div>

<!-- END OUTPUT from 'core/modules/views/templates/views-view-unformatted.html.twig' -->


    </div>

After

<div class="view-content">
      

<!-- THEME DEBUG -->
<!-- CALL: theme('views_view_unformatted') -->
<!-- FILE NAME SUGGESTIONS:
   * views-view-unformatted--frontpage--page-1.html.twig
   * views-view-unformatted--page-1.html.twig
   * views-view-unformatted--default.html.twig
   * views-view-unformatted--frontpage--page.html.twig
   * views-view-unformatted--page.html.twig
   * views-view-unformatted--frontpage.html.twig
   x views-view-unformatted.html.twig
   x views-view-unformatted.html.twig
-->
<!-- BEGIN OUTPUT from 'core/modules/views/templates/views-view-unformatted.html.twig' -->
  <div class="views-row views-row-1 views-row-odd views-row-first views-row-last">
    

<!-- THEME DEBUG -->
<!-- CALL: theme('node') -->
<!-- FILE NAME SUGGESTIONS:
   * node--article.html.twig
   * node--1.html.twig
   x node.html.twig
   * node--view--frontpage.html.twig
   * node--view--frontpage--page-1.html.twig
   x node.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/bartik/templates/node.html.twig' -->
<article id="node-1" class="node node-article promoted view-mode-teaser contextual-region clearfix" data-history-node-id="1" data-edit-entity="node/1" role="article" about="/d8/node/1" typeof="schema:Article">

  <header>
    
          <h2>
        <a href="/d8/node/1">test</a>
      </h2>
        <div data-contextual-id="node:node:1:" class="contextual-render-processed contextual" role="form" style="top: 30px;"><button class="trigger focusable visually-hidden" type="button" aria-pressed="false">Open test configuration options</button><ul class="contextual-links" hidden=""><li class="quick-edit"><a href="" role="button" aria-pressed="false">Quick edit</a></li><li class="node-edit odd first"><a href="/d8/node/1/edit?destination=node">Edit</a></li><li class="node-delete even last"><a href="/d8/node/1/delete?destination=node">Delete</a></li></ul></div><span property="schema:name" content="test" class="rdf-meta"></span>

          <div class="meta submitted">
        

<!-- THEME DEBUG -->
<!-- CALL: theme('user') -->
<!-- BEGIN OUTPUT from 'core/modules/user/templates/user.html.twig' -->
<article data-edit-entity="user/1" class="profile" typeof="schema:Person" about="/d8/user/1">
  </article>

<!-- END OUTPUT from 'core/modules/user/templates/user.html.twig' -->


        <span rel="schema:author">Submitted by <a href="/d8/user/1" title="View user profile." class="username" lang="" about="/d8/user/1" typeof="schema:Person" property="schema:name" datatype="">admin</a> on Wed, 10/23/2013 - 15:27</span><span property="schema:dateCreated" content="2013-10-23T15:27:52+00:00" class="rdf-meta"></span>
      </div>
      </header>

  <div class="content clearfix">
            <div class="field field-node--body field-name-body field-type-text-with-summary field-label-hidden edit-processed edit-field" data-edit-id="node/1/body/und/teaser"><div class="field-items"><div class="field-item even" property="schema:text"><p>test</p></div></div></div>
  </div>

      <footer class="link-wrapper">
      <ul class="links inline"><li class="node-readmore odd first"><a href="/d8/node/1" rel="tag" title="test">Read more<span class="visually-hidden"> about test</span></a></li><li class="comment-add even last"><a href="/d8/node/1#comment-form" title="Add a new comment to this page.">Add new comment</a></li></ul>
    </footer>
  
</article>

<!-- END OUTPUT from 'core/themes/bartik/templates/node.html.twig' -->


  </div>

<!-- END OUTPUT from 'core/modules/views/templates/views-view-unformatted.html.twig' -->


    </div>

The last submitted patch, theme-2118743-1.patch, failed testing.

oetseli’s picture

Issue summary: View changes
Status: Needs work » Needs review
FileSize
2.46 KB

I have another suggestion and patch that changes the way Twig debug prints out the theme call itself.

Instead of doing this:

<!-- CALL: theme('views_view_unformatted') -->
<!-- BEGIN OUTPUT from 'core/modules/views/templates/views-view-unformatted.html.twig' -->

It does this:

<!-- THEME HOOKS:
   * views_view_unformatted__twig_article_test__page_1
   * views_view_unformatted__page_1
   * views_view_unformatted__twig_article_test__page
   * views_view_unformatted__page
   * views_view_unformatted__twig_article_test
   x views_view_unformatted
-->
<!-- BEGIN OUTPUT from 'core/modules/views/templates/views-view-unformatted.html.twig' -->

Views does this a lot. That there are no theme_hook_suggestions, but rather a lot of hooks in theme()-function's $hook array. What do you think?

Status: Needs review » Needs work

oetseli’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work
star-szr’s picture

Status: Needs work » Postponed
star-szr’s picture

Status: Postponed » Needs work

Re-activating because that issue got shot down.

dawehner’s picture

@Cottser
Do you have a suggestion which of the two aproaches would you prefer?

lauriii’s picture

Status: Needs work » Needs review
FileSize
1.47 KB

I like #1 more so I rerolled it and most likely fixed tests.

Status: Needs review » Needs work

The last submitted patch, 11: theme-2118743-11.patch, failed testing.

lauriii’s picture

Status: Needs work » Needs review
FileSize
1.49 KB
1.6 KB

Status: Needs review » Needs work

The last submitted patch, 13: theme-2118743-13.patch, failed testing.

star-szr’s picture

Issue tags: +Needs tests

Thanks for working on this @lauriii!

dawehner’s picture

Status: Needs work » Needs review
FileSize
2.98 KB
1.38 KB

I wanted to ensure that we have some test coverage in views, you never know.

Status: Needs review » Needs work

The last submitted patch, 16: 2118743-16.patch, failed testing.

The last submitted patch, 11: theme-2118743-11.patch, failed testing.

botanic_spark’s picture

Assigned: Unassigned » botanic_spark
Status: Needs work » Needs review
FileSize
3.58 KB
826 bytes

It seams that TwigDebugTest is not passing because debug info is in wrong order. This happens because of the array_reverse in

 if ($hook != $theme_hooks) {
    $suggestions = array_merge($suggestions, (array) $theme_hooks);
    $suggestions = array_reverse($suggestions);
  }

My solution is to reverse it again in the twig.engine but just in case when #theme element is passed.

  // Reverse suggestions array before merging with derived suggestions.
  $variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);
  $variables['theme_hook_suggestions'] = array_merge($derived_suggestions, $variables['theme_hook_suggestions']);
  $variables['theme_hook_suggestions'][] = $base_hook;
dawehner’s picture

+++ b/core/themes/engines/twig/twig.engine
@@ -81,6 +81,8 @@ function twig_render_template($template_file, $variables) {
+      // Reverse suggestions array before merging with derived suggestions.
+      $variables['theme_hook_suggestions'] = array_reverse($variables['theme_hook_suggestions']);

This is really not obvious ... instead of explaning WHAT you do here, try to explain WHY you do it, because this is information not encoded in the code itself.

botanic_spark’s picture

Status: Needs review » Needs work

I spoke with @lauriii alot about this during last few days.
In theme.inc there is this part

if ($hook != $theme_hooks) {
    $suggestions = array_merge($suggestions, (array) $theme_hooks);
    $suggestions = array_reverse($suggestions);
}

For some reason array_reverse is done here, but this is only for case when suggestion is passed directly to theme function. For example
'#theme' => 'node__foo__bar',

But the thing is that in all other cases, the suggestions array is not reversed and this is braking the tests.

In twig.engine this array is reversed again in order to display debug info properly, but order of suggestions is different for case when
'#theme' => 'node__foo__bar', is passed.

So my "dirty" fix was to reverse it again in twig.engine but just for that specific case. This made tests to pass.

Both @lauriii and me agreed that this is not the solution, but it made clear what is the problem, and we need to avoid this double or even triple reversing.

I will keep working on this, and post some update when i have more info.

Ofcourse, every suggestion is welcome.

botanic_spark’s picture

Status: Needs work » Needs review
FileSize
2.93 KB
479 bytes

To avoid multiple array inversion i just removed

   if ($hook != $theme_hooks) {
     $suggestions = array_merge($suggestions, (array) $theme_hooks);
-    $suggestions = array_reverse($suggestions);
   }

from theme.inc

This was already tried in #11 but for some reason tests were not passing.

I have tried this correction on my local testbot instance and it's passing.

lauriii queued 23: 2118743-23.patch for re-testing.

Status: Needs review » Needs work

The last submitted patch, 23: 2118743-23.patch, failed testing.

lauriii’s picture

Issue tags: +Needs reroll
jjcarrion’s picture

Issue tags: -Needs reroll
FileSize
2.97 KB

I have made just the reroll

jjcarrion’s picture

Status: Needs work » Needs review
dawehner’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests

We do have tests, not part of twig tests itself but at least for the views problem.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review
  1. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -232,6 +234,9 @@ protected function theme($hook, $variables = array()) {
    +    if ($hook != $theme_hooks) {
    +      $suggestions = array_merge($suggestions, (array) $theme_hooks);
    +    }
    

    It seems strange and slightly dangerous that we're altering this code to improve debug output.

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -232,6 +234,9 @@ protected function theme($hook, $variables = array()) {
         if (isset($info['base hook'])) {
           $suggestions[] = $hook;
         }
    

    Is this even needed now? And if we do remove this - can be we remove the array_unique in twig.engine?

botanic_spark’s picture

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

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

Adding a test that should expose a problem in the current implementation: When theme is passed an array of hooks that contains a base hook (as is often the case), using hook_theme_suggestions_HOOK doesn't work. This is because the base hook from the array will always be found before the suggestion. Working on a fix...

#30:

1. ThemeManager might be a more natural place for the debug output as the selection of the hook isn't really the theme engine's concern. Would need a more general equivalent for twig_debug to move it there.

2. I think we can get rid of it. The current patch relies on it but after fixing the issue that the test exposes, the cases where it's needed should also go away.

Status: Needs review » Needs work

The last submitted patch, 33: 2118743-33.patch, failed testing.

Antti J. Salminen’s picture

Adding a couple of tests for the debug markup. I noticed the current committed version has duplicate suggestions in the debug output when there are specific suggestions in the hook passed to theme(). Also added a basic test for the array of hooks.

Antti J. Salminen’s picture

Status: Needs work » Needs review

Just triggering test runs, still needs work.

Status: Needs review » Needs work

The last submitted patch, 35: 2118743-35.patch, failed testing.

The last submitted patch, 35: 2118743-35-testonly.patch, failed testing.

star-szr’s picture

Just want to say thanks for working on this @Antti J. Salminen!

star-szr’s picture

Priority: Normal » Major
Issue tags: +DX (Developer Experience), +TX (Themer Experience), +Needs backport to D7

Tagging and bumping.

Antti J. Salminen’s picture

Status: Needs work » Needs review
FileSize
10.37 KB
15.35 KB

Haven't been able to work very fast on this unfortunately but here's some progress. I believe this would be what the approach suggested in the first patch looks like with everything in place.

What do you think about the assumption this makes that for arrays, base hooks should only be the last element? Without it those base hooks override direct suggestions but not other suggestions. It would mean it's impossible to represent the complete suggestions order with just a flat list.

The last submitted patch, 41: 2118743-40-testonly.patch, failed testing.

Antti J. Salminen’s picture

The tests-only patch had some issues that should now be fixed. Additionally made some extremely small adjustments. Also adding an interdiff to the patch in #27. I'm thinking the suggestion selection in theme() could be reworked a bit from this.

The last submitted patch, 43: 2118743-42-testonly.patch, failed testing.

rteijeiro’s picture

FileSize
15.23 KB
655 bytes

Fixed a small nitpick.

Antti J. Salminen’s picture

Assigned: Antti J. Salminen » Unassigned
FileSize
17.57 KB
6.31 KB

Reworked the generation of the derived suggestions, fixed an issue in the patch and improved a test to detect it. If the tests don't come up with any problems this could use some looking at by others I think.

akalata’s picture

Since we're refactoring theme() function in #2348381: [META-0 theme functions left] Convert/refactor core theme functions, is this issue going to be applicable in D8?

Antti J. Salminen’s picture

#47: To me it looked like #2348381 only concerns theme hook implementations and in that case there would be no overlap.

akalata’s picture

@Antti, the goal of #2348381 is to replace theme() functions with template files. If we're doing that, then this issue (fixing theme() function debugging) will be useless.

lauriii’s picture

@akalata theme() functions will be still in there and there will be contribs using them so I wouldn't say refactoring it is useless. Even though they are highly deprecated.

Antti J. Salminen’s picture

@Akalata: The debug output that is being fixed is presented as a list of templates and can be implemented with templates. Are you saying that issue plans to also replace the current suggestions?

akalata’s picture

@laurii @Antti ah, I see. My initial read of the issue was that template suggestions coming from *.html.twig files were working, and that ones coming from theme() functions were not.

star-szr’s picture

Title: Twig debug output does not display all suggestions when an array of suggestions is passed to theme() » Twig debug output does not display all suggestions when an array of suggestions is passed to #theme

This might be a better title then :)

akalata’s picture

Debugging output BEFORE

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
   * block--seven-content.html.twig
   * block--system-main-block.html.twig
   * block--system.html.twig
   x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/block/block.html.twig' -->
<div id="block-seven-content" class="block block-system">
  
    
      

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'container' -->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/form/container.html.twig' -->
<div class="views-element-container">

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'views_view' -->
<!-- BEGIN OUTPUT from 'core/modules/views/templates/views-view.html.twig' -->
<div class="view view-content view-id-content view-display-id-page_1 view-dom-id-b58a3131633d33a899a05166e6b98a4496c36bcb5f0ff59679d4e4d60835dff1">
  
    
        <div class="view-filters">
      

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'form' -->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/form/form.html.twig' -->
<form class="views-exposed-form" action="/admin/content" method="get" id="views-exposed-form-content-page-1" accept-charset="UTF-8">

Debugging output AFTER

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
   * block--seven-content.html.twig
   * block--system-main-block.html.twig
   * block--system.html.twig
   x block.html.twig
-->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/block/block.html.twig' -->
<div id="block-seven-content" class="block block-system">
  
    
      

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'container' -->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/form/container.html.twig' -->
<div class="views-element-container">

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'views_view' -->
<!-- FILE NAME SUGGESTIONS:
   * views-view--content--page-1.html.twig
   * views-view--page-1.html.twig
   * views-view--default.html.twig
   * views-view--content--page.html.twig
   * views-view--page.html.twig
   * views-view--content.html.twig
   x views-view.html.twig
-->
<!-- BEGIN OUTPUT from 'core/modules/views/templates/views-view.html.twig' -->
<div class="view view-content view-id-content view-display-id-page_1 view-dom-id-c20f87f4675e558b08d1230ece112410fad4c96840483893615041aa36ca8dcd">
  
    
        <div class="view-filters">
      

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'form' -->
<!-- BEGIN OUTPUT from 'core/themes/classy/templates/form/form.html.twig' -->
<form class="views-exposed-form" action="/admin/content" method="get" id="views-exposed-form-content-page-1" accept-charset="UTF-8">

I don't know testing well enough to review the added tests, sorry.

star-szr’s picture

Status: Needs review » Needs work

Been meaning to review this for a while so here's an initial pass, I'm not sure on some of the logic changes in ThemeManager just yet, need to do some manual testing/debugging on those.

Thanks for keeping on this @Antti J. Salminen and thank you @akalata for testing!

  1. +++ b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
    @@ -157,6 +157,28 @@ public function testSuggestionsAlterInclude() {
    +   * Tests hook_theme_suggestions_HOOK().
    +   */
    +  public function testArraySuggestions() {
    

    Could probably use a better summary line here, saying something about arrays.

  2. +++ b/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php
    @@ -133,6 +140,18 @@ function suggestionAlterInclude() {
    +    return array(
    +      '#theme' => array(
    +        'theme_test_array_suggestions__not_implemented',
    +        'theme_test_array_suggestions__not_implemented_2',
    +        'theme_test_array_suggestions'),
    +    );
    

    Minor: Needs some small adjustments to meet https://www.drupal.org/coding-standards#array.

  3. +++ b/core/modules/views/src/Tests/ViewsThemeIntegrationTest.php
    @@ -81,4 +81,29 @@ public function testThemedViewPage() {
    +    $build = [
    +      '#type' => 'view',
    +      '#name' => 'test_page_display',
    +      '#display_id' => 'default',
    +      '#arguments' => array(),
    +    ];
    

    Minor: Go all the way with short array syntax, change the last array() :)

  4. +++ b/core/modules/views/src/Tests/ViewsThemeIntegrationTest.php
    @@ -81,4 +81,29 @@ public function testThemedViewPage() {
    +    $this->assertTrue(strpos($output, '* views-view--test-page-display--default.html.twig') !== FALSE);
    +    $this->assertTrue(strpos($output, '* views-view--default.html.twig') !== FALSE);
    +    $this->assertTrue(strpos($output, '* views-view--test-page-display.html.twig') !== FALSE);
    +    $this->assertTrue(strpos($output, 'x views-view.html.twig') !== FALSE);
    

    I know it's uglier to test but IMO we should really be testing the order of the suggestions because that is very important.

  5. +++ b/core/themes/engines/twig/twig.engine
    @@ -68,31 +68,20 @@ function twig_render_template($template_file, array $variables) {
    -      // Only add the original theme hook if it wasn't a directly called
    -      // suggestion.
    -      if (strpos($variables['theme_hook_original'], '__') === FALSE) {
    ...
    +      // Only add the original theme hook if it wasn't a directly called
    +      // suggestion.
    

    Seems like this comment doesn't apply anymore so let's remove it. Correct me if I'm wrong :)

  6. +++ b/core/themes/engines/twig/twig.engine
    @@ -68,31 +68,20 @@ function twig_render_template($template_file, array $variables) {
    +      if ( $pos !== FALSE) {
    

    Minor: Coding standards issue, extra space inside parens.

Antti J. Salminen’s picture

Status: Needs work » Needs review
FileSize
17.82 KB
8.53 KB

Thanks for the nice review Cottser and also thanks for testing Akalata! I've tried to fix the issues in this patch. Also reformatted the tests and fixed some other small things I noticed.

Hoping to get feedback on the logic changes, especially the assumption that only the last direct array suggestion can be a base hook. :) It seems reasonable to me to force there to be a linear list for the suggestion priorities. It matches how it's used in the places I've found and also the original intent of the feature (going from specific to generic, alternative to just providing a pattern).

star-szr’s picture

@Antti J. Salminen thanks for keeping on this! I definitely missed your patch in all the craziness of DrupalCon :) changes look very good!

Can you expand a bit more on this please? Perhaps with some code examples?

the assumption that only the last direct array suggestion can be a base hook

star-szr’s picture

Bump. Patch still applies :)

hussainweb’s picture

Rerolled.

Status: Needs review » Needs work

The last submitted patch, 59: 2118743-59.patch, failed testing.

The last submitted patch, 59: 2118743-59.patch, failed testing.

hussainweb’s picture

Status: Needs work » Needs review
FileSize
813 bytes
18.19 KB

Fixing tests (hopefully).

akalata’s picture

I will take a look at reviewing this.

akalata’s picture

Another round of manual testing of template suggestion debug info:

Content admin page as a good set of debug messages to look at for *.html.twig suggestions: I compared the beginning of the system_main content block down to just inside the beginning of the exposed filters form. Existing correct template suggestions have not changed, and new template suggestions are showing up for views_view and views_exposed_form hooks.

I was trying to find debug info for the few remaining core theme functions, though I realized that those might not be showing up because they aren't Twig-based? If this is the case, the "THEME DEBUG" and "THEME HOOK" might be misleading (since I expected theme hook information to also show up here). If we can't extend the debug info to theme_ functions, maybe we need to rename the labels? Or is this an RTFM moment since services.yml clearly states that it's just for Twig functions?

I'm not sure if the request for elaboration in #57 happened elsewhere, but I think the logic is sound (and certainly how I've expected template suggestions to work). I also tested to be sure that the order of suggestions follows the order described in the documentation (and updated documentation where it differed from actual behavior in HEAD).

Antti J. Salminen’s picture

Sorry, I pretty much just forgot about expanding on what I meant with the difference.

Here's an example:

  • Take ['mandarin__spain', 'tangerine', 'mandarin__brazil'] as an example of directly passed array of theme hooks
  • If tangerine is implemented, hook_theme_suggestions_tangerine() will be called for it (instead of mandarin), and it can add for example 'tangerine__florida'
  • In the old version this will result in tangerine__florida being chosen if it's implemented, in the patch version it won't because base hooks are assumed to be in the last element

I haven't seen any actual use with base hooks in the middle like this and it's definitely pointless without multiple different base hooks involved. To me it seems like it could be just a side-effect of the current implementation.

@Akalata: Thanks for the review. Your point about theme functions not having debug information is good and it is caused by the printing of the debug information being part of the Twig engine currently. I had the thought that this functionality isn't really specific to the used theme engine and could be moved to a better place myself earlier as well.

akalata’s picture

@Antti can you think of any case where multiple base hooks would be an optimal solution? Or where the base hook isn't the last hook in the list of suggestions?

While technically possible to do with the code, I don't think it's something that people should be doing - so I'm personally not worried about it, but interested in other perspectives.

akalata’s picture

also re: #65, adding suggestions for theme_ function implementations would be cool, but would be out of scope for this issue (but would be great to have!). Could we think about changing the label as an intermediate step?

Antti J. Salminen’s picture

#66: I can't think of those examples and I tend to agree with you, but I've seen one example where the base hook isn't the last. The first test in #2111079: Add @code sample and test coverage per hook_theme_suggestions[_HOOK]() and hook_theme_suggestions[_HOOK]_alter() does that. Maybe @Cottser could comment on if that's based on a real-world use case?

#67: I agree changing the label could be a good idea, not sure what the replacement would be...

star-szr’s picture

@Antti J. Salminen I think I just did that test wrong, when you pass an array of hooks it will stop at the first one it finds so that should be reversed in the test.

star-szr’s picture

Or in other words more specific should come first.

flocondetoile’s picture

Status: Needs review » Needs work

Patch #62 has worked fine on Drupal 8.0.1. But applying patch after upgraded to 8.0.2 add the generic suggestion (block.html.twig, node.html.twig, etc.) in first position and so is always matched.

lauriii’s picture

Status: Needs work » Needs review
FileSize
18.4 KB

Rerolled the patch

joelpittet’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community
FileSize
294.86 KB
266.65 KB

Unless anybody has an issue with this solution it seems to fix things up and provides tests.

Screenshots.

Before

After

@akalata could you open up a follow-up to change the label and discuss what it should say so we can fix this separate. I also think it may alleviate confusion but since theme functions are deprecated or being deprecated it may be only good for D7.

alexpott’s picture

I'm not sure about this change - doesn't it mean we're doing a lot working stuff out in the ThemeManager that we will only use if twig debug is on?

dawehner’s picture

@alexpott What is the problem with that? Its not like dramatically more work and it actually fixes a bug

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  • +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -161,33 +162,33 @@ public function render($hook, array $variables) {
    +    if (!$theme_registry->has($hook)) {
    

    I think this can just be !$hook_found now... which helps with working out how all this hangs together.

  • +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -161,33 +162,33 @@ public function render($hook, array $variables) {
    +    // Get all the more generic fallbacks and check for them if there's no
    +    // implementation yet. If there's still no implementation, log an error and
    +    // return an empty string.
    

    This comment needs work. I suggest something along the lines of: Get the generic fallbacks. If a valid hook implementation has not been found, check each fallback until one is.

    The If there's still no implementation, log an error and return an empty string. is redundant and wrong - we return FALSE. I was going to suggest moving to above the relevant if but doing that made me realise this.

Antti J. Salminen’s picture

@alexpott: I made the suggested changes, had to do a few more to let $hook_found be always defined. Does this look better?

Antti J. Salminen’s picture

Status: Needs work » Needs review

Forgot to set needs review to see if it passes tests.

Status: Needs review » Needs work

The last submitted patch, 77: twig_debug_output_does-2118743-77.patch, failed testing.

Antti J. Salminen’s picture

Status: Needs work » Needs review
FileSize
18.57 KB

Oops, helps to have the right branch. This should apply cleanly I hope...

Status: Needs review » Needs work

The last submitted patch, 80: twig_debug_output_does-2118743-78.patch, failed testing.

lauriii’s picture

Status: Needs work » Needs review
FileSize
18.56 KB

Simple reroll

Status: Needs review » Needs work

The last submitted patch, 82: twig_debug_output_does-2118743-82.patch, failed testing.

lauriii’s picture

Version: 8.0.x-dev » 8.1.x-dev
Status: Needs work » Needs review

This probably helps a bit

Status: Needs review » Needs work

The last submitted patch, 82: twig_debug_output_does-2118743-82.patch, failed testing.

The last submitted patch, 82: twig_debug_output_does-2118743-82.patch, failed testing.

lauriii’s picture

Status: Needs work » Needs review
FileSize
18.93 KB
2.12 KB

This bit of code is very complex and for that reason hard to understand. I tried to add few lines of docs to make it more clear what happens there and for what reason. Let's see whats test bots response for this.

There was also problem where we were setting log messages in unnecessary cases.

Status: Needs review » Needs work

The last submitted patch, 87: twig_debug_output_does-2118743-87.patch, failed testing.

lauriii’s picture

Status: Needs work » Needs review
FileSize
18.89 KB
1.35 KB
star-szr’s picture

  1. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -145,48 +145,52 @@ public function render($hook, array $variables) {
    +    // All theme hooks are converted into an array. Save info to be used later
    +    // whether conversion has happened.
    

    I think the wording might be a bit confusing here. Maybe either no comment at all (or consider a slightly more descriptive var name like original_hook_is_array) or something like "All theme hooks are converted into an array, so we create $hook_is_array so that it can be checked later."

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -145,48 +145,52 @@ public function render($hook, array $variables) {
    +    // Check for hook implementation. If an array of hook candidates were
    +    // passed, use the first one that has an implementation.
    +    foreach ($theme_hooks as $candidate) {
    

    Can we check $hook_is_array here before doing the foreach? Otherwise I think we do unnecessary processing when $hook is a string. What do you think?

greggmarshall’s picture

#89 solved an issue I was having with templates for certain entity references inside the paragraphs module, thanks.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Antti J. Salminen’s picture

How about this for avoiding the is_array(). Also tried to clarify the comment accompanying the rather weird behavior related to the watchdog messages vs. arrays of hooks.

star-szr’s picture

Version: 8.2.x-dev » 8.1.x-dev

I think this fix could be included in 8.1.x.

clemens.tolboom’s picture

Please add this to 8.1.x :-)

I needed this info for 8.0.5 so added kint($hook) in Drupal/Core/Theme/ThemeManager.php:136 render method like

  public function render($hook, array $variables) {
    kint($hook);
dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Nice, we moved logic from the template engine more towards the theme layer. This is great, given that the theme engine should not have to implement this complex logic.
We also extended the test coverage for the new capability to see views template suggestions ...

The changes to the ThemeManager look sane as well.

+++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
@@ -145,48 +145,52 @@ public function render($hook, array $variables) {
+    while ($pos = strrpos($hook_pattern, '__')) {
+      // Save all derived hooks to be used later as a theme suggestion.
+      $derived_hooks[] = $hook_pattern;
+      $hook_pattern = substr($hook_pattern, 0, $pos);
+      if (!$hook_found && $hook_found = $theme_registry->has($hook_pattern)) {
+        $hook = $hook_pattern;
       }

out of scope of this issue: On the longrun I'm wondering whether we could move the logic to retrieve theme registry entries to the theme registry and let the theme manager deal with the rest of the problem space

star-szr’s picture

Version: 8.1.x-dev » 8.2.x-dev

Since this changes so much I don't think we should commit it to 8.1.x at this time (too risky), but we can get it into 8.2.x I think :)

catch’s picture

Status: Reviewed & tested by the community » Needs review
+++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
@@ -145,48 +145,51 @@ public function render($hook, array $variables) {
+    if (!$hook_found) {
+      // Do not create a watchdog warning for arrays of hooks because their
+      // every element is allowed to be unimplemented.

I don't understand 'their every element is allowed to be unimplemented' - is this 'every element of the array'?

Antti J. Salminen’s picture

@catch: Yeah, that's what the comment is trying to say.

star-szr’s picture

@lauriii and I pair reviewed this patch for a while a couple days ago and I spent several hours today going over everything and trying some real world examples to see if I could break it.

Summary of what I'm asking for after this review, detailed thoughts below the horizontal rule:

  1. Write a change record because we are adding more output to $variables['theme_hook_suggestions'].
  2. Add unit tests and another variation on the web test around at least the parts of Drupal\Core\Theme\ThemeManager::render() that we are changing here - deriving theme suggestions especially.
  3. Four code and docs changes.

  1. This could likely use a change record because we are changing the value of $variables['theme_hook_suggestions'].
  2. I may have found a slight logic change with the patch (I think point #3 below may fix it but I've been staring at it too long today). I think in a followup we should revisit the logic around this to make sure it makes sense but probably in another issue. The logic is a bit complex and it would be best to focus this on fixing twig_debug for these use cases and not change the behaviour if we can help it. I would feel much better if we had some unit tests around some of the logic we are changing inside render() to make sure we are not changing behaviours.

    For the "pattern" used to derive more generic suggestions, I think there is a behaviour change and perhaps a bit of an assumption that the last item in the array of theme hooks is "the original hook" - there is a comment that says:

    +    // Remove the last item of the array which is the original hook and use it
    +    // as a pattern.

    Before: First theme hook in the array that is implemented, OR if none are implemented, the last theme hook.

    For this last part I'm not sure if it's a bug or by design. I'm talking specifically about the $hook = $candidate; after foreach ($hook as $candidate) {. When nothing is found $hook will be the last candidate that was checked.

    After: Always the last theme hook in the array regardless of implementations (via array_pop).

    Below are a couple example render arrays you can use to test this behaviour with and without the patch (the behaviour in terms of which templates are picked up seems to stay the same).

    $kittens = [
      '#theme' => [
        'item_list__stuff__things__kittens',
        'item_list__stuff__things',
        'item_list',
      ],
      '#items' => [1, 2, 3],
    ];
    
    $kittens = [
      '#theme' => [
        'item_list__stuff__things__kittens',
      ],
      '#items' => [1, 2, 3],
    ];
    

    With and without this patch, using the first render array a template of item-list--stuff.html.twig won't get picked up. I don't think any of the current web tests cover that behaviour either, so we should add that too IMO.

  3. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -145,48 +145,51 @@ public function render($hook, array $variables) {
    +    $hook_pattern = array_pop($theme_hooks);
    

    Based on the logic from twig.engine we are porting in here I think it might make more sense to use $original_hook rather than array_pop($theme_hooks);.

  4. The comment @catch pointed out in #98 could use some rewording. I don't think it's necessarily helpful to get into detail here, I would suggest something really simple like:

    Do not log warnings when an array of theme hooks is passed in.

  5. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -145,48 +145,51 @@ public function render($hook, array $variables) {
    +      if (!is_array($hook)) {
    +        \Drupal::logger('theme')->warning('Theme hook %hook not found.', array('%hook' => $candidate));
           }
    

    I think it would be less confusing to use $hook here rather than $candidate because we know $hook is a string.

  6. +++ b/core/themes/engines/twig/twig.engine
    @@ -82,31 +82,18 @@ function twig_render_template($template_file, array $variables) {
    +      $pos = strpos($variables['theme_hook_original'], '__');
    ...
    +      if ($pos !== FALSE) {
    +        $suggestions[] = substr($variables['theme_hook_original'], 0, $pos);
    +      }
    +      else {
             $suggestions[] = $variables['theme_hook_original'];
           }
    

    This logic could use a comment to say that it's appending the base hook or something along those lines.

Antti J. Salminen’s picture

@Cottser:

Thanks for taking the time to thoroughly review!

Regarding some of the items:

2.
If the hook is implemented the currently committed version doesn't use the pattern so it doesn't really matter. The only case where this would make a difference as far as I know is the case that I mentioned in #41, #56 and tried to describe in #65.

The reason was that If alternate base hooks (with or without a suggestion) are permitted in elements besides the last one, the list of possible templates to implement won't be just a single list of template names. It means that more suggestions are possibly inserted into the list by hook_theme_suggestions_HOOK() in the case that they have an implementation in the registry.

At least this is what I believe the implications are, it's been a year since I really looked at this in depth. My assumption was that this is not something that was ever intended as a real use case, I've found nothing implying so in code or ancient issue discussions and it certainly makes the way the hooks are selected more complicated.

3.
As outlined above, If this was changed to $original_hook, the list of hooks that twig_debug outputs would change depending on what you have implemented and would not show the full list of possible template/theme function names.

4.
Don't you think the explanation is the part that is actually useful about the comment? Without it, it just states the exact same thing you can see from the lines it's commenting on. I can't really tell what @catch's stance on this was from his comment.

The reason for the behavior isn't obvious to me from the code and I added the explanation because I was confused enough that I didn't properly address it in a version of this patch.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

kclarkson’s picture

Would love to see this move forward.

Antti J. Salminen’s picture

I looked at the current functionality and the patch to carefully look at the possible concerns in detail and I noticed there is one issue that needs addressing related to what @Cottser wrote previously: If there is a hook derived from a base hook in the array that does not follow the naming pattern of suggestions (name doesn't start with the base hook and have the suggestion(s) separated with '__'), the displayed base hook for the Twig debug output will not be correct.

Other than that I believe what I wrote before is correct provided that the assumption I have mentioned previously, namely that all the hooks in the passed theme hook array *must* have the same base hook holds true. I hope that I properly addressed the other concerns in @Cottser's review there in that previous comment. I think coming up with a fix for the remaining problem and adding some tests that expose the assumptions/behavior for added clarity and coverage as he mentioned is a good way forward. I've also searched all of contrib for usages where the assumption regarding the base hook would be a problem, I'll report my findings once that's finished.

lauriii’s picture

Issue tags: +Triaged core major

@alexpott, @Cottser, @joelpittet, @xjm, and I discussed this and agreed that this is a major bug because of the widespread TX issues this causes. This mostly effects theming Views, which is a common use case. There are no known workarounds for this.

This is also a regression from Drupal 7 where views used to provide this information in the Views UI, and now it is not available anywhere.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

B-Prod’s picture

This patch applies specifically to Drupal 8.3.0, to be used in a Composer file.

mikeker’s picture

Issue tags: +Baltimore2017

I'm working (off and on) to incorporate @Cottser's feedback incorporated into a new patch during the DC Baltimore sprints.

mikeker’s picture

Status: Needs work » Needs review
FileSize
8.26 KB
22.19 KB

Posting my work in progress. Changes in this patch:

  • Rewording of some comments for clarity/grammar
  • Removed the $original_hook variable as it is not needed
  • Added some tests to cover a more specific suggestion being used over a more general one
  • Added tests for invalid single theme suggestions (one that derives to a valid suggestion and one that does not)

I still need to address #100.2.

mikeker’s picture

Status: Needs review » Needs work

The testbot is happy, but back to Needs Work until #100.2 is addressed. Also realized we're missing tests for when there is an array of options that aren't implemented but one of the derived options is.

clemens.tolboom’s picture

+++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
@@ -210,9 +205,11 @@ public function render($hook, array $variables) {
+
+    // Save the original theme hook, so it can be supplied to theme variable
+    // preprocess callbacks.
     $variables += [
-      'theme_hook_original' => $original_hook,
+      'theme_hook_original' => $candidate,
     ];

Is the _original theme hook_ or the _candidate_ supposed to be saved? Either adjust the comment or revert $variables.

mikeker’s picture

@clemens.tolboom, thank you for the review.

Is the _original theme hook_ or the _candidate_ supposed to be saved? Either adjust the comment or revert $variables.

They are the same. Earlier, we set a variable named $original_hook that was only used to set $variables['original_hook']. That seemed extraneous to me, but I suppose it did help with readability...

mikeker’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests, -Needs followup
FileSize
20.99 KB
2.74 KB

I believe that #2752443: Incorrect order and duplicate theme hook suggestions is the appropriate place to handle the logic side of this issue, namely the order of suggestions and whether derivative suggestions are used for both string and array #theme items. I *think* this addresses @Cottser's concerns in #100.2 so I'm removing the Needs followup tag.

The tests I considered missing in #110 should probably be handled in #2752443: Incorrect order and duplicate theme hook suggestions as well, so I'm removing the "Needs tests" tag. I believe we've got the tests we need to cover the fact the debug info doesn't appear. Plus some extras that would be better handled in the followup (see the interdiff).

mikeker’s picture

Issue tags: -Needs change record

Added a draft CR.

hanoii’s picture

I just tried this and it works very nice and for twig debugging views is almost a must.

lauriii’s picture

Status: Needs review » Needs work

Thanks for your help trying to get this issue landed. I'm starting to be pretty confident about this, but there are a few things I think we should still try to solve here.

  1. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -140,48 +140,43 @@ public function render($hook, array $variables) {
    +      if (is_string($hook)) {
    

    We will have to change this since the $hook is now always an array. We probably should also add test coverage for this since the tests are passing and it seems like this was broken.

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -210,9 +205,11 @@ public function render($hook, array $variables) {
    +      'theme_hook_original' => $candidate,
    

    I don't fully understand why is the original theme hook now determined. Probably we should find this value in another way than we do currently or at least document how it is determined.

mikeker’s picture

@lauriii, thank you for the review!

re: #116:

We will have to change this since the $hook is now always an array.

I think there's still plenty of places we call render with a string instead of an array for $hook. And we don't force $hook to be an array in the code so I don't think this is correct.

Agreed, though, I couldn't find a test for the warning when an invalid single template string is passed.

I don't fully understand why is the original theme hook now determined.

That makes two of us... :)

Honestly, that was in the original code so I think the hope was to change as little as possible. There is also a lot of confusion on how theme suggestions should be ordered (least-to-most specific or the opposite) and how derived suggestions are to be included in the mix. Is there a source of truth for how this should be handled?

clemens.tolboom’s picture

Needs work?

sites/drupal/d8/www % git apply 2118743-113-twig-debug-info.patch
error: core/modules/views/src/Tests/ViewsThemeIntegrationTest.php: No such file or directory

mikeker’s picture

Status: Needs work » Needs review
FileSize
21.02 KB

Rerolled. Tests moved to core/modules/views/tests/src/Functional/ViewsThemeIntegrationTest.php.

mlncn’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +DrupalCampMontréal2017

Yay!!! Template suggestions for Views! Fantastic work everyone.

Working great.

bobthebuilder’s picture

The patch, #119, fixed the problem for me as well. Thanks.

star-szr’s picture

Status: Reviewed & tested by the community » Needs work

Thanks, everyone! Happy to see this RTBC. I got part way through a review and this is looking very good overall.

The change record should probably also indicate that $variables['theme_hook_suggestions'] will be changing in the scenario in question here (array of theme hooks passed to #theme).

Some minor feedback:

  1. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -140,48 +140,43 @@ public function render($hook, array $variables) {
    +        \Drupal::logger('theme')->warning('Theme hook %hook not found.', array('%hook' => $hook));
    
    +++ b/core/modules/system/src/Tests/Theme/ThemeSuggestionsAlterTest.php
    @@ -152,6 +152,31 @@ public function testSuggestionsAlterInclude() {
    +    \Drupal::service('module_installer')->install(array('theme_suggestions_test'));
    
    +++ b/core/modules/system/src/Tests/Theme/TwigDebugMarkupTest.php
    @@ -19,22 +19,30 @@ class TwigDebugMarkupTest extends WebTestBase {
    +    \Drupal::service('theme_handler')->install(array('test_theme'));
    ...
    +    $this->drupalCreateContentType(array('type' => 'page'));
    
    @@ -80,4 +88,65 @@ public function testTwigDebugMarkup() {
    +    \Drupal::service('module_installer')->install(array('theme_suggestions_test'));
    
    +++ b/core/modules/system/tests/modules/theme_suggestions_test/theme_suggestions_test.module
    @@ -55,3 +55,10 @@ function theme_suggestions_test_theme_suggestions_theme_test_specific_suggestion
    +  return array('theme_test_array_suggestions__suggestion_from_hook');
    
    +++ b/core/modules/system/tests/modules/theme_test/src/ThemeTestController.php
    @@ -106,6 +106,13 @@ public function generalSuggestionAlter() {
    +    return array('#theme' => 'theme_test_specific_suggestions__not__found');
    
    @@ -128,6 +135,33 @@ public function suggestionAlterInclude() {
    +    return array(
    +      '#theme' => array(
    ...
    +    return array(
    +      '#theme' => array(
    

    Minor: These should all use the short array syntax ([]) per https://www.drupal.org/docs/develop/standards/coding-standards#array.

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -231,9 +228,7 @@ public function render($hook, array $variables) {
         // If the theme implementation was invoked with a direct theme suggestion
         // like '#theme' => 'node__article', add it to the suggestions array before
         // invoking suggestion alter hooks.
    -    if (isset($info['base hook'])) {
    -      $suggestions[] = $hook;
    -    }
    +    $suggestions = array_merge($suggestions, array_reverse($theme_hooks));
    

    This inline comment looks like it could use an update since the code is now doing something more generic.

  3. +++ b/core/themes/engines/twig/twig.engine
    @@ -79,31 +79,18 @@ function twig_render_template($template_file, array $variables) {
    -      // Only add the original theme hook if it wasn't a directly called
    -      // suggestion.
    -      if (strpos($variables['theme_hook_original'], '__') === FALSE) {
    +      $pos = strpos($variables['theme_hook_original'], '__');
    +
    +      if ($pos !== FALSE) {
    +        $suggestions[] = substr($variables['theme_hook_original'], 0, $pos);
    +      }
    

    I think this part could still use a comment, mentioned in #100.6. I don't think it's obvious what's happening here.

mikeker’s picture

@Cottser, thank you for the review!

I've replaced all long-syntax array declarations with short-syntax array declarations, some of which were handled in other bug fixes and I think I may found another couple along the way. Anyhow,

$ git diff 8.4.x | grep "array("
-    if (is_array($hook)) {
$ 

So I think that should cover it...

Updated the inline comments to (hopefully) better reflect what's happening in the code.

mikeker’s picture

Status: Needs work » Needs review

Oops.

bapi_22’s picture

These are the list of theme hook suggestions for views module which has not included in suggestions. So it will not display while twig debugging.

views-view--foobar--page.html.twig
views-view--page.html.twig
views-view--foobar.html.twig
views-view.html.twig

views-view-unformatted--foobar--page.html.twig
views-view-unformatted--page.html.twig
views-view-unformatted--foobar.html.twig
views-view-unformatted.html.twig

views-view-fields--foobar--page.html.twig
views-view-fields--page.html.twig
views-view-fields--foobar.html.twig
views-view-fields.html.twig

bapi_22’s picture

Hi,

This patch will create possible template suggestions for views template.

In same way we can create suggestion for views display and views field templates.

markhalliwell’s picture

@bapi_22, please don't hijack an existing issue. The patch in #124 is the correct one for this issue.

bapi_22’s picture

Yes markcarver,

Its great job. Its a complete suggestion for views as well as its child elements.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Antti J. Salminen’s picture

Thanks to everyone who's been working on this. Great to see it moving forward!

+++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
@@ -169,18 +166,13 @@ public function render($hook, array $variables) {
-      // Do not create a watchdog warning for arrays of hooks because their
-      // every element is allowed to be unimplemented.
-      // This is utilized with for example form arrays to provide a theme hook
-      // that could be used if theming a specific form.
-      if (!is_array($hook)) {
-        \Drupal::logger('theme')->warning('Theme hook %hook not found.', array('%hook' => $candidate));
+      // Only log missing theme hook implementations for single (string) hooks.
+      if (is_string($hook)) {
+        \Drupal::logger('theme')->warning('Theme hook %hook not found.', array('%hook' => $hook));

I don't understand why this got changed and I'd still like to see something closer to the older comment that actually tried to explain why this exception exists. I believe comments should primarily be used for answering why the code does what it does and only repeat what it does when that is non-obvious to a less-experienced reader (for example summarising larger block of code or some unfamiliar idiom). See also: http://wiki.c2.com/?CodeComments

If you don't think the explanation is needed here just removing the comment altogether would be better because the code is already very simple and clear. In general I think comments shouldn't be used too sparingly but the current version just doesn't add much.

frob’s picture

We could almost just concatenate the two comments. The wording is still a little awkward.

Do not create a watchdog warning for arrays of hooks because their every element is allowed to be unimplemented. This is utilized with for example form arrays to provide a theme hook that could be used if theming a specific form. Only log missing theme hook implementations for single (string) hooks.

What if we changed it to:

Do not create a watchdog warning for arrays of hooks because every element is allowed to be unimplemented. For example, this is utilized to allow form arrays to provide a theme hook that could be used to theme a specific form. Therefore, we only log missing theme hook implementations for single (string) hooks.

How does that sound?

star-szr’s picture

Status: Needs review » Needs work

I like the direction you're both going, here's a slightly reworded suggestion based on #132:

Do not create a watchdog warning for arrays of theme hooks because every hook in the array is allowed to be unimplemented. For example, form arrays can provide an array of suggested theme hooks for theming a specific form. Therefore, we only log missing theme hook implementations for single (string) hooks.

mikeker’s picture

Version: 8.5.x-dev » 8.4.x-dev
Status: Needs work » Needs review
FileSize
919 bytes
21.56 KB

I went back and forth between which sounds better:

...because every hook in the array is allowed to be unimplemented

or

...because not every hook in the array is required to be implemented

I went with @Cottser's suggestion because he has core commit permissions and I don't. :) But I'm happy to switch it if folks feel the second is more clear than the first.

Also, pushing this back to 8.4.x in hopes of getting it in the next release. As per the allowed changes, I feel this falls under non-disruptive bugs where the disruption (very, very low) outweighs the benefit (we can see Views' theme suggestions!).

star-szr’s picture

@mikeker thanks :) I thought that wording was awkward as well but just left it as is (it's from HEAD).

What about something along the lines of:

Do not log a warning for arrays of theme hooks with no implemented hooks. It's valid to pass an array of theme hooks where none of the hooks are implemented.

Could probably be merged into one sentence but not sure how to do that smoothly at the moment.

Zooming out for a second, maybe it's a bit weird that we support this, in the form example it seems like you'd want to at least have a fallback of form in case no specific suggestions are implemented but that also seems out of scope for this issue! :)

+1 to hopefully getting this into 8.4.x.

mikeker’s picture

Yes, I like the version in #135 much better.

Out with the old, in with the new! :)

mikeker’s picture

Zooming out for a second, maybe it's a bit weird that we support this, in the form example it seems like you'd want to at least have a fallback of form in case no specific suggestions are implemented but that also seems out of scope for this issue! :)

Maybe handled in #2752443: Incorrect order and duplicate theme hook suggestions? But, agreed, definitely outside the scope of this issue...

star-szr’s picture

Status: Needs review » Needs work

Thanks @mikeker :)

Seems like we're just down to nitpicks at this point :) I've been poking at this patch as much as I can recently and as much as I try I can't find anything functionally wrong with it.

I will say, one thing that still feels a bit weird is the logic for the THEME HOOK: part in Twig debug. However, I also think that is OK to be out of scope here, what we have here is such a massive improvement and I don't want to delay things any further. I created a new issue to discuss what to do with that: #2901599: Decide what to display for 'THEME HOOK' in Twig debug for special cases such as arrays of theme hooks

  1. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -140,48 +140,46 @@ public function render($hook, array $variables) {
    +      // There is no theme implementation for the hook passed. Return FALSE so
    +      // the calling function can differentiate between a hook that exists and
    +      // renders an empty string, and a hook that is not implemented.
    +      return FALSE;
    

    Minor but going through this again and this chunk of docs only refers to hook singular where it could be either singular or plural at this point. Some suggested wording:

    There is no theme implementation for the hook(s) passed.
    Return FALSE so the calling function can differentiate between a hook that exists and renders an empty string,
    and hooks that are not implemented.

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -228,12 +228,9 @@ public function render($hook, array $variables) {
    +    // Prioritize suggestions from hook_theme_suggestion_HOOK implementations
    

    This should be hook_theme_suggestions_HOOK() (suggestions plural, add parens).

mikeker’s picture

@Cottser, thanks, as always, for the review!

Nits have been picked.

I will say, one thing that still feels a bit weird is the logic for the THEME HOOK: part in Twig debug

I completely agree. Thank you for opening the followup for that.

joelpittet’s picture

Status: Needs review » Needs work

I'm a bit concerned about this change:

-      'theme_hook_original' => $original_hook,
+      'theme_hook_original' => $candidate,

That changes the meaning of that variable, doesn't it? It was the incoming $hook variable before and now it's the last found $candidate.

In most cases it would be the first one in the array, but the way it's written if it doesn't find it, it will keep moving through candidates.

star-szr’s picture

Thanks for taking another look @joelpittet :) The logic looks a little bit different but to my eyes ends up the same.

Before:

    if (is_array($hook)) {
      foreach ($hook as $candidate) {
        if ($theme_registry->has($candidate)) {
          break;
        }
      }
      $hook = $candidate;
    }
    // Save the original theme hook, so it can be supplied to theme variable
    // preprocess callbacks.
    $original_hook = $hook;

After:

    foreach ($theme_hooks as $candidate) {
      if ($theme_registry->has($candidate)) {
        $hook_found = $candidate;
        break;
      }
    }

In both cases, the value that ends up as theme_hook_original (original_hook/candidate) is either:

  1. The first implemented hook found. Because of the break in both cases.
  2. Before, the code will break out of the loop and hit the $hook = $candidate; line outside of the loop. After, it's set before the break.

  3. If no implemented hooks are found, the last hook in the array (or the only hook). Before, this is the $hook = $candidate; line (or the original $hook if it's a string passed in). After, it's the fact that we're using the loop variable of $candidate to set theme_hook_original. In both instances, the variable used to populate theme_hook_original will be the last (or only) theme hook passed in.
star-szr’s picture

Status: Needs work » Needs review
Anonymous’s picture

#139 patch is very useful! Now information about the suggestions displayed much better. It really saves time. Many thanks!

joelpittet’s picture

Status: Needs review » Reviewed & tested by the community

Oh weird, theme_hook_original really isn't that in some edge cases(it's mostly that, and sometimes last found hook)... thanks for double checking that @Cottser, we are good here then:) No harm, no foul.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 139: 2118743-139-twig-debug-info.patch, failed testing. View results

mikeker’s picture

Status: Needs work » Needs review

Looks like an unrelated test failure, requeuing.

mikeker’s picture

Status: Needs review » Reviewed & tested by the community

Test is back to green. Setting the status to where it was.

xjm’s picture

Adding to a queue of issues for the frontend framework managers. Thanks!

dkre’s picture

This is a massive quality of life and time saver for theming - Thank you!

This applies cleanly on 8.3.x

mikeker’s picture

Issue summary: View changes

Minor IS updates.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 139: 2118743-139-twig-debug-info.patch, failed testing. View results

mikeker’s picture

Status: Needs work » Needs review

Again, the test failures seem unrelated. Re-queuing.

mikeker’s picture

Status: Needs review » Reviewed & tested by the community

Testbot came back green so I'm resetting to the status in #144.

Anonymous’s picture

Looks like @Cottser (Framework Manager - Frontend maintainer) already implicitly approved the last patch in #141. And all his points are addressed.

Also we have RTBC (#144) from @joelpittet (Theme API maintainer).

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 139: 2118743-139-twig-debug-info.patch, failed testing. View results

frob’s picture

Status: Needs work » Reviewed & tested by the community

Looks like the test failing is systemic to an issue with the testbot and not to do with with anything related to the patch.

Anonymous’s picture

#139 contains 3 fail cases:

  1. https://www.drupal.org/pift-ci-job/758910 - random fail was fixed in #2857843: Random fail in Drupal\KernelTests\Core\Entity\ContentEntityChangedTest::testChanged
  2. https://www.drupal.org/pift-ci-job/772925 - not random, was fixed via revert in #2711353-89: Migrate never unsets existing data for content entitites
  3. https://www.drupal.org/pift-ci-job/782513 - random fail described in #2906317: Random fail due to problems with database.

Issue with map of random fails: #2829040: [meta] Known intermittent, random, and environment-specific test failures

If we always will qualify random faults (mentioning them in the related issues, or creating new issues), then we will deal with them much more quickly.

I already did all this, just wanted to remind about good practices for random fails.

frob’s picture

I was unaware of that protocol. thank you.

shaal’s picture

I tested https://www.drupal.org/node/2118743#comment-12218334 patch with 8.4.0, and it works great!

Anonymous’s picture

#158: no problem, and thanks for understanding!

#159: good point! I also tested the last patch (#139) on 8.4.2 and it works like a charm!

xjm’s picture

Thanks everyone for your ongoing work on this issue!

Since this issue has been at RTBC awhile, @lauriii, @catch, @effulgentsia, and I discussed this issue today to figure out how to move it forward. There are a couple of reasons we have hesitated on it:

  • The patch changes some low-level code that affects how basically all templates are loaded, and so it is risky and could have a lot of side effects. While the patch itself has good test coverage, not everything that might be affected by it does (or we don't know for sure that it does).
  • Even though the patch isn't actually all that large, we need to consider the implications of each bit pretty carefully when reviewing it, so the review can take quite a bit of time.

Given these two things, we discussed whether it might be better to commit this issue very early in the development cycle for a minor release (for example, right away when we open 8.6.x in January, rather than now just two months before the alpha). Sometimes for things like this we postpone the issue and schedule it for a certain date, but we want to be ready to commit it other than that before we do so (in case there's other points that come up during review that need to be addressed).

Other than that, the main thing that's blocking this is just committers having enough time to give it the careful review it needs. In the meanwhile, though, there are a couple things that contributors can do to help give us confidence in the patch.

  1. Are you using this patch on a production site? If so how is it working, and what side effects if any have you noticed?
  2. Provide thorough manual testing with base themes that do theme system customizations (lauriii suggested Bootstrap as a good example).
  3. Code review from core extension system contributors as well as contributed theme maintainers might also help.

I'm going to keep the issue at RTBC for now since there aren't any specific blockers currently. @lauriii might have additional feedback on the issue as well. Thanks everyone.

hanoii’s picture

I can add a bit to 1. but isn't this patch something that affects only twig debug, or does it affect anything else?

In any case, I am running several productions sites, both 8.4.x and 8.3.x with #119 without any issue so far, and this patch has proven very useful for local envs.

pingers’s picture

1. Are you using this patch on a production site? If so how is it working, and what side effects if any have you noticed?
- We've been tracking the patch in production on about 20 sites (same install profile) since May 2017, without any noticeable side-effects.

The install profile uses paragraphs module with about 15 unique paragraph types on a custom, style guide driven theme.

markhalliwell’s picture

Priority: Major » Normal
Status: Reviewed & tested by the community » Needs work
Related issues: +#2752443: Incorrect order and duplicate theme hook suggestions

This issue is of very little importance.

It only really focuses on the debug output concerning like 0.01% of code that actually implements the rarely used "theme hook array" (a.k.a. views).

This is a legacy "feature" that really should be converted to use the, now, proper hook: hook_theme_suggestions_HOOK().

If anything, I would say that the real "major bug" here lies within Views and its need to use the proper hooks now. Thus, I'm downgrading this issue to "Normal".

The related issue I'm attaching now is a real major bug in theme hook suggestions that affect which suggestion is actually used and should probably be fixed before this one. It may even semi-fix this one.

Provide thorough manual testing with base themes that do theme system customizations (lauriii suggested Bootstrap as a good example).

FTR, Bootstrap does little to nothing with the debug output of theme hook suggestions. That being said, given that this patch is altering the underlying suggestions array, I wouldn't be surprised if this patch actually improves the base theme in some way, regarding Views anyway.

Normal string theme hooks still seem to function the same, from what I can tell by reviewing the patch.

---

Initial quick review of latest patch:

  1. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -140,48 +140,46 @@ public function render($hook, array $variables) {
    +    $theme_hooks = (array) $hook;
    

    I'm really not a fan of typecasting this. It just makes this more unnecessarily complicated.

    As I mentioned above, this "theme hook array" feature is rarely used. If anything, I think this feature should be removed entirely in the future.

    For BC reasons, we can keep this "array theme hook" detection (is_array) and just log a warning that this will be removed in the future and to use the proper hooks for theme hook suggestions.

    Changing the overall structure to "just deal with arrays" is what has gotten the theme system in the "Render arrays of doom" mess we're in now.

    Perpetuating this mentality in code is wrong.

    Especially in the theme system.

  2. +++ b/core/lib/Drupal/Core/Theme/ThemeManager.php
    @@ -140,48 +140,46 @@ public function render($hook, array $variables) {
    +        $hook_found = $candidate;
    
    @@ -210,9 +208,11 @@ public function render($hook, array $variables) {
    -      'theme_hook_original' => $original_hook,
    +      'theme_hook_original' => $candidate,
    

    I don't like this unnecessary change.

    It may seem trivial, but given how complex this method/topic is, keeping semantic variable names is important for future work.

markhalliwell’s picture

A little history:

In D6, #141730: Allow theming system to use wildcards introduced this "theme hook array" feature. It was, essentially, the first iteration of "theme hook suggestions" in core.

In D7, #653622: Make the '__' pattern for theme suggestions easier to use and #678714: Unify use of theme hook / template suggestions, fix clobbering problems, and improve suggestion discovery performance moved to a more "internal" way of providing theme hook suggestions via $variables['theme_hook_suggestions'] in the preprocess phase.

In D8, dedicated hooks were introduced for theme hook suggestions. These hooks removed the internal preprocess suggestions, but never removed the original "theme hook array" way of providing suggestions.

It's wildly redundant, unnecessary, should be deprecated and then ultimately removed.

dkre’s picture

@markcarver I agree with the logic but this is a further dialution of Drupal's usability for non-developers.

Basically theming shouldn't be so layered and complex. Out of the box a CMS should be able to create logic, clean markup which can be altered without too much fuss. By removing the debugging output it requires a further step to markup alterations.

The hook system isn't overally intuitive due to Drupal's endless nesting of elements which isn't always easy to discover or interpret. Worse it requires an understanding of the underlying Drupalisms. Often I find myself poking away to see what effects the markup at the right point in the render chain.

My biggest concern with only using suggestion hooks is that it seems like an impossibility to document it effectively to allow new Drupal users to make frontend alterations as you would expect in a modern CMS.

markhalliwell’s picture

this is a further dialution of Drupal's usability for non-developers.

No, it's not. It's putting the blame where it belongs: with Views. If Views used D8's new theme suggestion hooks, then non-developers would be able to see the proper theme hook suggestions in the debug output. I think you are conflating what I have said above with an assumption that this is somehow shifting the focus from "fixing a problem" to "telling non-developers they have to code". That isn't true. What I am proposing would actually help everyone, even non-developers.

Basically theming shouldn't be so layered and complex. Out of the box a CMS should be able to create logic, clean markup which can be altered without too much fuss.

It's a nice sentiment and I generally agree. However, Drupal has over a decade of its own history. How a page is ultimately "themed" in Drupal has evolved over time (rather slowly I might add). There are years of technical debt and antiquated techniques still being used to this day. As I outlined above in #165, this issue is a direct symptom of using said outdated theming practice (from D6).

By removing the debugging output it requires a further step to markup alterations.

No one is "removing" the debugging output. What I have suggested will actually make the debugging output work properly, because it wouldn't have to deal with "arrays of theme hooks".

The hook system isn't overally intuitive due to Drupal's endless nesting of elements which isn't always easy to discover or interpret. Worse it requires an understanding of the underlying Drupalisms.

As someone who has spent their entire career in understanding the fundamentals of Drupal's theming layer, I couldn't agree more. However, you are again assuming that I am pushing the responsibility of fixing this onto non-developers. That is not the case. Views is in core. Developed by and maintained by core developers. They are the ones that should use these hooks, not non-developers.

My biggest concern with only using suggestion hooks is that it seems like an impossibility to document it effectively to allow new Drupal users to make frontend alterations as you would expect in a modern CMS.

The documentation would be the (proper) debug output. I still think you are confusing what I am saying here. I will try to break this down and explain in greater detail:

ViewExecutable::buildThemeFunctions is responsible for generating the necessary theme hooks.

As you can see, this is creating an array of theme hooks (not theme hook suggestions) that will be passed directly to #theme (typically, this is just a single string).

This technique is very old, outdated and harkens back to the days of D6. merlinofchaos, who also developed Views, created this "array of theme hooks" technique (#141730: Allow theming system to use wildcards) that was added to core (likely a direct correlation to Views). In the 11+ years that this "array of theme hooks" feature has been in core, almost nothing has really used it except Views.

Even though Views is now in core, this specific aspect of Views (providing an "array of theme hooks") really hasn't changed all that much. It is severe technical debt that was simply inherited.

Early on in D7's development (#653622: Make the '__' pattern for theme suggestions easier to use), it was realized that passing array() each time and duplicating the same prefix in hooks was entirely unnecessary and simply added more unnecessary technical debt:

But, if we're gonna use this in core, and if in core, we're settling on the '__' convention, let's make it easier to use. Instead of code having to call theme(array('links__comment', 'links'), ...), how about letting theme('links__comment', ...) work.

This is when the "array of theme hooks" technique should have been deprecated and Views' code adjusted to using proper preprocess alterations to the $variables['theme_hook_suggestions']. However, given that Views was still contrib and my own personal experience with trying to fix bugs in Views was always met with hostility and a superiority complex, I can see how that never happened.

Now that, in D8, there are dedicated hooks for providing and alter actual theme hook suggestions, Views' code should be fixed (moved) to utilize them.

This simple change would just mean that instead of providing an "array of theme hooks" to #theme, it would provide a single theme hook and then these "arrays of theme hooks" would then be provided as proper suggestions later when they're actually needed.

This would make everything "just work", even for non-developers.

markhalliwell’s picture

dawehner’s picture

@markcarver Thank you for the great suggestion. Let's see whether its possible to implement that at least for views: #2923634: [PP-1] Use hook_theme_suggestions in views

markhalliwell’s picture

frob’s picture

So what is the actual problem with the patch? This is an RTBC patch that fixes an issue with DX.

Can we just revert this patch after the underlaying issue with views is fixed? I just don't understand why this was changed from RTBC to needs work. What work needs to be done?

markhalliwell’s picture

See my review in #164.

frob’s picture

I'm sorry, its been a long week already. I completely missed the later half of your comment. I read the whole rest of the thread though. Sorry.

markhalliwell’s picture

Title: Twig debug output does not display all suggestions when an array of suggestions is passed to #theme » Twig debug output does not display all suggestions when an array of theme hooks is passed to #theme

I'm sorry, its been a long week already.

I hear that, no worries :D

Can we just revert this patch after the underlaying issue with views is fixed?

Since the "array of theme hooks" feature has been in core since 6.x, this is still technically a bug and needs to be fixed. So no, I don't think it should be reverted after Views gets fixed. It should, however, be removed entirely once all deprecated code is removed in the future.

I just don't think that focusing on this particular issue is all that important right now considering that it's just a symptom due to outdated theming techniques.

The end goal of the OP (Views theme hook suggestions) can be fixed using the proper hooks first, without fiddling around with the internals of an already extremely complicated theme "system".

In my mind, the priority of importance is as follows:
#2923634: [PP-1] Use hook_theme_suggestions in views
#2752443: Incorrect order and duplicate theme hook suggestions
#2923506: Deprecate and discourage use of the "array of theme hooks" feature
... then this issue.

How the above issues are tackled will likely affect how this issue implements it's "fix" for displaying "suggestions" for an "array of theme hooks". Given that, I would almost say this issue should probably be postponed until then.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

gambry’s picture

Title: Twig debug output does not display all suggestions when an array of theme hooks is passed to #theme » [PP-3] Twig debug output does not display all suggestions when an array of theme hooks is passed to #theme
Issue summary: View changes
Status: Needs work » Postponed

I agree with #174. The work done here is as huge as important, but this fix may create more problems than the ones is trying to fix if we don't do #2923634: [PP-1] Use hook_theme_suggestions in views, #2752443: Incorrect order and duplicate theme hook suggestions and #2923506: Deprecate and discourage use of the "array of theme hooks" feature before.

So let's postpone this in favour of those three.

I'm also updating the IS to reflect these thoughts.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

shaal’s picture

Ignore these patch files (they include by mistake a /web directory)
Use #179, works like a charm

shaal’s picture

Until a better solution for Views suggestions is found, this patch is awesome!
I re-applied manually @mikeker patch #139
It is now working with Drupal 8.6.1

Ben Buske’s picture

reroll of #179 for 8.8.x

shaal’s picture

I rerolled #179 for 8.8.x, but kept code changes that were introduced in 8.8.x and seemed to be removed in #180
(you can see these details in the interdiff)

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

shaal’s picture

shaal’s picture

Issue tags: +Bug Smash Initiative

Hopefully #bugsmash initiative can help getting this resolved.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

JohnAlbin’s picture

Title: [PP-3] Twig debug output does not display all suggestions when an array of theme hooks is passed to #theme » Twig debug output does not display all suggestions when an array of theme hooks is passed to #theme
Version: 8.9.x-dev » 9.2.x-dev
Priority: Normal » Major
Issue summary: View changes
Status: Postponed » Needs work
Issue tags: -Triaged core major, -Baltimore2017, -DrupalCampMontréal2017, -Needs frontend framework manager review

It's a major bug when the twig debugging comments that are meant to show all of Drupal's theme suggestions don't display all of Drupal's theme suggestions. In this case, the mechanism by which the feature fails to work (because of an array is used for #theme) is important for how to fix the bug, but not for determining its severity, IMO. These twig debugging comments are an important feature in discoverability of Twig templates.

And postponing this bug for a more important refactoring was a mistake. This issue has remained untouched and unfixed for an additional 3 years because of that. Both the refactoring and this bug fix could have been done in parallel.

Having read all the previous comments, I think xjm's comment is most pertinent for finding the most expedient way to fix this bug:

The patch changes some low-level code that affects how basically all templates are loaded, and so it is risky and could have a lot of side effects. While the patch itself has good test coverage, not everything that might be affected by it does (or we don't know for sure that it does).

She suggests a way to commit the patch in #139 to a Drupal branch before any releases are tagged. Currently, that means applying it to 9.2.x.

Alternatively, we could fix the bug by only altering the Twig debug comments and not the underlying #theme-handling code. Any code that looks like it needs refactoring (there's lots!) should be done in a separate issue.

JohnAlbin’s picture

Status: Needs work » Needs review

Alternatively, we could fix the bug by only altering the Twig debug comments and not the underlying #theme-handling code.

I've created a merge request that uses this new approach. It adds two new read-only variables when rendering a template:

  • template_suggestions: containing the full list of possible theme hook suggestions
  • template_suggestion: containing the actual theme hook of the matched template

Because it is only adding 2 new variables, it only adds additional lines to core/lib/Drupal/Core/Theme/ThemeManager.php and does not modify any of the existing lines of code. It also removes all the template suggestion-generating code in twig_render_template() since it was buggy and all that function needs now is to just append the .html.twig suffix to each entry in the new template_suggestions variable.

This should be a completely safe patch to backport. (Though we'll need to change the PHP 7.3-specific array_key_last() to array_pop() in Drupal versions that support PHP 7.2.)

The MR still needs tests. I can possibly re-use some of the test from the previous patches.

JohnAlbin’s picture

The fact that none of Drupal's existing tests break with this change is a good sign!

I'll see about adding in the tests from earlier patches into the MR. Also, this MR probably fixes some of #2752443: Incorrect order and duplicate theme hook suggestions too, so I could also use some of the proposed tests in that issue's patches.

joseph.olstad’s picture

array_key_last is fine for 9.2.x

Great work on the merge request, wow, huge improvement!

I noticed the use of array_key_last , it is (PHP 7 >= 7.3.0) only, so I switched to php 7.3.x for my test run and applied your patch on 8.9.9 , works as anticipated!

Huge improvement.

Before patch:

no views-view-field suggestions,

after patch, all the twig suggestions that we expect to see are there.

I haven't done extensive testing on this patch but it did not cause any issues in my test environment. Thanks so much for this!

Attaching a new version of the patch with changes based on the failure suggestions.
see interdiff for changes.

joseph.olstad’s picture

**EDIT**
Still testing and reviewing, but so far it looks ok.
**EDIT**

Status: Needs review » Needs work

The last submitted patch, 190: 2118743-190.patch, failed testing. View results

joseph.olstad’s picture

initial testing is promising showing expected theming suggestions for views fields , views lists, unordered lists, and other twig theming components, however lots of warnings and notices from the twig engine, excessively (at least in my environment). 8.9.9 with php 7.3.x , bootstrap theme.

still some refinement to do and one test failure.

JohnAlbin’s picture

Status: Needs work » Needs review
Issue tags: +needs backport to 8.9.x

@joseph.olstad I haven't gotten to try this yet, but multiple people can push to the issue fork. You can either add to the existing MR's branch or create a new branch. https://www.drupal.org/drupalorg/docs/gitlab-integration/issue-forks-mer...

however lots of warnings and notices from the twig engine

I've not seen any warnings when testing on Drupal 9.2.x. What specific warnings are you seeing?

Since my last comment, I've added the tests from patch #139 and have just now fixed the broken test. The tests aren't a perfect match though because they were testing the approach in #139 and my approach is completely different. I need to add some tests that actually cover all the possible paths through the new code. So, definitely, the MR needs work.

But the MR needs review like the one Joseph started, so I'm putting this back at "needs review".

JohnAlbin’s picture

While working on more specific tests for this MR, I discovered a bug in the code. (Yay, tests!) My code was inserting all suggestions returned from hook_theme_suggestions_HOOK and hook_theme_suggestions_HOOK_alter in place of the one matched hook in the #theme array, but while that follows the flow of the code in Drupal, it misrepresents how Drupal behaves when new templates are created.

Here's the example:

Let's assume these templates exist: base--from-hook-alter.html.twig, base--suggestion1.html.twig, and, of course, base.html.twig.

'#theme' => [
  'base__suggestion2',
  'base__suggestion1',
  'base',
],

Since base--suggestion1.html.twig is the first match, the hook_theme_suggestions_HOOK hook is called and will result in this array:

$suggestions = [
  'base__from_hook2',
  'base__from_hook1',
  'base',
];

Drupal will note that the matched hook was base__suggestion1 and will add it as the most specific spot in the $suggestions list, giving us:

$suggestions = [
  'base__suggestion1',
  'base__from_hook2',
  'base__from_hook1',
  'base',
];

Then hook_theme_suggestions_HOOK_alter is called and can add stuff and move stuff around like so:

$suggestions = [
  'base__from_hook_alter',
  // An alter hook was devious and moved base__from_hook2 to a more specific spot.
  'base__from_hook2',
  'base__suggestion1',
  'base__from_hook1',
  'base',
];

My previous code was taking this entire $suggestions list and inserting into the theme #theme list, like so:

'#theme' => [
  'base__suggestion2',
  // The whole $suggestion list replaces the previous 'base__suggestion1' entry.
  'base__from_hook_alter',
  'base__from_hook2',
  'base__suggestion1',
  'base__from_hook1',
  'base',
  'base',
],

Since base--from-hook-alter.html.twig exists, themers would see the above list and think that a base--suggestion2.html.twig template would override it, but THEY WOULD BE WRONG. Why? Because if base--suggestion2.html.twig exists, then the entire $suggestions list is inserted into the theme #theme list, like so:

'#theme' => [
  // The whole $suggestion list replaces the previous 'base__suggestion2' entry.
  'base__from_hook_alter',
  'base__from_hook2',
  'base__suggestion2',
  'base__from_hook1',
  'base',
  'base__suggestion1',
  'base',
],

As you can see the themer added base--suggestion2.html.twig, but base--from-hook-alter.html.twig is still being used since it is the most specific suggestion.

That means my code is not creating a list that reflects how Drupal is behaving.

The solution is to split the $suggestions list into 2 parts, those suggestions before the original matched $hook (base__suggestion1 in the first part of the example above) and those suggestions after that $hook.

In other words, split:

$suggestions = [
  'base__from_hook_alter',
  // An alter hook was devious and moved base__from_hook2 to a more specific spot.
  'base__from_hook2',
  'base__suggestion1',
  'base__from_hook1',
  'base',
];

into:

$most_specific_suggestions = [
  'base__from_hook_alter',
  'base__from_hook2',
];
$least_specific_suggestions = [
  'base__from_hook1',
  'base',
];

Then take those 2 lists and insert the most specific suggestion before the first hook in #theme with the same base and the least specific suggestions before the last hook in #theme with the same base. e.g.

Take these 3 arrays:

'#theme' => [
  'base__suggestion2',
  'base__suggestion1',
  'base',
],
$most_specific_suggestions = [
  'base__from_hook_alter',
  'base__from_hook2',
];
$least_specific_suggestions = [
  'base__from_hook1',
  'base',
];

and combine them like this:

'#theme' => [
  'base__from_hook_alter',
  'base__from_hook2',
  'base__suggestion2',
  'base__suggestion1',
  'base__from_hook1',
  'base',
],

which is what the new MR does. Oof. Yes, there's lots more lines of code, but it still doesn't modify any existing code, it just adds lines to support the 2 new variables.

I still need to finish refactoring the tests. Right now one of them still fails, but I need some sleep. I'm pushing the WIP tests to the MR.

andypost’s picture

@JohnAlbin great research! Just not clear how to document expected behavior to make everyone understand and prevent misuse

PS: patches are hidden to point that WIP in MR now https://git.drupalcode.org/project/drupal/-/merge_requests/49#note_5162

JohnAlbin’s picture

Status: Needs review » Needs work

I found a minor bug in my code when ordering a base hook suggestion relative to those from hook_theme_suggestions_HOOK(). Again, I found this due to tests I'm writing. (yay!)

joseph.olstad’s picture

Great find @JohnAlbin, thanks again for your hard work, I'm really looking forward to this one, very important improvement IMHO.

JohnAlbin’s picture

Status: Needs work » Needs review

Okay, I've refactored and expanded the theme suggestions tests. They now mostly use the data provider interface of PHPUnit to make them easier to understand. I got rid of all the controller paths as they made the tests really hard to understand; and it's much simpler to take a render array and render it to markup directly rather than pull an entire Drupal page.

As for the actual changes to Drupal\Core\Theme\ThemeManager::render(), the MR changes no existing lines of code; it just adds 60 lines of PHP to calculate the list of templates to print out in Twig debug comments. It also adds about 60 lines of code comments. And I went ahead and fixed all the phpcs code formatting warnings in that file.

The most controversial part of the MR changes is that I was forced to call theme suggestions alter hooks a second time so that I can accurately figure out how to split the $suggestions list created by hook_theme_suggestions_XXX functions into 2 different lists. Why? Here's how I describe it in the code comment:

    // In order to properly merge these new suggestions into our previous list
    // of all possible template suggestions, we need to determine where each
    // suggestion comes from and order them like so:
    //
    // 1. More-specific suggestions from the #theme list that aren't for the
    //    $base_theme_hook.
    // 2. Suggestions for $base_theme_hook from:
    //    a. hook_theme_suggestions_alter(), hook_theme_suggestions_HOOK_alter()
    //    b. #theme list
    //    c. hook_theme_suggestions_HOOK()
    //    d. $base_theme_hook
    // 3. Less-specific suggestions from the #theme array that aren't for the
    //    $base_theme_hook.
    //
    // Since 2a and 2c come from $suggestions, we need to figure out how to
    // split that array into two parts.

The reason why I ordered the list of suggestions like above is due to this: the call to hook_theme_suggestions_HOOK() returns $suggestions and Drupal appends the matched $hook (from #theme), but only if $hook is a hook suggestion and not a simple base hook. This affectively splits the $suggestions into 2 parts, any suggestions before $hook will NEVER be used because $hook already matches an implementation and only those suggestions after it can override it.

The code implementation of how to split the $suggestions into two parts is complex because Drupal only conditionally appends the matched $hook. If the matched $hook was a simple base hook, we still need to track where it would have been in $suggestions because a themer may later to decide to implement one of the more-specific suggestions from #theme. I tried figuring out how to do that without actually inserting a separator into $suggestions (to mock how an appended $hook would work), but it's literally impossible to do:

If hook_theme_suggestions_HOOK() creates this list: A - B - C

We need to track the end of that list: A - B - C - d (I'm using "d" to represent where $hook would have been added if needed)

A hook_theme_suggestions_HOOK_alter hook might return: A - B - Z - C

But where is "d" in that list? Impossible to tell. Here's 2 possible answers:

Z is inserted into the middle of the list: A - B - Z - C - d

Z is appended and then C is moved from the middle to the end: A - B - d - Z - C

As you can see both of the above lists are identical EXCEPT where d is located. Both of those answers represent completely valid steps that an alter hook may have done and the only way to tell the difference between the two is to insert an actual item on to the end of $suggestions before the alter hooks are run.

To be clear, the best solution is to insert all the #theme suggestions on to the end of hook_theme_suggestions_HOOK()'s list before letting alter hooks modify that list. IMO, it's a bug that theme suggestions alter hooks aren't actually given all the possible suggestions that Drupal knows about. However, that's a BIG change and might break have unintended consequences for contrib modules. I'd argue it can only be done for Drupal 10. I'll search the issue queue to see if this bug report already exists and make a new issue if it does not.

Which means, the safe (but verbose way) to fix this bug now is to insert a fake separator into a fake list and re-run the alter hooks. This fake list is only used by the Twig debug comments, so it doesn't affect how the rest of Drupal\Core\Theme\ThemeManager::render() works. And it is totally safe to run alter hooks as many times as we want (on different data each time), so we won't cause any problems for contrib modules. Is it possible that some weird contrib module will mess up the data when it sees this new fake separator? I'll be honest; the answer is: Yes, never underestimate the insane things contrib modules will do. :-D However, it would be very rare and it would only mess up the fake list of suggestions used by the Twig comments and have no side effects anywhere else in Drupal's code.

Reviews, please! :-)

JohnAlbin’s picture

IMO, it's a bug that theme suggestions alter hooks aren't actually given all the possible suggestions that Drupal knows about.

I've opened a bug report for this at #3187010: Not all suggestions are passed to theme suggestions alter hooks.

While working on a MR for that issue I found another edge case where this issue's MR would fail. I've just pushed an updated test that should fail. And I'll add the fix after the testbot runs.

JohnAlbin’s picture

Issue summary: View changes
Issue tags: -Needs backport to D7

I've added comments directly to the MR to point out the controversial part of this code change (discussed in detail in #199).

This MR is 100% safe and 100% ugly. It adds ~48 lines of code to fix this bug. If we were to fix #3187010: Not all suggestions are passed to theme suggestions alter hooks first in 9.2.x, then we would only need ~2 lines of code to fix this bug.

I really, really, really want to see this bug fixed in Drupal 9. I believe #3187010: Not all suggestions are passed to theme suggestions alter hooks is the better fix, but I would love to get some people's opinions on whether we can make that change to 9.2.x or if we'd need to wait until 10.0.x.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

star-szr’s picture

@JohnAlbin I don't have much to contribute at this time but I just want to sincerely thank you for working on this issue again! If I get time I will try to contribute a review (here or on #3187010: Not all suggestions are passed to theme suggestions alter hooks).

JohnAlbin’s picture

Issue summary: View changes
Status: Needs review » Needs work

So to reiterate:

  1. We can't fix this bug by only making changes in core/themes/engines/twig/twig.engine's twig_render_template() (where Drupal currently calculates the list of suggestions) because some of the valid theme suggestions are never passed to twig_render_template() and are only known inside \Drupal\Core\Theme\ThemeManager::render().
  2. We can fix this bug in \Drupal\Core\Theme\ThemeManager::render() without altering any of the existing logic used; this would 100% guarantee that no other parts of core or contrib would be affected by the bugfix. HOWEVER, this bug fix requires adding 123 lines of code and explanatory comments, including making duplicate calls to the theme_suggestions alter hooks. And looks like this https://git.drupalcode.org/project/drupal/-/merge_requests/49/diffs?diff...
  3. We can fix this bug by combining the it with the fix for #3187010: Not all suggestions are passed to theme suggestions alter hooks.

Since no one else has reviewed the code in option #2, I'm going to, even though I wrote it.

My conclusion: the bugfix using option #2 is way too ugly and hacky to add to core. There is no cleaner way to fix the bug "without altering any of the existing logic used" in \Drupal\Core\Theme\ThemeManager::render(). Which means, if we want clean, acceptable code (and core always wants this), the bugfix will have to alter the existing lines of code and be really damn careful that we don't alter the basic logic of how we load templates.

I think option #3 is our best solution. I'll update the MR momentarily.

JohnAlbin’s picture

Issue summary: View changes
Status: Needs work » Needs review
JohnAlbin’s picture

Issue summary: View changes

I've updated the issue summary to show the rationale for rejecting the previous proposed solution.

FYI, I'm using this patch on production using the latest 9.2.8 official release (minus the changes to the tests since they don't apply cleanly.)

JohnAlbin’s picture

Issue summary: View changes

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

pivica’s picture

Just to note that we have a similar order problem in ThemeManager in #3073053: Theme library override can fail in when you have multiple parent themes with wrong order of libraries-override and alter hooks calls.

Didn't check what this patch is exactly fixing but this patch and patch from 3073053 are fixing different parts of code and order problems. Do we have some overlaps here in fix approach?

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mherchel’s picture

Cross referencing #3301373: Create twig |add_suggestion filter, which is affected by this issue.

JohnAlbin’s picture

Version: 9.5.x-dev » 10.1.x-dev
Assigned: Unassigned » JohnAlbin
Status: Needs review » Needs work

I'll try to get this rebased on 10.1.x during Drupalcon Prague this week.

JohnAlbin’s picture

Assigned: JohnAlbin » Unassigned
Status: Needs work » Needs review

Let's see what the testbot says…

joseph.olstad’s picture

@JohnAlbin
great work, thanks! Looking forward to getting this improvement, hope it makes it into 9.5.x / 9.4.x also

jwilson3’s picture

Just a quick side note here that the current state where the D9 MR !49 was left is not generating the template suggestions in the correct order.

<!-- FILE NAME SUGGESTIONS:
   x item-list.html.twig
   * item-list--responsive-preview.html.twig
-->

This is breaking contrib module responsive_preview, which depends on the custom-defined suggestion and template provided by that module for proper theming display.

greggmarshall’s picture

It would appear this patch/diff and the latest one from #2752443: Incorrect order and duplicate theme hook suggestions conflict with each other.

nod_’s picture

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

The 10.1.x MR doesn't apply anymore unfortunately

Bhanu951’s picture

Assigned: Unassigned » Bhanu951
Bhanu951’s picture

Assigned: Bhanu951 » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs reroll

Re Rolled to 10.1.x branch latest commits.

nod_’s picture

Status: Needs review » Needs work
Issue tags: -needs backport to 8.9.x

Thanks, a little lint error left :)

Removing old tag

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

fjgarlin made their first commit to this issue’s fork.

Giuseppe87 made their first commit to this issue’s fork.

JohnAlbin’s picture

Assigned: Unassigned » JohnAlbin

It looks like all the new code handling for #3343198: Improve documentation of hook_theme_suggestions_HOOK_alter() has been reverted during a rebase and force pushed to the "-d10" GitLab branch.

I'll work on properly porting this to the main (11.x) branch.

JohnAlbin’s picture

alexismmd made their first commit to this issue’s fork.

alexismmd changed the visibility of the branch 2118743-twig-debug-output-updated-11-x to hidden.

Giuseppe87’s picture

FileSize
81.59 KB

@JohnAlbin about #225: I tried to rebase the MR according the documentation, I'm sorry if I messed something up.

I needed to reroll the 10.x patch again, this time against 10.2.x, as it doesn't work anymore for that version.

In order to avoid to mess again, I'm attaching as .patch file, if it is good, should I rebase\or push on the MR request?

saidatom made their first commit to this issue’s fork.

vasike made their first commit to this issue’s fork.

vasike’s picture

Assigned: JohnAlbin » Unassigned
Status: Needs work » Needs review

Some updates on MR to make it "green"

- "Refactor" for related refactor https://www.drupal.org/project/drupal/issues/2953921 (i think also tried on #234 patch)
- Updates for the related refactor "regression" https://www.drupal.org/project/drupal/issues/3409982
- Some updates for "invalid suggestions"
- Updates (forced sometimes) for tests to pass

In conclusion ...the MR got dirty (in its "moments") ... commits and merges
And, i think, it needs more than review ... maybe a "resume" ... and make it happen!!!

For now "Needs review" ... but it's "Needs work" (imho) ,,, still

joseph.olstad’s picture

Status: Needs review » Reviewed & tested by the community

This is a 10 year old issue that will improve DX / TX by a large margin. I'm favoring a community RTBC on this as we'll need theming system manager review on this and from there lets try to get this to the finish line and into the end zone ( a release ) while we have some momentum here.

Bhanu951 changed the visibility of the branch 2118743-twig-debug-output-d10 to hidden.

Bhanu951 changed the visibility of the branch 11.x to hidden.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Needs to merge 11.x and fix conflicts due to #3420709: Make it more obvious that a Twig template is overridden

sakthi_dev made their first commit to this issue’s fork.

vasike’s picture

Status: Needs work » Needs review

MR green again
Most of errors were from https://www.drupal.org/project/drupal/issues/3420709 update .. mentioned in #241.
So updated the MR - put back things and fix tests

There also others changes missed in latest merges and rebases. I hope I covered them all.

Let's review again

joseph.olstad’s picture

Status: Needs review » Reviewed & tested by the community
  • Has new and adjusted test coverage
  • Passes all tests
  • Conflicts are resolved.
  • Code Quality hasn't changed.
  • 11 years and counting, it's time
needs-review-queue-bot’s picture

Status: Reviewed & tested by the community » Needs work
FileSize
90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

vasike’s picture

Status: Needs work » Reviewed & tested by the community

MR updated - solved conflicts
so RTBC ... once more

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I think we need a separate CR detailing the new variables that are going to be available ie.

+    // Add two read-only variables that help the template engine understand
+    // how the template was chosen from among all suggestions.
+    $variables['template_suggestions'] = $template_suggestions;
+    $variables['template_suggestion'] = $hook;

And specifically how they related to any existing variables, ie. theme_hook_original.

Also this is adding an info variable everywhere - this feels very generic and likely to be used elsewhere - is this necessary?

evilehk changed the visibility of the branch 2118743-twig-debug-output to active.

vasike changed the visibility of the branch 2118743-twig-debug-output to hidden.