This will not generate the child elements. It will yield the same results as the code from the original question (the code is basically the same with one extra condition added which does not affect the output). Here is the code from the original question:
{% set menu = menu(module.menu) %}
{% for item in menu.children %}
<li class="{{ item.label|lower|replace(' ', '-') }}">
<a href="{{ item.url }}">{{ item.label }}</a>
</li>
{% endfor %}
However, after exploring the output of menu fuction, here is the working solution with macro included:
{% macro generateMenuMarkup(menuId) %}
{% set menu = menu(menuId) %}
{% for child in menu.children %}
<h2>{{child.label}}</h2>
<ul>
{% for node in child.children %}
<li>{{node.label}}</li>
{% endfor %}
</ul>
{% endfor %}
{% endmacro %}
Calling this macro is simple as {{ generateMenuMarkup(module.menu) }}
This way, you have complete control over markup regarding menus. One additional benefit is that you can use hubl tokens directly in your menu and they will be properly rendered in your hubl markup which is not the case when you include menu directly with hubl snippet:
{% menu id="{{ module.user_logged_in_menu }}" %}
Example:
When using macro and menu() function the content.absolute_url value (https://www.somelink.com) will be rendered. When using hubl menu snippet, {{ content.absolute_url }} will be rendered as a simple string and value will not be inserted.
NOTE: This code will work for menus which are 1 level deep. For deeper menus more for loops will be needed.
This will not generate the child elements. It will yield the same results as the code from the original question (the code is basically the same with one extra condition added which does not affect the output). Here is the code from the original question:
{% set menu = menu(module.menu) %}
{% for item in menu.children %}
<li class="{{ item.label|lower|replace(' ', '-') }}">
<a href="{{ item.url }}">{{ item.label }}</a>
</li>
{% endfor %}
However, after exploring the output of menu fuction, here is the working solution with macro included:
{% macro generateMenuMarkup(menuId) %}
{% set menu = menu(menuId) %}
{% for child in menu.children %}
<h2>{{child.label}}</h2>
<ul>
{% for node in child.children %}
<li>{{node.label}}</li>
{% endfor %}
</ul>
{% endfor %}
{% endmacro %}
Calling this macro is simple as {{ generateMenuMarkup(module.menu) }}
This way, you have complete control over markup regarding menus. One additional benefit is that you can use hubl tokens directly in your menu and they will be properly rendered in your hubl markup which is not the case when you include menu directly with hubl snippet:
{% menu id="{{ module.user_logged_in_menu }}" %}
Example:
When using macro and menu() function the content.absolute_url value (https://www.somelink.com) will be rendered. When using hubl menu snippet, {{ content.absolute_url }} will be rendered as a simple string and value will not be inserted.
NOTE: This code will work for menus which are 1 level deep. For deeper menus more for loops will be needed.
you don't need a for loop to display the menu if you're using this hubl code.
Simply paste it in your module/template and leave the id blank. When building a page you can select the desired menu. HubSpot will automaticly translate the hubl into the right menu structure.
Tipp: The ID is a bit hidden but can be found after selecting the menu once and previewing the page. When you inspect the sourcecode of the page/menu you should see this line(s):
The "data-menu-id" is your menu ID. So after you found it you can go back to your module/template and paste it in. By doing this you won't need to select the menu everytime you're building a page.
It's not just the span I want to remove, it's the unncessary classes and data attributes that come alongside this appoach too. Whilst your approach does the job, I'm looking to be in complete control of the markup that is generated within my list items.
Are you suggesting there is no way for me achieve this with the partial approach HubSpot have defined here?
But if you want to completly modify it and have complete control over your menu try this:
Write your own menu Module
It's easier than it sounds.
Here's my code:
{# Config #}
{% for item in module.single_nav_entry %}{% set href = item.menu_url.url.href %}
{% if item.menu_url.url.type is equalto "EMAIL_ADDRESS" %}
{% set href = "mailto:" + href %}
{% endif %}
{% endfor %}
{# Code #}
<ul>
{% for item in single_nav_entry %}
{% if item.child %}
<li>
<ul>
<li class="{{item.custom_class}}"><a href="{{ href }}"{% if item.menu_url.open_in_new_tab %}target="_blank"{% endif %}{% if item.menu_url.no_follow %}rel="nofollow"{% endif %}>{{ item.menu_name }}</a></li>
</ul>
</li>
{% else %}
<li class="{{item.custom_class}}"><a href="{{ href }}"{% if item.menu_url.open_in_new_tab %}target="_blank"{% endif %}{% if item.menu_url.no_follow %}rel="nofollow"{% endif %}>{{ item.menu_name }}</a></li>
{% endif %}
{% endfor %}
</ul>
and here some screens of the module functions/widgets:
module widgetsgroup settings
If you want to use it as a global element don't forget to select "global module" when creating the module. If you want to use the module in a global group you don't need to do this.