Problem/Motivation
When you have a complex setup of a couple of themes that are inheriting each other, something like:
theme_1 <- theme_2 <- theme_3 <- client_theme
where theme_1 is the starting base theme, and each theme is overriding various libraries from parent themes library override definitions can fail when multiple themes are overriding the same library.
In LibraryDiscoveryParser::applyLibrariesOverride() next call on line 339
$all_libraries_overrides = $active_theme->getLibrariesOverride();
Will return array of library overrides for all themes but in the wrong order, like
[
'theme_3' => [...],
'theme_2' => [...],
'theme_1' => [...],
'client_theme' => [...],
]
The correct order would be
[
'theme_1' => [...],
'theme_2' => [...],
'theme_3' => [...],
'client_theme' => [...],
]
As a consequence of this wrong order applyLibrariesOverride() can and will fail for libraries that are overridden for example in theme_1 and theme_3 because override is applied in the wrong order. Order is important for now because of #2642122: Overriding already overridden libraries-override requires knowledge of previous libraries-overrides.
Proposed resolution
Active theme libraries-override array should respect theme inheritance order and have parent themes in the correct order.
Remaining tasks
- Figure should we fix some other definitions also like 'libraries' because they are also in the wrong order. Maybe this affects the loading of resources in the wrong order?
User interface changes
None.
API changes
None.
Data model changes
None.
Release notes snippet
Comment | File | Size | Author |
---|---|---|---|
#28 | Screenshot 2023-10-27 at 11.24.48 AM.png | 33.19 KB | smustgrave |
#26 | 23-26.txt | 1.01 KB | tonibarbera |
#26 | 3073053-26.patch | 5.67 KB | tonibarbera |
|
Issue fork drupal-3073053
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:
Comments
Comment #2
pivica CreditAttribution: pivica at MD Systems GmbH commentedHere is a first patch that is fixing order for the libraries-override part.
I am not 100% sure should we reverse $base_themes on the start for all getActiveTheme() call, the comment that is explaining correct order is a bit confusing:
I guess the comment is trying to say that the first parent of the active theme should be on the top level of the array. This would mean that $base_themes is passed in the correct order and that we should reverse it inside of getActiveTheme() method just for some cases like 'libraries-override' is.
Comment #3
Wim LeersWow, excellent find! Thanks for explaining it so clearly, and for creating a patch that fixes it. For this to be committable, it needs to have a test that reproduces the bug. Do you think you could do that? :)
Comment #5
mbovan CreditAttribution: mbovan at MD Systems GmbH commentedSetting it to Needs work because of missing tests.
Comment #7
Primsi CreditAttribution: Primsi commentedComment #8
Primsi CreditAttribution: Primsi commentedAdding a test. I added it to LibraryDiscoveryIntegrationTest, or it would make more sense somewhere else?
Comment #9
Primsi CreditAttribution: Primsi commentedComment #12
pivica CreditAttribution: pivica at MD Systems GmbH commentedI've found one more problem with reversed call order. For the same themes inherit example, as in issue description, the Drupal\Core\Theme\ThemeManager::alterForTheme() will call functions in the wrong/reversed order.
So, for example, if all themes are defining hook_form_alter() ThemeManager::alterForTheme will call hooks in this order:
and the correct order is:
The problem is inherited from the same place, in ThemeInitialization::getActiveTheme() we are doing:
which has themes in reversed order, and then later we are using this value to initialize ActiveTheme::baseThemeExtensions variable which will be returned by ActiveTheme::getBaseThemeExtensions() which is used in ThemeManager::alterForTheme().
As an experiment, I've tried to reverse $base_themes for all method code in ThemeInitialization::getActiveTheme() but that created other unexpected problems. So we can't do that.
Then I've checked can we just array_reverse for `$values['base_theme_extensions']` but that is also not an option because some places are already using array_reverse() approach, like Drupal\Core\ThemeRegistry::build() and in the same class postProcessExtension(), and webform WebformThemeManager::getActiveThemeNames().
So I guess the only thing we can do currently is to find all places where getBaseThemeExtensions() call is used and make sure that array_reverse is applied to them. Not an ideal solution at all but I can't think a better approach for now.
Here is a patch that is adding array_reverse where needed and also adds explanation to getBaseThemeExtensions() comment about this.
If new patch makes sense should we add additional tests that are covering other cases?
Comment #13
pivica CreditAttribution: pivica at MD Systems GmbH commentedSorry, the last patch is a wrong diff, this one is correct. Interdiff is fine.
Comment #14
pivica CreditAttribution: pivica at MD Systems GmbH commented> If new patch makes sense should we add additional tests that are covering other cases?
Quickly checking new changes it looks to me that we can't really create tests for other changes because those places are only calling other functions.
Comment #15
BerdirI guess the wording could be improved a bit?
"For most use cases, parent themes are expected to be called first, so this order needs to be reversed with array_reverse()."?
This is not on an interface, so a possible option could also be to add an argument (or a separate method) to let it to the array_reverse() internally, e.g. function getBaseThemeExtensions($root_first = FALSE). But don't make that change just based on my feedback, lets see what others think.
We can test this indirectly. Add a form alter to the example themes that we already use in the other test, then similar to block_form_form_test_alter_form_alter(). Then we can extend \Drupal\Tests\system\Functional\Form\AlterTest with the additional messages. I think it's OK to extend that existing test for that.
Comment #18
pivica CreditAttribution: pivica at MD Systems GmbH commentedThis issue is maybe partially related (alter call order fixing) to #2118743: Twig debug output does not display all suggestions when an array of theme hooks is passed to #theme.
Comment #21
unstatu CreditAttribution: unstatu commentedHi all,
@pivica thanks for the patch and for reporting the bug. When I discovered the problem I was not sure if it was a bug or it wasn't and I was not very comfortable creating an issue for it since it has a quite a big impact in the core. Then, I found your ticket and saw that it has been well received. That made me happy :)
Well, I'll go straight to the point:
- I have tried to apply the patch on 9.3.12 without success so I have created a MR with a reroll
- Besides to the reroll I have applied the @Berdir suggestion to improve the wording.
Related to the changes in the method. I don't think it does worth to create a new method for changing the order. IMO, it will add some confusion about it. However, I think it is a good idea to add the $root_first parameter with the default value to it. If there is some consensus, I can do it.
Also, I think it's a good idea to extend the \Drupal\Tests\system\Functional\Form\AlterTest for testing the new behavior.
Comment #23
pooja saraah CreditAttribution: pooja saraah at Srijan | A Material+ Company for Drupal India Association commentedFixed failed commands on #20
Attached patch against Drupal 9.5.x
Comment #26
tonibarbera CreditAttribution: tonibarbera as a volunteer commentedRerolled patch for Drupal 10.1.5 and the interdiff
Comment #27
smustgrave CreditAttribution: smustgrave commented11.x is the current development branch, running #26 against 11.x
Comment #28
smustgrave CreditAttribution: smustgrave commentedRan the tests without the fix and got expected failure. Removing tests tag.
Moving to NW though for the open remaining task
Has this been figured out?
Comment #29
lauriiiI'm not sure that's required to fix bug that this issue is focused on, although it could be another related bug. I was thinking of a follow-up but I'm not sure if we need that unless the bug exists. Regardless, I think this could use a review.
Comment #30
smustgrave CreditAttribution: smustgrave commentedIn that case then patch #26 addresses the problem at hand.
FYI should try to use MRs vs patches as patches are slowly phased out. MRs can be much faster and easier to review.
Comment #32
longwaveCommitted 528ac57 and pushed to 11.x. Thanks!
Decided not to backport to 10.2.x as this seems quite an obscure bug that doesn't affect many users, but I'm concerned that making this change in a patch release might have an unintended side effect in case anyone is currently somehow relying on the existing broken behaviour without realising it.