Problem/Motivation
Having the following menu tree:
- item 1 (disabled) -- item 1a -- item 2a - item 2 -- item 2a - item 3
Then fetch the full menu tree with only enabled menu items:
$parameters = new MenuTreeParameters();
$parameters->onlyEnabledLinks();
$tree = \Drupal::service('menu.link_tree')->load($menu_name, $parameters);
I expect to get the following tree:
- item 2 -- item 2a - item 3
Instead I get:
- item 1a -- item 2a - item 2 -- item 2a - item 3
Proposed resolution
Don't add enabled subtree items to the tree when the parent item is disabled and the menu tree is build with the "onlyEnabledLinks" parameter set.
| Comment | File | Size | Author |
|---|---|---|---|
| #34 | 2939357-34.patch | 6.67 KB | ciprian.stavovei |
| #24 | menu_link_disabled_subtree-2939357-24.patch | 7.5 KB | Ankit.Gupta |
| #15 | menu_link_disabled_subtree-2939357-14.patch | 7.5 KB | bladedu |
| #13 | menu_link_disabled_subtree-2939357-13.patch | 5.67 KB | bladedu |
| #12 | menu_link_disabled_subtree-2939357-12.patch | 5.65 KB | bladedu |
Issue fork drupal-2939357
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
tvoesenek commentedThis patch skips the enabled subtree items of disabled parent links when building the full menu tree.
Comment #7
ckaotikThis issue also crops up with a slightly different setup:
Results in:
The patch in #2 caused my toolbar to become pretty much empty. The bunch of failed tests also indicates that the patch does not (really) fix the problem, unfortunately :(
Comment #8
ckaotikLet's see how this patch fares with the tests. Not sure if it also fixes the example @TVoesenek provided, but I would think so.
We should probably add a test for this.
Comment #9
ckaotikComment #11
bladeduI've tried both patches myself and it didn't work correctly on all scenarios.
I tried then to read the code and this part, imho, is the problem:
if ($next && $next['depth'] > $depth) {The assumption here is that if there is a next item and its depth is greather than current item, then it's a child of it. This assumption proved wrong when MenuLinkTree::load is invoked with menu tree parameter set to show only enabled links.
Here I provide a patch that address this wrong assumption (which worked in above scenarios and others)
if ($next && $next['depth'] > $depth && $next['parent'] === $tree_link_definition['id']) {Comment #12
bladeduFurther investigating it I realized that children of a disabled parent were rendering at the root with only the path above.
I expanded the above patch to avoid adding to root level items with a disabled parent.
I've also added a kernel test to validate the scenario.
Comment #13
bladeduI missed a set of parentheses in the big if.
Attached the updated one.
Comment #15
bladeduI've added a private method to better validate what goes inside the menu tree and what not.
Comment #18
andrew_l commentedWe were also having the problem where enabled child menu items of disabled parent menu item were being displayed under the wrong parent.
We are having this issue in Drupal 8; we applied the patch in #15, cleared caches and this has fixed the problem for us.
Many thanks
Comment #19
nsciaccaThe patch in #15 did suppress the disabled items and its children but it messed up the depth and parenting of other items in my menu.
Item A (enabled)
- Item A_a
-- Item A_a_1
--- Item A_a_1_i
--- Item A_a_1_ii
Item B (enabled)
- Item B_a
Item C (disabled)
- Item C_a (enabled)
ended up rendering as
Item A
Item B
- Item A_a
-- Item A_a_1
--- Item A_a_1_i
--- Item A_a_1_ii
children of Item B didn't get rendered at all
Comment #22
welly commentedThe patch at #15 also didn't work for me and removed other valid, enabled menu items. I'll have a look at the patch and see if I can get it working for my particular case.
Comment #23
bladeduComment #24
Ankit.Gupta commentedRerolled patch #14 with Drupal 9.5.x
Comment #26
dksdev01 commentedHi there, I am trying this issue as part of the contribution day Prague 2022. Thanks
Comment #28
dksdev01 commentedI created a merge request with the latest patch #24 to get familiar with the new workflow.
Comment #30
bladeduI tested the latest patch release and I confirm it works as expected.
Comment #31
bladeduUpon further testing I found out a scenario which leads to wrong results when only enabled links are requested.
The query results returned by
loadLinksmethod takes into account that only links with enabled set to 1 should be returned.In a scenario with the following tree:
A
-- Aa (disabled)
--- Aaa (enabled)
-- Ab (enabled)
The Ab element will not be rendered under A, because the algorithm in place within the method
treeDataRecursivetakes for granted that the$nextelement is possibly the first subtree element, but there could be scenarios in which this won't be true with filtered out links.So my guess is that the whole logic here isn't enough to cover all scenarios and we should also rethink a fast way to calculate the tree recursively and not having all items available.
Comment #33
danielcavanagh commentedWe've just run into a similar issue: menu items and their children being attached to the entirely wrong parent seemingly for no reason, even when all items are active
It ultimately stems from the list of links returned from DB query in MenuTreeStorage::loadLinks() not being ordered properly, despite the function correctly setting the SQL orders (p1 ASC, p2 ASC, etc.) before querying and the data in the DB being correct. It seems to make no sense. It's mostly ordering it correctly, but a few odd items are being moved out of order somehow
I suspect this is the source of a few of the problems in this thread
Perhaps there's a bug in the SQL fetch code that leads to the row order being wrecked when converted to an associative array, or perhaps there's some custom hook that runs after queries
This code triggers the issue:
This doesn't:
It seems this also doesn't tho 🙃:
We're working around the issue by not using onlyEnabledLinks() and instead manually filtering out disabled links after loading the full tree
Comment #34
ciprian.stavovei commentedI also ran into this issue while having the patch from comment #24 applied. Seems like it doesn't fix all the edge cases.
E.g:
Having the following menu tree
Expecting:
Getting:
Because there are some menu items that are active on the second level with the parent disabled, it is skipped and goes to the next one without returning the current subtree. It goes to the next link and add it to the latest sub-tree in use, instead of starting a new one. When skipping a link we should also check if we should actually return the current sub-tree because the parents changed.
Added a patch to fix it.
Comment #35
smustgrave commented@ciprian.stavovei we don't want to mix MRs and patches if we can help it, previously this appeared to be an MR, though the MR needs to be updated 11.x
moving to NW for that.
Comment #36
super_romeo commentedI tried patch #34. In my case it doesn't fully work.
My menu tree:
...
- item 4
-- item 41
--- item 411
--- item 412
--- ...
-- item 42 (disabled)
--- item 421
--- ...
-- item 43
--- item 431
--- item 432
--- ...
Expected:
...
- item 4
-- item 41
--- item 411
--- item 412
--- ...
-- item 43
--- item 431
--- item 432
--- ...
Got:
- item 4
-- item 43
--- item 431
--- item 432
--- ...
Tried to debug, but without success.
Something wrong in this part:
My workaround: don't use
OnlyEnabledLinks()and filter the disabled items in the recursion loop.