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