#1896674: On primary navigation menu, class 'active' is not set on active menu item Added some code for setting the 'active' link class. The way this was implemented breaks other modules' logic. For instance, it completely disregards anything done in hook_preprocess_menu_link() to unset the active link and slaps it right back on there.

The least we should do is set that logic in hook_preprocess_menu_link() so other implementations can undo whatever Bootstrap did. Placing business logic in the theme hook bootstrap_menu_link() is not the best way of doing things.

Also see #1896674-11: On primary navigation menu, class 'active' is not set on active menu item for another reported problem with the code that got added.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kristiaanvandeneynde created an issue. See original summary.

regilero’s picture

+1

markhalliwell’s picture

Status: Active » Closed (outdated)

No patch or further complaints about it.

kristiaanvandeneynde’s picture

Status: Closed (outdated) » Active

I'd agree with the "Closed (Outdated)" status if it weren't for the fact that the bug is still very much there.

The code that sets the active class should at least be moved to bootstrap_preprocess_menu_link() so that other modules may decide whether they want that link to show as active or not. The other code in bootstrap_menu_link() is fine because it actually relates to how you want to theme the menu link.

markhalliwell’s picture

Title: #1896674 introduced broken logic » Only set "active" class on menu links based on "active-trail"

Ok. I re-read the issue(s). I'm still a little unclear as to what the "bug" is exactly.

The problem with using the "active-trail" bit is that it isn't always that accurate either in 7.x; especially if the link's href if <front>.

Also, whether this code is in bootstrap_menu_link() or bootstrap_preprocess_menu_link() doesn't really matter. They're both invoked after modules.

That being said, I'll upload a patch here shortly to see if it helps with what you're talking about.

markhalliwell’s picture

Status: Active » Needs review
FileSize
1.63 KB
markhalliwell’s picture

FileSize
1.56 KB

Actually, no need for an elseif.

kristiaanvandeneynde’s picture

The issue is that there is no way to strip the 'active' class.

This is because the class will always get added back when styled unless you go out of your way to copy-paste the whole function body of bootstrap_menu_link() into mysubtheme_menu_link() just to remove the part that sets the 'active' class.

It's fine to add classes in a theme function if they are specific to your theme. The 'active' class isn't, however, and should thus be added in a preprocess function so other modules/subthemes can at least remove it again.

markhalliwell’s picture

The 'active' class isn't, however, and should thus be added in a preprocess function so other modules/subthemes can at least remove it again.

  1. Yes, it is specific to this base theme. Almost every Bootstrap nav based component requires the an "active" class is present on the <li> element. That isn't a requirement in core, hence why this is added.
  2. Modules cannot/should not, ever, remove something that was added by any theme. That is not how the system is designed to work.
  3. Yes, sub-theme's would have to override this theme function. That is how the system is designed to work.
  4. The theme function isn't big enough to justify what you're proposing. This is for a seemingly small use-case (of which, no use case has yet to be provided) for why this is is actually needed.
  5. In 8.x-3.x, this "active" class is added on inside the Twig template itself (the theme function equivalent).
  6. Ultimately, moving this to a preprocess would technically be a BC break. A change notice would need to be created. This is not something I'm not too happy about introducing.

I'm trying to compromise here, but you're not understanding what the complexities your proposal actually entails.

The patch in #7 is, more or less, the best I can come up with. Have you tried it?

kristiaanvandeneynde’s picture

The patch in #7 looks fine, but it still doesn't fix the use case where I needed to unset the active class because of this bit: $element['#href'] == '<front>' && drupal_is_front_page().

The use case I had was a menu that had two links to the front page and was present on every page, except each link would point to a different space (Spaces module). Consider a space a context.

Because we effectively used that menu as a "space switcher", we needed to unset the active class on the link that was not pointing to the active space. This was impossible without overwriting the theme function, for something that ideally could have been done in a preprocess function.

I still don't see how you consider the active class as something Bootstrap-specific. If you look at menu_tree_output(), menu_navigation_links(), etc. you'll see core actually sets this class regardless of the active theme. It didn't seem to break Bootstrap for me when I removed it, that is.

Anyways, the patch in #7 looks fine for what you changed the issue title to. I'm just detailing the use case I had here which is impossible to pull off with Bootstrap unless you overwrite the entire theme function.

I do understand the complexities behind what I'm discussing here, don't get me wrong. I'm simply debating whether this specific class shouldn't have been handled by a preprocess function instead.

P.S.: I don't mean to annoy you with this, even if I inadvertently have.

markhalliwell’s picture

Title: Only set "active" class on menu links based on "active-trail" » Move menu_link "active" class logic into a preprocess function and base it on "active-trail"
Issue tags: +Needs change record

$element['#href'] == '<front>' && drupal_is_front_page()

Like I said above, there's no other way to get the "active" class on these links. It doesn't get the active-trail class or even the in_active_trail flag set on the original menu item. Not even with a helper module like Menu Trail by Path does this work. This is primarily due to the broken nature of core in 7.x and why in 8.x the entire menu system was replaced with the concept of true routes. This logic cannot be removed. Period.

Because we effectively used that menu as a "space switcher", we needed to unset the active class on the link that was not pointing to the active space.

Honestly though, this sounds more like a fundamental architectural flaw in the decisions that were made. Using a not so widely installed (< 3k) contrib module in an attempt to provide another alternative way to solve another type of multi-site scenario. This project simply cannot cater to every single contrib/custom module that decides to do things just a little differently for their use cases. I could understand more if it was something that is a commonly used module/best practice.

This was impossible without overwriting the theme function, for something that ideally could have been done in a preprocess function.

I'm trying to understand here. How is copying and pasting < 40 lines of code is too difficult? I honestly cannot understand the rational behind this argument. If it were, say, regarding something extremely more complex like the page theme hook.. then sure, this would make sense to do. As it stands now, it literally can be replaced in a sub-theme within 5 seconds.

I still don't see how you consider the active class as something Bootstrap-specific. If you look at menu_tree_output(), menu_navigation_links()...

Yes, these functions do add an active class, but on the link itself (#localized_options)... not on the <li> element wrapping it. That is what I meant by that it is unique to what Bootstrap expects for their nav components to function properly. The active class that is set on the links themselves have absolutely no effect in Bootstrap.

I don't mean to annoy you with this, even if I inadvertently have.

Not at all, you're perfectly fine :D A common misconception when people interact with me is that, while I may be annoyed, it's not at them personally. It has more to do with the fact that little to no information was provided to describe the issue at hand, provide steps to reproduce and justification through use cases.

As you can see here, it's taken several comments to get to a point where I actually understand what's going on here (in your situation). I have limited time and that's why the issue was closed after 8 months of... nothing. No further explanation other than "#1896674 introduced broken logic". That doesn't give me a lot to go on when no one else has really complained about this.

I'm not unsympathetic to your issue, I'm just burdened by responsibility to all for the quality and integrity of this code.

---
I still don't necessarily agree the above rational behind moving this into a preprocess function. That being said, this issue will still need a change record regardless to inform people that the logic for this has changed and if they overrode the theme function in their sub-theme, they will need to update it.

Since we're going to have to do that anyway, I suppose we can also go ahead with the move to a preprocess function. The change record can just say that they should remove the logic for this in their overridden theme function and let the base theme handle it. If they did indeed customize this active class logic, then they will need to move that into a sub-theme preprocess function.

I'll commit a fix for all of this shortly.

Cautionary note: I may still, ultimately, revert this commit/decision if enough people complain about BC breaks. Menus are already a touchy subject in this project and many already customize it to suit their needs. I won't be all that surprised if this causes a lot of grief.

  • markcarver committed 7e4dd31 on 7.x-3.x
    Issue #2618828 by markcarver, kristiaanvandeneynde, regilero: Move...
markhalliwell’s picture

Status: Needs review » Fixed
markhalliwell’s picture

Issue tags: -Needs change record
kristiaanvandeneynde’s picture

Using a not so widely installed (< 3k) contrib module in an attempt to provide another alternative way to solve another type of multi-site scenario.

Well, it's actually a really cool module. It's basically Domain Access, but for other ways of triggering your context (path, taxonomy, ...). It lost a lot of installs to Domain Access over the years because Spaces is more of an API whereas DA offers a good UI.

Yes, these functions do add an active class, but on the link itself (#localized_options)... not on the <li> element wrapping it.

Oh, right. Subtle but important difference.

Since we're going to have to do that anyway, I suppose we can also go ahead with the move to a preprocess function.

Yay, I completely agree with your reasoning.

I may still, ultimately, revert this commit/decision if enough people complain about BC breaks.

Naturally.

Thanks for taking the time to resolve this issue!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.