I have a scenario where menu attributes added to menu items do not render when using a Bootstrap-based subtheme.

  • Using Bootstrap as the base theme.
  • Using the -dev version of the Menu Link Attributes module.
  • Menu is a hierarchy.
  • Attributes are added to a top-level menu item that has child menu items.

For example:

  • Menu 1
  • Menu 2
    • Menu 2.1
    • Menu 2.2
  • Menu 3

When I add an attribute to "Menu 2.1", and show it as expanded, the attribute does not display.

But, if I add an attribute to "Menu 3", the attribute displays properly.

It appears that this is a conflict between this module and Bootstrap, as when I try the exact same scenario using core Bartik, all attributes render as expected.

I have also posted this issue in the Menu Link Attributes issue queue (sorry for the cross-posting!)

-mike

Comments

ultimike created an issue. See original summary.

markhalliwell’s picture

Category: Bug report » Feature request
Status: Active » Closed (won't fix)

Seeing how this is a contrib module compatibility issue and no patch provided, I'm marking as such given current project priorities.

If someone feels they want to tackle this specific issue (e.g. do the work and provide a patch), please feel to re-open.

nanobyt3’s picture

Category: Feature request » Support request
Status: Closed (won't fix) » Active

If we take the 'stable' theme from core, it plays well with menu_link_attributes module.
I have tried to re-build/override menu.html.twig at sub-theme level.
Not sure how correct is the bleow code or approach, but it seems to resolve my issue and I am able to set classes (at <li> and <a> levels) using menu_link_attributes module:

{% import _self as menus %}
{{ menus.menu_links(items, attributes, 0) }}

{% macro menu_links(items, attributes, menu_level) %}
  {% set classes = ['menu', 'nav'] %}
  {% import _self as menus %}
  {% if items %}
    {% if menu_level == 0 %}
      <ul{{ attributes.addClass(classes) }}>
    {% else %}
      <ul class="dropdown-menu">
    {% endif %}
    {% for item in items %}
      {%
        set item_classes = [
          item.is_expanded and item.below ? 'expanded',
          item.is_expanded and menu_level == 0 and item.below ? 'dropdown',
          item.in_active_trail ? 'active-trail',
          loop.first ? 'first',
          loop.last ? 'last',
        ]
      %}
      {% if menu_level == 0 and item.is_expanded and item.below %}
        <li{{ item.attributes.addClass(item_classes) }}>
          <a href="{{ item.url }}" >{{ item.title }} <span class="caret"></span></a>
      {% else %}
        <li{{ item.attributes.addClass(item_classes) }}>
          {{ link(item.title, item.url) }}
      {% endif %}
      {% if item.below %}
        {{ menus.menu_links(item.below, attributes, menu_level + 1) }}
      {% endif %}
      </li>
    {% endfor %}
    </ul>
  {% endif %}
{% endmacro %}

I guess, if this works, a similar approach can be taken to create a patch for bootstrap base-theme's menu.html.twig. Please review and suggest refinements.

Just my view, but, if in Drupal 7, bootstrap module and menu_attributes module (similar to menu_link_attributes module in functionality), were working properly, then in Drupal 8 it should work too. I have tried other D8 modules like menus_attribute, which also do not work with bootstrap as base-theme.

subbu94’s picture

Assigned: Unassigned » subbu94
subbu94’s picture

StatusFileSize
new74.89 KB

Looks like this is a Configuration changes.
You need to change the menu levels in the menu block.
To do so,
1. Go to admin/structure/block/manage/main_menu here you can notice MENU LEVELS under block Title field and top of Visibility field.
2. Click on MENU LEVELS,then you can find Initial visibility level and Number of levels to display.
3. Change the levels as per you requirement.

PFA Screenshot

Please Review

subbu94’s picture

Assigned: subbu94 » Unassigned
Status: Active » Needs review
gge’s picture

Needs review status should be set when a patch is provided. See more here: https://www.drupal.org/issue-queue/status

markhalliwell’s picture

Status: Needs review » Closed (works as designed)
kreatil’s picture

I experienced the same problem as described. Nevertheless, I managed to add custom attributes to the wrapping 'li' container elements by editing the configuration page as described here.

As for the original problem of missing links attributes: if someone here could outline a solution I would like to work out a patch.

nanobyt3’s picture

Attached is a patch based on code in comment #3

chrisolof’s picture

Category: Support request » Bug report
Status: Closed (works as designed) » Active

I can confirm that bootstrap is currently blowing away any classes or attributes the drop-down-ified menu item had to begin with. The patch provided in #10 didn't seem to apply cleanly for me.

I had success in my project by moving the dropdown logic out of the template and into a template preprocess function, then using css to achieve the dropdown arrow rather than inserting span markup into the link title. I'll try and follow up with a patch here, time permitting.

markhalliwell’s picture

currently blowing away any classes or attributes

I'd be really interested to know where this supposed "blowing away" is happening in this base theme.

It only ever adds custom classes to any existing attributes that were passed in the template:
https://drupal-bootstrap.org/api/bootstrap/templates%21menu%21menu.html....

The only thing this base theme removes is the very specific classes that the template introduced in the first place to account for recursion, but only those classes... it doesn't "blow away" the entire attributes array.

markhalliwell’s picture

Status: Active » Postponed (maintainer needs more info)
chrisolof’s picture

@markcarver What it blows away is not at the <li> level, but at the <a> level - and only for expanded, top-level parents.

      {% if menu_level == 0 and item.is_expanded and item.below %}
        <li{{ item.attributes.addClass(item_classes) }}>
        <a href="{{ item.url }}" class="dropdown-toggle" data-toggle="dropdown">{{ item.title }} <span class="caret"></span></a>
      {% else %}
        <li{{ item.attributes.addClass(item_classes) }}>
        {{ link(item.title, item.url) }}
      {% endif %}

When that if statement evaluates to TRUE, whatever attributes the <a> had going in are lost, because the <a> is defined explicitly to contain only the class="dropdown-toggle" data-toggle="dropdown" attributes.

To reproduce the issue, try adding a top-level, expanded parent menu item with attributes. For example, in a module's links.menu.yml file you could include this:

my_module.parent:
  title: Expanded top-level parent (I'll lose my attributes)
  weight: 0
  route_name: '<none>'
  menu_name: main
  expanded: TRUE
  options:
    attributes:
      data-my-custom-attribute: my_value
      class:
        - some-custom-class
my_module.child:
  title: Child (I get to keep my attributes)
  weight: 0
  route_name: '<none>'
  menu_name: main
  parent: my_module.parent
  options:
    attributes:
      data-my-custom-attribute: my_value
      class:
        - some-custom-class
my_module.standard:
  title: Standard link (I get to keep my attributes too)
  weight: 1
  route_name: '<none>'
  menu_name: main
  options:
    attributes:
      data-my-custom-attribute: my_value
      class:
        - some-custom-class

Render that menu in bootstrap and you'll see what I'm talking about. Interestingly I found that the link attributes are housed in the item's \Drupal\Core\Url object, which {{ link(item.title, item.url) }} is unpacking into the resulting <a>. I hope to provide a patch soon...

chrisolof’s picture

Status: Postponed (maintainer needs more info) » Needs review
StatusFileSize
new1.46 KB

Got it. Patch attached.

kreatil’s picture

I can confirm that patch #15 works, even on the sub-levels. I'm running Drupal 8.5.0 & bootstrap 8.x-3.11. Nice work, @chrisolof

markhalliwell’s picture

Status: Needs review » Needs work
  1. +++ b/templates/menu/menu.html.twig
    @@ -28,11 +28,15 @@
    +          {% set link_attributes = create_attribute(item.url.getOption('attributes')) %}
    ...
    +          {% set link_attributes = create_attribute() %}
    

    This is a no-go. The create_attribute() Twig function wasn't introduced until 8.3.x: https://www.drupal.org/node/2818293. We have no idea how many sites are still using older versions, this would break their sites.

  2. +++ b/templates/menu/menu.html.twig
    @@ -28,11 +28,15 @@
    +        <a href="{{ item.url }}"{{ link_attributes.addClass(['dropdown-toggle']).setAttribute('data-toggle', 'dropdown') }}>{{ item.title }} <span class="caret"></span></a>
    

    Instead of attempting to extract the existing attributes, maybe the manual link used here should also just use the link() Twig function.

biigniick’s picture

i'm also encountering this error. some of it seems fixed with the new 3.12 release. but here is the problem i'm still finding.

in an expanded top level menu item, with children in <ul class="dropdown-menu">, the <li> items in the dropdown-menu don't get any classes if you properly setup menu_link_attributes with container_class config. the class works and is correct, but the container <li> doesn't get any classes.

- nick

baltazarz3’s picture

BiigNiick did you find a way to render the class/es to the <li> elements or this is still an issue? I ran into the same problem. I can render classes for the <a> element but <li> are not displaying and I get null when doing the dump of the container_class.
Thanks

joshuautley’s picture

#15 with Drupal 8.5.6 works for me. Thank you.

Mark, I trust you'll get a better solution together.

markhalliwell’s picture

Title: Incompatibility with D8 Menu Link Attributes module » Add compatibility with D8 Menu Link Attributes module
Version: 8.x-3.x-dev » 8.x-4.x-dev
Category: Bug report » Feature request

Until we can institute a new minimum core requirement (e.g. 8.5.x in the 8.x-4.x branch), this likely won't happen. Also, this is a feature request to support a 3rd-party contrib module, not a bug.

chrisolof’s picture

Being able to manage a link's attributes is well-documented Drupal core functionality and with 8.x-3.x Bootstrap this functionality is broken. The fact that a contrib module that deals in menu link attributes is also broken is a side-effect of this bug. In my project we don't even use that module - we're just trying to use the core API to add some attributes to some of our menu links.

I'm not going to step on Mark's toes here but I'd personally re-title this "Attributes are removed from menu links" and move it back to an 8.x-3.x bug report. I'd bet we could figure out a way to get this working in 8.x-3.x without bumping the D8 core version requirement.

kreatil’s picture

#22: +1

nanobyt3’s picture

StatusFileSize
new1.95 KB

#22 +1, this is the source of the issue and what is causing this, should be fixed.

In the meanwhile, if you need to get container attributes as well, below code should help:

{%
  set item_classes = item.url.getOption('container_attributes').class | split(" ")
%} 
{%
  set item_classes = item_classes | merge([
    item.is_expanded and item.below ? 'expanded dropdown',
    item.in_active_trail ? 'active-trail',
    loop.first ? 'first',
    loop.last ? 'last',
  ])
%}

Attached patch should help.

markhalliwell’s picture

Title: Add compatibility with D8 Menu Link Attributes module » Attributes are removed from menu links
Version: 8.x-4.x-dev » 8.x-3.x-dev
Category: Feature request » Bug report
Status: Needs work » Fixed
StatusFileSize
new4 KB

Ok, I took a look at this and believe I've come up with a semi-solution for 8.x-3.x by preprocessing menus before they're actually sent to the templates. This will allow us to do the necessary merging in PHP while supporting BC versions of core/Twig that don't have the create_attributes function.

  • markcarver committed 3b144f5 on 8.x-3.x
    Issue #2706595 by nanobyt3, markcarver, chrisolof, subbu94: Attributes...
lonalore’s picture

Status: Fixed » Needs review
StatusFileSize
new895 bytes

Hi! With the last commit in this issue we can no longer alter menu links in Bootstrap based themes, and Font Awesome Menu Icons module stopped to work.

Related issue: https://www.drupal.org/project/fontawesome_menu_icons/issues/3014454

I'm attaching a patch to fix this.

markhalliwell’s picture

Status: Needs review » Fixed

Using the link Twig function isn't always going to be viable. That module should use, in addition to hook_link_alter(), hook_preprocess_menu() to iterate over links.

markhalliwell’s picture

Just a heads up...

So it turns out, we do need to use link() after all #3017388: Missing data-drupal-link-system-path from menu links.

My only hesitation with this, originally, was prior implementations proved quite difficult to get this working with the custom caret span added to the title for dropdowns. I wanted to keep the code to a minimum and reduce duplicate code whenever possible. I think I've finally figured it out in that issue though.

Regardless, implementing both hooks in that module is still "Best Practice™" since link() isn't necessarily always used, especially in sub-themes.

Status: Fixed » Closed (fixed)

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

mastermint’s picture

I just used the base template from "menus_attribute" module to override my theme's menues template.
modules/contrib/menus_attribute/templates/menu.html.twig
No patchs, no breaking my head about -pre- or -post- processings...
Works at first.