Drupal add extra fields to menu - drupal

I have some issue with drupal 9 and the menu. Basically i want to add some extra fields for menu link, like icon (image or svg upload) and some text for description. I use Simplify menu for the menus.
I already tried with Menu item extras module but i can't print the added fields in twig file.
Someone know how to fix this and get the fields value in twig template? (menu.html.twig)?
Thanks

You can print it in *.html.twig file, the below code I rendered the main menu like:
{% set items = simplify_menu('main') %}
{{ menu_item.NEW_FIELD }}
<nav class="nav">
<ul class="navbar-ul">
{% for menu_item in items.menu_tree %}
<li class="nav-item">
<a class="nav-link" href="{{ menu_item.url }}">{{ menu_item.text }}</a>
</li>
{% endfor %}
</ul>
</nav>

Related

How to display the class for the active menu?

Here is the menu.twig.html template provided by Drupal Bootstrap :
{#
/**
* #file
* Default theme implementation to display a menu.
*
* Available variables:
* - classes: A list of classes to apply to the top level <ul> element.
* - dropdown_classes: A list of classes to apply to the dropdown <ul> element.
* - menu_name: The machine name of the menu.
* - items: A nested list of menu items. Each menu item contains:
* - attributes: HTML attributes for the menu item.
* - below: The menu item child items.
* - title: The menu link title.
* - url: The menu link url, instance of \Drupal\Core\Url
* - localized_options: Menu link localized options.
*
* #ingroup templates
*
* Define a custom macro that will render all menu trees.
*/
#}
{% macro menu_links(items, attributes, menu_level, classes, dropdown_classes) %}
{% if items %}
<ul{{ attributes.addClass(menu_level == 0 ? classes : dropdown_classes) }}>
{% for item in items %}
{%
set item_classes = item.url.getOption('container_attributes').class | split(" ")
%}
{%
set item_classes = [
item.is_expanded and item.below ? 'expanded dropdown',
item.in_active_trail ? 'active active-trail',
loop.first ? 'first',
loop.last ? 'last',
]
%}
<li{{ item.attributes.addClass(item_classes) }}>
{% set link_title = item.title %}
{% set link_attributes = item.link_attributes %}
{% if menu_level == 0 and item.is_expanded and item.below %}
{% set link_title %}{{ link_title }} <span class="caret"></span>{% endset %}
{% set link_attributes = link_attributes.addClass('dropdown-toggle').setAttribute('data-toggle', 'dropdown') %}
{% endif %}
{# Must use link() here so it triggers hook_link_alter(). #}
{{ link(link_title, item.url, link_attributes.addClass(item.in_active_trail ? 'active-trail')) }}
{% if item.below %}
{{ _self.menu_links(item.below, attributes.removeClass(classes), menu_level + 1, classes, dropdown_classes) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{#
Invoke the custom macro defined above. If classes were provided, use them.
This allows the template to be extended without having to also duplicate the
code above. #see http://twig.sensiolabs.org/doc/tags/macro.html
#}
{{ _self.menu_links(items, attributes, 0, classes ?: ['menu', 'menu--' ~ menu_name|clean_class, 'nav'], dropdown_classes ?: ['dropdown-menu']) }}
Here is the main menu HTML code :
<ul class="menu menu--main nav navbar-nav">
<li class="first">
Banques
</li>
<li>
Cashback
</li>
<li class="active active-trail">
Avis
</li>
<li>
Essentiel
</li>
<li class="last">
Actu
</li>
</ul>
I want to customize this menu and add an icon before each menu link and the number of page elements in a badge.
Here is the custom code I want for my main menu :
<ul class="menu menu--main nav navbar-nav">
<li>
<i class="fas fa-piggy-bank fa-lg"></i> Banques <span class="badge badge-light">{{ drupal_view_result('accueil_banque', 'page_1')|length }}</span>
</li>
<li>
<i class="fas fa-undo fa-lg"></i> Cashback <span class="badge badge-light">{{ drupal_view_result('accueil_cashback', 'page_1')|length }}</span>
</li>
<li>
<i class="fas fa-gift fa-lg"></i> Avis <span class="badge badge-light">{{ drupal_view_result('accueil_avis', 'page_1')|length }}</span>
</li>
<li>
<i class="fas fa-thumbs-up fa-lg"></i> Essentiel <span class="badge badge-light">{{ drupal_view_result('accueil_essentiel', 'page_1')|length }}</span>
</li>
<li>
<i class="fas fa-newspaper fa-lg"></i> Actu <span class="badge badge-light">{{ drupal_view_result('accueil_actu', 'page_1')|length }}</span>
</li>
</ul>
The problem is that when I click on a menu link, the menu is not displayed as active.
How can I have the same behavior in my custom code ? With the active class automatically added to the menu link that is currently displayed.
How else can I integrate my custom code into one of the menu.html.twig or menu--main.html.twig templates ?
In Bootstrap there is a menu--main.html.twig template that I copy to my sub-theme, but I don't know how to use it. Here are its contents :
{#
/**
* #file
* Default theme implementation to display a menu.
*
* Available variables:
* - classes: A list of classes to apply to the top level <ul> element.
* - dropdown_classes: A list of classes to apply to the dropdown <ul> element.
* - menu_name: The machine name of the menu.
* - items: A nested list of menu items. Each menu item contains:
* - attributes: HTML attributes for the menu item.
* - below: The menu item child items.
* - title: The menu link title.
* - url: The menu link url, instance of \Drupal\Core\Url
* - localized_options: Menu link localized options.
*
* #ingroup templates
*/
#}
{% extends "menu.html.twig" %}
{%
set classes = [
'menu',
'menu--' ~ menu_name|clean_class,
'nav',
'navbar-nav',
]
%}
Example of the main menu by default with an open link (it is active because the page is displayed) :
Example of the main menu personalized with an open link (it is not active, because the classes are not automatically added by the template menu.twig.html) :
The answer they gave you in the referenced issue is a very clear one RTFM (Read the f***ing manual) especially the following:
core/themes/stable/templates/menu.html.twig
core/themes/classy/templates/menu.html.twig contains {% extends "menu.html.twig" %} (to add a specific class) and expects Stable's menu.html.twig to be extended
core/themes/YOUR_DIR/templates/menu.html.twig contains {% extends "menu.html.twig" %} (to override a Twig block) and expects Classy's menu.html.twig to be extended — or, really, any of its ancestor themes, because it couldn't care less if Classy's menu.html.twig was removed
Notes:
in point 3, we specifically do NOT want to specify {% extends "#classy/menu.html.twig" %} because we don't want to care. We just want the parent theme's template — according to the theme registry — to be extended.
in point 1, the "root template" could just as well not live in a theme, but in a module. That's also a valid use case.
So you have an issue because you state menu.twig.html but your module extends "menu.html.twig" so make sure your naming is right.
The Drupal handbook statesNEVER to fiddle around with the delivered templates, rather extend it with user specific modulues.
Q: Where should I make changes?
A: In a custom sub-theme
You should never modify any theme or sub-theme that is packaged and
released from Drupal.org. If you do, all changes you have made would
be lost once that theme is updated. This makes keeping track of
changes next to impossible.
Instead, you should create a custom sub-theme that isn't hosted on
Drupal.org.

How to interpolate a variable in a twig loop to render a file?

I am looping through a list of social profiles to render the logo. Each social item has a field of svg_icon_code that looks like "twitter" or "facebook". I want to use this code to render the correct file. Currently I am just hardcoding in "twitter" resulting in all logos being the Twitter svg. How can I use the icon_code to render the correct svg?
{% for item in options.social_media_links %}
<li class="header__social-media-links__item">
<a href="{{item.link}}" target="_blank">
{% include 'component/svg-twitter-icon.twig' %}
</a>
</li>
{% endfor %}
You need to concat the icon like this,
{% for item in options.social_media_links %}
<li class="header__social-media-links__item">
<a href="{{item.link}}" target="_blank">
{% include 'component/svg-'~item.svg_icon_code~'-icon.twig' %}
</a>
</li>
{% endfor %}
If an icon doesn't have a template or the template is missing you can do this to render a default icon
{% for item in options.social_media_links %}
<li class="header__social-media-links__item">
<a href="{{item.link}}" target="_blank">
{% include [ 'component/svg-'~item.svg_icon_code~'-icon.twig', 'component/svg-default-icon.twig' ] %}
</a>
</li>
{% endfor %}

Drupal 8 remove extra divs and add custom classes in menu

Currently the {{page.primary_menu}} created the extra divs and default d8 classes as below:
<div class="region region-primary-menu">
<nav role="navigation" aria-labelledby="block-demo-main-menu-menu" id="block-demo-main-menu">
<h2 class="sr-only" id="block-demo-main-menu-menu">Main navigation</h2>
<ul class="menu menu--main nav navbar-nav">
<li class="first">
Home
</li>
<li>
Home
</li>
<li class="last">
ABOUT US
</li>
</ul>
</nav>
</div>
However, I want to generate the menu structure as like:
<ul id="top-menu" class="nav navbar-nav navbar-right mu-main-nav">
<li>HOME</li>
<li>ABOUT US</li>
<li>MENU</li>
<li>RESERVATION</li>
<li>GALLERY</li>
<li>OUR TEAM</li>
<li>BLOG</li>
<li>CONTACT</li>
</ul>
I've created a file name demo.theme and pasted the code but it did not give me the expected result.
<?php
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Template\Attribute;
/**
* Implements hook_preprocess_HOOK() for HTML document templates.
*
* Adds body classes if certain regions have content.
*/
function demo_menu_tree(&$variables) {
return '<ul id="top-menu" class="nav navbar-nav navbar-right mu-main-nav">' . $variables['tree'] . '</ul>';
}
Any suggestion?
Make sure you have twig debugging enabled, it will make your life a lot easier, by adding comments to your mark up (which you can see inline in the web inspector). Using those comments you can figure out what you should name your theme file.
Create a new custom twig file in the /templates directory of your theme like so themes/[your-theme-name-here]/templates/menu.html.twig. As a starting point I'd suggest either using the default classy theme menu.html.twig template, or clone use the file referenced inline in the markup comments of your site when you have twig debugging enabled.
Edit the menu.html.twig file to meet your needs, something like this:
{% 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 id="top-menu" {{ attributes.addClass('nav navbar-nav navbar-right mu-main-nav') }}>
{% else %}
<ul class="menu">
{% endif %}
{% for item in items %}
{%
set classes = [
'menu-item',
item.is_expanded ? 'menu-item--expanded',
item.is_collapsed ? 'menu-item--collapsed',
item.in_active_trail ? 'menu-item--active-trail',
]
%}
<li{{ item.attributes.addClass(classes) }}>
{{ link(item.title, item.url) }}
{% if item.below %}
{{ menus.menu_links(item.below, attributes, menu_level + 1) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}

(Sub)-categories affix stacked sidebar in Bootstrap

I am trying to implement a navbar affix in Symfony2 with Bootstrap, but I have not managed to find any useful resources so far.
What I would like to do is having some Categories and SubCategories and when the user clicks on a Category, then the available SubCategories are popping up.
Initial state example:
+Category 1
+Category 2
+Category 3
+Category 4
After clicking on Category 1 link example:
+Category 1
-SubCategory 1
-SubCategory 2
-SubCategory 3
+Category 2
+Category 3
+Category 4
What I have so far is:
<div role="tabpanel" class="tab-pane" id="profile">
<div id="affix-nav" class="affix sidebar col-sm-3">
<ul class="nav sidenav" data-spy="affix">
{% for cat in categories %}
{% include 'ToolBundle:Default:sidebar_bit.html.twig' %}
{% endfor %}
</ul>
</div>
</div>
...and that is sidebar_bit.html.twig
<li>
{{ cat.getDefaultName }}
{% if no_subs is not defined %}
<ul class="nav">
{% for cat in cat.getChildren %}
{% include 'ToolBundle:Default:sidebar_bit.html.twig' with {'no_subs': true} %}
{% endfor %}
</ul>
{% endif %}
</li>
Thanks alot in advance and do not hesitate for additional info if is required.
UPDATE
Here is the jsfiddle: https://jsfiddle.net/0uwegh6k/2/
the fiddle example is messed up, but it looks like you have to add some js to make it work or you can use the boostrap 3 toggle link is here
How it works is like data-toggle="collapse" on the trigger and target it using href="collapseExample" or data-target="#collapseExample" as shown in the link above
<ul>
<li>
<a href="collapseExample" data-toggle="collapse" >Europe</a>
<ul class="nav" id="collapseExample">
<li>
England
</li>
<li>
Spain
</li>
</ul>
</li>
<ul>

Rendering different controller view in sitelayout in symfony 2

I have a layout which has a sidebar. Inside sidebar, there is a block for displaying list of categories. I have called a controller (fetches list of categories) to be rendered inside this block. Here is how my sidebar looks like:
Here is my main layout file containing sidebar:
<!-- siteLayout.html.twig -->
<div id="sidebar">
{% block sidebarBlock1 %}
{% render "TestBundle:Index:categoryList" %}
{% endblock %}
</div>
TestBundle:Index:categoryList fetches list of categories from database and returns as below:
<ul>
<li>Category 1</li>
<li>Category 2</li>
</ul>
All my other views extends siteLayout.html.twig. What i want is that when users loads this url "/category/1" i want to add css class to li tag.
For example if someone clicks /category/1 then the output should be
<li class="active">.......</li>
How can I achieve this?
<li {% if app.request.attributes.get('_route') == 'category_view' %}
class="active"
{% endif %}>
</li>
Check route and set class if route matches your category route. Replace category_view with the route name of /category
{%if app.request.server.get('REQUEST_URI')== path('viewCategoryItems', {'slugName': category.slugName})%} class="active"{%endif%}
This worked for me

Resources