Enabled subtree links of a disabled parent link are added to the menu tree at the wrong depth.

Created on 25 January 2018, almost 7 years ago
Updated 24 July 2024, 5 months ago

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.

πŸ› Bug report
Status

Needs work

Version

11.0 πŸ”₯

Component
Menu systemΒ  β†’

Last updated 20 minutes ago

Created by

πŸ‡³πŸ‡±Netherlands tvoesenek

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

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

  • We'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 were 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

        for ($i = 1; $i <= $this->maxDepth(); $i++) {
          $query->orderBy('p' . $i, 'ASC');
        }
        ...
        $links = $this->safeExecuteSelect($query)->fetchAllAssoc('id', \PDO::FETCH_ASSOC);
        // links are already out of order
    

    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:

    $parameters = new MenuTreeParameters();
    $parameters->onlyEnabledLinks();
    

    This doesn't:

    $parameters = new MenuTreeParameters();
    

    It seems this also doesn't tho πŸ™ƒ:

    $parameters = new MenuTreeParameters();
    $parameters->onlyEnabledLinks();
    $parameters->addCondition('expanded', 1);
    $parameters->setActiveTrail([...]);
    $parameters->setMaxDepth(3);
    

    We're working around the issue by not using onlyEnabledLinks() and instead manually filtering out disabled links after loading the full tree

  • Status changed to Needs review about 1 year ago
  • πŸ‡·πŸ‡΄Romania ciprian.stavovei

    I 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

    - item 1
    -- item 1a
    -- item 2a
    --- item 3a
    - item 2 (disabled)
    -- item 2a
    - item 3
    -- item 3a
    --- item 3b
    - item 4
    

    Expecting:

    - item 1
    -- item 1a
    -- item 2a
    --- item 3a
    - item 3
    -- item 3a
    --- item 3b
    - item 4
    

    Getting:

    - item 1
    -- item 1a
    -- item 2a
    --- item 3a
    - item 3
    -- item 3a
    --- item 3b
    -- item 4
    

    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.

  • Status changed to Needs work about 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    @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.

  • last update about 1 year ago
    29,722 pass
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Environment: PHP 8.1 & MySQL 5.7 updated deps
    last update about 1 year ago
    30,493 pass, 77 fail
  • πŸ‡·πŸ‡ΈSerbia super_romeo Belgrade

    I 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:

    if (!empty($tree_parent['depth'])
      && $tree_link_definition['depth'] > $tree_parent['depth']
      && $tree_link_definition['parent'] !== $tree_parent['id']
    ) {
      return $tree;
    }
    

    My workaround: don't use OnlyEnabledLinks() and filter the disabled items in the recursion loop.

Production build 0.71.5 2024