Incorrect order and duplicate theme hook suggestions

Created on 20 June 2016, over 8 years ago
Updated 23 July 2024, 2 months ago

Just by turning on twig debug and looking at theme suggestions, you can see for the main menu (and any corresponding menu like footer) that there is a duplicate theme suggestion and at the most specific level which overrides any and all customizations in hook_theme_suggestions_alter().

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'menu__main' -->
<!-- FILE NAME SUGGESTIONS:
   x menu--main.html.twig
   * menu--main--customization.html.twig
   x menu--main.html.twig
   * menu.html.twig
-->

Should be:

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'menu__main' -->
<!-- FILE NAME SUGGESTIONS:
   x menu--main--customization.html.twig
   * menu--main.html.twig
   * menu.html.twig
-->
🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component
Theme 

Last updated about 2 hours ago

Created by

🇨🇦Canada sylus

Live updates comments and jobs are added and updated live.
  • Needs backport to D7

    After being applied to the 8.x branch, it should be considered for backport to the 7.x branch. Note: This tag should generally remain even after the backport has been written, approved, and committed.

  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

  • Triaged core major

    There is consensus among core maintainers that this is a major issue. Only core committers should add this tag.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

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

  • 🇺🇦Ukraine stomusic Ukraine

    #77 wasn't getting applied to 10.1.0, #83 also. I've make re-roll

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Custom Commands Failed
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    Custom Commands Failed
  • #86 doesn't work well for me, admin menu bar suggestion comment:

    INVALID FILE NAME SUGGESTIONS:
       See https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!theme.api.php/function/hook_theme_suggestions_alter
       menu__admin
       menu
    
  • Status changed to Needs review 9 months ago
  • 🇺🇸United States jacobbell84

    I also experienced the same error from this patch. I think the patch has a couple different issues. First, it looks like a lot of the derived suggestion logic was pulled from the twig.engine debug code, but the problem with that is that the debug output is presented in reverse order.

        $derived_suggestion = $original_hook;
        $derived_suggestions[] = $derived_suggestion;
        while ($pos = strrpos($derived_suggestion, '__')) {
          $derived_suggestion = substr($derived_suggestion, 0, $pos);
          $derived_suggestions[] = $derived_suggestion;
        }
    

    This would generate hooks in the order of

    base_hook__specific__really_specific
    base_hook__specific
    base_hook

    When the later code merged this array with the suggestions array coming from the theme system (which is in the opposite order) it would create odd sorting under some conditions.

        $derived_suggestions_excluding_base_hook = array_slice($derived_suggestions, 0, -1);
        if (isset($info['base hook']) && !in_array($hook, $derived_suggestions_excluding_base_hook)) {
           $suggestions[] = $hook;
         }
        $suggestions = array_merge($derived_suggestions_excluding_base_hook, $suggestions);
    

    Second, the patch had this check:

        $derived_base_hook = array_slice($derived_suggestions, -1);
        if (!in_array($derived_base_hook, $suggestions)) {
          $suggestions = array_merge($derived_base_hook, $suggestions);
        }
    

    The above code would always fire since array_slice returns an array not a scaler value, which could sometimes cause duplicates.

    Third, part of the updates removed some variable initialization in twig.engine

    -      
    -       // Get the value of the base hook (last derived suggestion) and append it
    -      // to the end of all theme suggestions.
    -      $base_hook = array_pop($derived_suggestions);
    

    Later in the twig.engine file, the base_hook variable is used to determine whether a suggestion is valid or not

          $base_hook = $base_hook ?? $variables['theme_hook_original'];
          foreach ($suggestions as $key => &$suggestion) {
            // Valid suggestions are $base_hook, $base_hook__*, and contain no hyphens.
            if (($suggestion !== $base_hook && !str_starts_with($suggestion, $base_hook . '__')) || str_contains($suggestion, '-')) {
              $invalid_suggestions[] = $suggestion;
              unset($suggestions[$key]);
              continue;
            }
            $template = strtr($suggestion, '_', '-') . $extension;
            $prefix = ($template == $current_template) ? 'x' : '*';
            $suggestion = $prefix . ' ' . $template;
          }
    

    That's the reason folks started getting the "INVALID FILE NAME SUGGESTIONS:" error after applying the patch. I made a new patch that addresses those 3 issues.

  • last update 9 months ago
    Custom Commands Failed
  • Status changed to Needs work 9 months ago
  • 🇺🇸United States smustgrave

    Seems to have failures and is missing test coverage. Moving to NW for that.

  • 🇺🇸United States jacobbell84

    Attempting to fix the failures. I assume we'll want to wait until it's confirmed this is the approach people want before we write test cases though.

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7 updated deps
    last update 9 months ago
    Custom Commands Failed
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    31:48
    59:39
    Running
  • 🇺🇸United States jacobbell84

    Fixing failing unit test.

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 9 months ago
    29,722 pass
  • Status changed to Needs review 9 months ago
  • Status changed to Needs work 9 months ago
  • 🇨🇦Canada joseph.olstad

    Actually, still needs tests.

  • 🇺🇸United States jacobbell84

    Yup, I just wanted to fix the issues first. I'll try to get a unit test going, but I have very little experience with it so it might take a bit.

  • 🇺🇸United States nicxvan

    This should probably move to an MR, the core team is using MRs for development now and the test suite is significantly faster on gitlab if you're writing tests.

  • Merge request !6041Resolve #2752443 "Incorrect order 11.x" → (Open) created by nicxvan
  • 🇺🇸United States nicxvan

    I've converted the patch in 91 as closely as I can to 11.x, there was a refactor in https://www.drupal.org/project/drupal/issues/2953921 📌 Refactor out theme hook suggestion building from ThemeManager::render() into a separate function. Fixed that may have affected how this works. I have not added any additional tests, but I will review the MR now to see if it is working.

    Hiding patches.

  • 🇺🇸United States nicxvan
  • 🇺🇸United States nicxvan

    Can someone confirm this is still an issue on 11.x

    I was unable to reproduce this, if you can update the steps to reproduce I'm happy to continue testing.

  • 🇨🇦Canada joseph.olstad

    @nicxvan, the WxT distribution has been using patch #1 for several years.

    With that said, we're using the bootstrap 3x theme which may not behave exactly as the core themes. With that said, it would be good to try the latest version of this patch and give it some serious looks.

    Unfortunately I don't have any spare cycles at this moment.

  • 🇺🇸United States nicxvan

    There was some refactoring in the same area so I think that might have resolved this issue, but I'd like another confirmation.

  • 🇨🇭Switzerland ayalon

    Thanks for the updated patch. Here is an updated patch file for use with Drupal 10.2 based on the merge request usable with composer.json

  • last update 8 months ago
    Custom Commands Failed
  • 🇨🇦Canada joseph.olstad

    phplint saw an undefined variable, replaced with what looked to be obviously the correct variable.

  • 🇺🇸United States alphex Atlanta, GA USA

    I can confirm this is still happening with Drupal 10.2.5 - WITH - the patch from #102 applied.

    <!-- FILE NAME SUGGESTIONS:
       x page--node--general-page.html.twig
       * page--node--2.html.twig
       * page--node--%.html.twig
       * page--node.html.twig
       * page.html.twig
    -->
    

    I would expect that "page--node--2.html.twig" would be at the top of the list.

    ----

    When I add some code I've used in past sites, to my .theme file

    function themename_theme_suggestions_page_alter(array &$suggestions, array $variables) {
      // Add content type suggestions.
      if ($node = \Drupal::request()->attributes->get('node')) {
        array_splice($suggestions, 1, 0, 'page__node__' . $node->getType());
      }
    }
    

    It puts the template suggestion, in the right spot, but the TOP one is still there, which is wrong.

    <!-- FILE NAME SUGGESTIONS:
       x page--node--general-page.html.twig
       * page--node--2.html.twig
       * page--node--%.html.twig
       x page--node--general-page.html.twig
       * page--node.html.twig
       * page.html.twig
    -->
    
  • 🇺🇸United States sapetm

    This is a tweak on the patch from comment #102. We have had this problem for a while and we've always had to, in the render function at the last point where the suggestions array is defined, apply an array_unique() to it. This has always fixed the problem for us, but I haven't tested thoroughly to see if this in fact fixes it everywhere. We are running Drupal 10.2.6 and PHP 8.1.27. Hope this helps!

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 5 months ago
    Patch Failed to Apply
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 5 months ago
    Patch Failed to Apply
  • 🇺🇸United States sapetm

    I seem to have messed up the naming convention for the patch files. This is my first time uploading a patch file. Sorry about that! Hope I did it right this time. Below is from my previous post.

    This is a tweak on the patch from comment #102. We have had this problem for a while and we've always had to, in the render function at the last point where the suggestions array is defined, apply an array_unique() to it. This has always fixed the problem for us, but I haven't tested thoroughly to see if this in fact fixes it everywhere. We are running Drupal 10.2.6 and PHP 8.1.27. Hope this helps!

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7 updated deps
    last update 5 months ago
    Patch Failed to Apply
  • 🇺🇸United States sapetm

    Sorry folks, third time's the charm, or something like that. I uploaded the wrong patch file with my other two comments. This is the patch I am using for Drupal 10.2.6 and PHP 8.1.27. It is identical to the patch in comment #102 but with the addition of an array_unique() in the second hunk when setting the value of the $suggestions array in the render function. This fixes the issue for us. Hope it helps!

  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update 4 months ago
    Patch Failed to Apply
  • 🇺🇸United States nicxvan

    Can you please add those changes to the merge request? People can then generate local patches as needed and the core team uses the actual mr for testing and merging.

  • 🇬🇧United Kingdom scott_euser

    Looks like the issue summary needs an update? Drupal 11 with default Olivero theme, no changes from clean install other than turning on twig.config debug to true now results in this which appears correct:

    The selected customisation comes from olivero.theme:

    function olivero_theme_suggestions_menu_alter(&$suggestions, array $variables) {
      if (isset($variables['attributes']['region'])) {
        $suggestions[] = 'menu__' . $variables['attributes']['region'];
      }
    }
    

    For the region 'primary_menu'. Is there a step I am missing to reproduce?

  • 🇳🇿New Zealand djroshi

    I'm going to post this as it might help someone who stumbles over this issue (as I did). This is using Drupal 10.2.6 with Bootstrap5 subtheme.

    When placing a menu block in a region (pretty normal thing to do) I get the following suggestions, prioritized first to last (as suggestions are array_reversed)

    1. menu__region-name
    2. menu__menu-name_region-name
    3. menu__menu-name

    This is counterintuitive because (in my mind at least) theme suggestions should be ordered from most specific to least specific i.e.

    1. menu__menu-name_region-name (that menu when it appears in that region)
    2. menu__menu-name (all instances of that menu)
    3. menu__region-name (all menus in that region)

    Can someone perhaps confirm if this is happening on other installs of Drupal? Or is it just me :D

  • 🇩🇪Germany Anybody Porta Westfalica

    Re #110 you're right and that's what this issue is about.

    We're still experiencing this with Drupal 10.3.0, so I don't think this is fixed without this patch.

  • 🇩🇪Germany Anybody Porta Westfalica
  • 🇮🇳India Dinesh18

    Is there a fix for this?

Production build 0.71.5 2024