Skip to main content
added 2 characters in body
Source Link
duru
  • 599
  • 7
  • 17

But there should be a more "Drupal way" of doing it. In Drupal 7, AFAIR, I could set the whole html of a menu item. But as you can see in the following kint()kint() output, I couldn't find room to do that.

But there should be a more "Drupal way" of doing it. In Drupal 7, AFAIR, I could set the whole html of a menu item. But as you can see in the following kint() output, I couldn't find room to do that.

But there should be a more "Drupal way" of doing it. In Drupal 7, AFAIR, I could set the whole html of a menu item. But as you can see in the following kint() output, I couldn't find room to do that.

Source Link
duru
  • 599
  • 7
  • 17

Insert custom html into menu

I am trying to insert the languageswitcher block and login block into the menu. So basically I am after inserting custom html into menu or change the html of a menu link.

Looks like the best place to do this is hook_preprocess_menu(). A dirty workaround is adding it under a desired menu item by finding that item with a condition check.

But there should be a more "Drupal way" of doing it. In Drupal 7, AFAIR, I could set the whole html of a menu item. But as you can see in the following kint() output, I couldn't find room to do that.

enter image description here

Here is my workaround:

function mytheme_preprocess_menu(&$variables) {
  if (isset($variables['menu_name']) && $variables['menu_name'] == 'main') {
    foreach ($variables['items'] as &$item) {
      $attributes = $item['url']->getOption('attributes');
      if (isset($attributes['class']) && in_array('locale', $attributes['class'])) {
        if ($block = \Drupal\block\Entity\Block::load('languageswitcher')) {
          $copy = $item;
          $item['is_expanded'] = true;
          $copy['locale'] = \Drupal::entityTypeManager()
            ->getViewBuilder('block')
            ->view($block);
          $item['below'][] = $copy;
        }
      }
    }
  }
}

The condition I check here is a class I added with the menu_link_attributes module.

Then I print it in menu--main.html.twig. I am using a Bootsrap submenu and putting here the whole code for reference:

{% import _self as menus %}

{#
  We call a macro which calls itself to render the full tree.
  @see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ menus.menu_links(items, attributes, 0) }}

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

So the actual question is, what is the Drupal way of doing this?