Class active-trail not added to li element when linking to front page

Created on 15 May 2012, almost 13 years ago
Updated 20 November 2024, 4 months ago

D8 explanation:

I've installed bootstrap 8.x-3.x on a multilanguage site, but in the default main menu the home link is never active, when I'm in the home page the claass="is-active" won't appear.
This doesn't just occur with bootstrap though, it's a core issue.
See screenshots:

Active class missing (illustration)

Active After Applying Active Class

D7 explanation:

There is a bug with the "active-trail" class not showing up on <li> for menu items with Drupal 7.14. The problem is that "active-trail" is missing for a menu link to the front page (path "<front>"), all other links have "active-trail" just fine.

The situation is also slightly different for the horizontal primary link tabs that can be switched on from theme settings Toggle display - Main menu, than they are for the vertical navigation in the Main menu block. In the horizontal tabs the front page <li> has "active" but not "active-trail". So "active" could be used to do get around this issue for horizontal menus. But unfortunately if you want the vertical menu, there is no "active" nor "active-trail".

I verified that both "active" and "active-trail" are missing with a fresh install without any added modules on Drupal 7.4 to 7.14. The behaviour is identical with Bartik, Garland and Stark themes, as well as Zen.

Steps to reproduce:

1. Create a fresh install of Drupal 7.14.
2. On the front page go to Structure -> Blocks.
3. Move "Main menu" block to "First sidebar"
4. Create a new "Basic page" with test content and click "Provide a menu link" -> "Parent item" [Main menu]
5. Use e.g. Firebug to verify that the newly created test page link on the sidebar has "active-trail" on <li> but "Home" does not.

Attached is a patch that fixes the bug by adding special handling for the front page when adding the active-trail class. A better solution would be to get the 'in_active_trail' variable correctly set for links to <front>, but unfortunately I could not find out how to do that.

🐛 Bug report
Status

Needs work

Version

11.0 🔥

Component

menu system

Created by

🇫🇮Finland ttiurani

Live updates comments and jobs are added and updated live.
  • 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.

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.

  • 🇺🇸United States dcam

    The following workaround code was adapted from #64. It corrects the problem of flagging all routes of the same name by also comparing the route parameters.

    /**
     * Prepares variables for block__system_menu_block templates.
     *
     * Work around an issue where front page menu links are not set in the
     * active trail.
     *
     * Default template: block.html.twig.
     *
     * @see https://www.drupal.org/project/drupal/issues/1578832
     */
    function my_theme_preprocess_block__system_menu_block(&$variables) {
      if (!\Drupal::service('path.matcher')->isFrontPage()) {
        return;
      }
    
      $homepage_path = \Drupal::config('system.site')->get('page.front');
      $homepage_url = \Drupal::service('path.validator')->getUrlIfValid($homepage_path);
      if (!$homepage_url instanceof Url) {
        return;
      }
    
      foreach ($variables['content']['#items'] as $key => $item) {
        /** @var \Drupal\Core\Url $url */
        $url = $item['url'];
        if (!($url instanceof Url) || !$url->isRouted()) {
          continue;
        }
    
        $is_front = $url->getRouteName() == '<front>';
        $is_configured_route = $url->getRouteName() == $homepage_url->getRouteName() &&
          $url->getRouteParameters() == $homepage_url->getRouteParameters();
        if ($is_front || $is_configured_route) {
          $variables['content']['#items'][$key]['in_active_trail'] = TRUE;
        }
      }
    }
    
  • 🇺🇸United States dcam

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

  • Pipeline finished with Failed
    4 months ago
    #368140
  • 🇺🇸United States dcam

    I disagree with the approach in the previous MR that made MenuTreeStorage::loadByRoute() load front page routes. It violates the single responsibility principle and will result in unexpected behavior for calling code.

    My own approach is to add a check for the front page to the menu.active_trail service's getActiveLink() function. That function is responsible for determining whether a menu is in the trail or not. <front> is effectively an alias for the front page route. So if anything needs to compensate for these non-standard <front> links, that seems like the most appropriate function to do it.

    That said, I was a little confused at first because the docblock for MenuActiveTrailInterface::getActiveLink() is misleading:

      /**
       * Fetches a menu link which matches the route name, parameters and menu name.
       *
       * @param string|null $menu_name
       *   (optional) The menu within which to find the active link. If omitted, all
       *   menus will be searched.
       *
       * @return \Drupal\Core\Menu\MenuLinkInterface|null
       *   The menu link for the given route name, parameters and menu, or NULL if
       *   there is no matching menu link or the current user cannot access the
       *   current page (i.e. we have a 403 response).
       */
    

    There is no "given route" because you don't pass a route to the function. Instead, it gets the current route from the current_route_match service. There's some code smell going on here. I assert that the docblock in the interface is incorrect and needs to be changed. I updated it to say that it looks for a menu link for the currently active route, although even that can't be guaranteed by the interface. There's an argument that the docblock change should be a separate issue, but since we're altering the behavior of this function to look for "alias" links that should be active for the current route, then I argue that it's an appropriate change for this issue.

    The lack of route injection for the function also made the test harder to write. I tried to make a kernel test, but eventually punted on that and made a functional test that checks for Olivero's active trail class. I don't like it, but I couldn't figure out how to do it any other way. If someone has suggestions, please let me know.

  • 🇺🇸United States dcam

    dcam changed the visibility of the branch 1578832-tree-storage-check-front to hidden.

  • Pipeline finished with Failed
    4 months ago
    Total: 195s
    #368158
  • Pipeline finished with Failed
    4 months ago
    #368164
  • 🇬🇧United Kingdom oily Greater London

    oily changed the visibility of the branch 1578832-tree-storage-check-front to hidden.

  • 🇬🇧United Kingdom oily Greater London
  • Pipeline finished with Failed
    4 months ago
    Total: 638s
    #368186
  • 🇬🇧United Kingdom oily Greater London

    @dcam There seems to be a test has got broken. Line 126 of SystemMenuBlockTest.php seems root of the problem?:

      // This creates a tree with the following structure:
        // - 1
        // - 2
        //   - 3
        //     - 4
        // - 5
        //   - 7
        // - 6
        // - 8
        // With link 6 being the only external link.
        $links = [
          1 => MenuLinkMock::create(['id' => 'test.example1', 'route_name' => 'example1', 'title' => 'foo', 'parent' => '', 'weight' => 0]),
          2 => MenuLinkMock::create(['id' => 'test.example2', 'route_name' => 'example2', 'title' => 'bar', 'parent' => '', 'route_parameters' => ['foo' => 'bar'], 'weight' => 1]),
          3 => MenuLinkMock::create(['id' => 'test.example3', 'route_name' => 'example3', 'title' => 'baz', 'parent' => 'test.example2', 'weight' => 2]),
          4 => MenuLinkMock::create(['id' => 'test.example4', 'route_name' => 'example4', 'title' => 'qux', 'parent' => 'test.example3', 'weight' => 3]),
          5 => MenuLinkMock::create(['id' => 'test.example5', 'route_name' => 'example5', 'title' => 'title5', 'parent' => '', 'expanded' => TRUE, 'weight' => 4]),
          6 => MenuLinkMock::create(['id' => 'test.example6', 'route_name' => '', 'url' => 'https://www.drupal.org/', 'title' => 'bar_bar', 'parent' => '', 'weight' => 5]),
          7 => MenuLinkMock::create(['id' => 'test.example7', 'route_name' => 'example7', 'title' => 'title7', 'parent' => 'test.example5', 'weight' => 6]),
          8 => MenuLinkMock::create(['id' => 'test.example8', 'route_name' => 'example8', 'title' => 'title8', 'parent' => '', 'weight' => 7]),
        ];
    
  • Pipeline finished with Failed
    4 months ago
    Total: 3034s
    #368192
  • 🇬🇧United Kingdom oily Greater London

    Adding Issue tags:

    The Issue summary is for Drupal 7. Before and after screenshots for Drupal 11 are needed.

  • 🇬🇧United Kingdom oily Greater London
  • 🇬🇧United Kingdom oily Greater London

    Have updated the Issue summary so it makes more sense in relation to Drupal 11.

    There is more work to do. The screenshots need to be updated for Drupal 11 and any discrepancies with the existing D8 and D7 sections in the issue summary can be rectified.

  • 🇺🇸United States dcam

    @dcam There seems to be a test has got broken.

    Yeah. I saw that. But it was well past quitting time for the day, so I haven't tried to debug it. That's why I didn't set the issue status to Needs Review. Just from glancing at the backtrace it looked like the change to the service either broke the system menu block or maybe just the test. I'm not sure which.

  • 🇬🇧United Kingdom oily Greater London

    @dcam Great work. This is a long-standing bug!

  • 🇺🇸United States dcam

    SystemMenuBlockTest was failing because it mocks all the routes. But when the menu links were being built for the block they went through the path.matcher service which checked for the existence of the routes. Since they didn't actually exist it threw exceptions. I mocked the service to fix the test.

  • Pipeline finished with Failed
    4 months ago
    Total: 290s
    #370343
  • Pipeline finished with Failed
    4 months ago
    Total: 262s
    #370349
  • Pipeline finished with Success
    4 months ago
    Total: 858s
    #370365
  • 🇺🇸United States dcam
  • 🇬🇧United Kingdom oily Greater London

    @dcam Great!

  • 🇺🇸United States dcam

    Issue summary update

  • 🇺🇸United States dcam
  • 🇺🇸United States smustgrave

    Left some comments on MR

    Thanks

  • Pipeline finished with Success
    3 months ago
    Total: 655s
    #382025
  • Pipeline finished with Failed
    3 months ago
    Total: 662s
    #382052
  • Pipeline finished with Failed
    3 months ago
    Total: 942s
    #382065
  • 🇺🇸United States dcam

    A kernel test needs to be created to verify the fix.

  • Pipeline finished with Failed
    3 months ago
    Total: 7846s
    #382096
  • First commit to issue fork.
  • Pipeline finished with Success
    3 months ago
    Total: 923s
    #386580
  • 🇪🇸Spain vidorado Logroño (La Rioja)

    I’ve contributed my two cents and implemented it as a unit test, as the necessary mocking was straightforward, just like in the existing MenuActiveTrailTest unit test.

    I've tested the MenuActiveTrail::getActiveLink() method, which should return the first <front> route menu link when the current page is the front page and corresponds to a route without its "own" links. This scenario occurs in a default fresh Drupal installation, where the home page is the view.frontpage.page_1 route and the main navigation menu has only a "Home" link provided by the system core module for the route <front>.

  • 🇺🇸United States smustgrave

    Super close, just 1 more comment.

  • Pipeline finished with Failed
    3 months ago
    Total: 152s
    #392155
  • Pipeline finished with Failed
    3 months ago
    Total: 160s
    #392175
  • Pipeline finished with Failed
    3 months ago
    Total: 153s
    #392208
  • Pipeline finished with Failed
    3 months ago
    Total: 2706s
    #392220
  • Pipeline finished with Failed
    3 months ago
    Total: 168s
    #392286
  • Pipeline finished with Success
    3 months ago
    Total: 411s
    #392294
  • 🇪🇸Spain vidorado Logroño (La Rioja)

    That was a hard one! :)

  • 🇺🇸United States smustgrave

    Thanks! just needs a rebase now and think it's good to move up

  • Pipeline finished with Success
    3 months ago
    Total: 915s
    #392548
  • 🇪🇸Spain vidorado Logroño (La Rioja)

    Oops! I'm sorry, I was so focused on the test pipeline passing that I overlooked the merge conflicts :)

    Thanks for the review!

  • 🇺🇸United States smustgrave

    Thanks, believe this is good to go now.

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

  • Pipeline finished with Success
    2 months ago
    Total: 939s
    #400953
  • 🇺🇸United States dcam

    Updated the target branch. Restoring RTBC status.

  • 🇬🇧United Kingdom oily Greater London

    @dcam just re-ran the one failing test

  • Pipeline finished with Success
    2 months ago
    Total: 4369s
    #407862
  • 🇬🇧United Kingdom oily Greater London

    Pipeline green, test only test fails as it should.

  • 🇺🇸United States dcam

    Thanks @oily. I forgot to check on the test results after I rebased the MR to make certain it would still apply after all the recent commits to Core.

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

  • Pipeline finished with Failed
    2 months ago
    Total: 719s
    #411303
  • Pipeline finished with Failed
    2 months ago
    Total: 808s
    #411325
  • 🇺🇸United States dcam

    I'm going to have to iteratively update the StandardPerformanceTest to account for the changes to the cache as a result of the bug fix. Because for some reason my local environment doesn't want to run FunctionalJavascript tests today so that I can do this in one commit.

  • 🇪🇸Spain vidorado Logroño (La Rioja)

    I could help you out if you want. Let me know here or contact me in slack :)

  • Pipeline finished with Failed
    2 months ago
    Total: 452s
    #411350
  • Pipeline finished with Success
    2 months ago
    Total: 582s
    #411360
  • 🇺🇸United States dcam

    All the tests are green again. I'm setting this back to Needs Review instead of RTBC only because this wasn't a simple rebase this time. I had to make adjustments to the expected values in the StandardPerformanceTest. They're probably innocuous, but someone should look them over.

  • 🇪🇸Spain vidorado Logroño (La Rioja)

    The new numbers look reasonable to me

  • Pipeline finished with Failed
    about 2 months ago
    Total: 547s
    #413612
  • Pipeline finished with Success
    about 2 months ago
    #413628
  • 🇺🇸United States dcam

    I rebased again due to a merge conflict caused by this morning's commits to Core. This was an easier rebase than the last one, so I'm leaving it at RTBC.

  • Pipeline finished with Success
    about 2 months ago
    Total: 720s
    #419284
  • Pipeline finished with Success
    about 2 months ago
    Total: 508s
    #420364
  • 🇺🇸United States drupgirl

    Marking as needs work, as this patch does not apply to 10.4.

  • 🇪🇸Spain vidorado Logroño (La Rioja)

    That's normal @drupgirl, it has to apply to the last major development branch (11.x in this case)

    You can make a backport and publish it here as a patch, for others.

  • 🇪🇸Spain vidorado Logroño (La Rioja)
  • Pipeline finished with Success
    30 days ago
    Total: 896s
    #439295
  • Pipeline finished with Success
    29 days ago
    Total: 417s
    #439816
  • 🇺🇸United States dcam

    Sorry for all the rebasing spam. I've been trying to keep this up to date despite all of the other recent commits. Practically every change to the performance test forces a rebase and update of this MR.

  • Pipeline finished with Failed
    23 days ago
    Total: 529s
    #444983
  • 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.

  • Pipeline finished with Failed
    13 days ago
    Total: 984s
    #453251
  • Pipeline finished with Canceled
    13 days ago
    Total: 121s
    #453265
  • Pipeline finished with Failed
    13 days ago
    Total: 422s
    #453270
  • Pipeline finished with Failed
    13 days ago
    Total: 394s
    #453322
  • Pipeline finished with Success
    13 days ago
    Total: 410s
    #453335
  • 🇺🇸United States dcam

    I rebased the MR against 11.x again. Restoring RTBC status.

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

  • Pipeline finished with Failed
    11 days ago
    Total: 702s
    #455016
  • Pipeline finished with Failed
    11 days ago
    Total: 1218s
    #455066
  • Pipeline finished with Success
    11 days ago
    Total: 688s
    #455078
  • 🇺🇸United States dcam

    Rebased again.

  • Pipeline finished with Success
    10 days ago
    Total: 882s
    #455743
  • 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.

  • Pipeline finished with Success
    about 8 hours ago
    #463397
  • Pipeline finished with Failed
    about 8 hours ago
    #463412
  • Pipeline finished with Success
    about 7 hours ago
    #463432
  • 🇺🇸United States dcam

    Rebased. Again. Restoring RTBC.

Production build 0.71.5 2024