Split main menu in two blocks

I want to make the main menu of the site, but in such a way that there is a logo in the center and menu items on the left and right.

My idea is this:

ul — logo — ul

So I need to divide the menu into two parts.

{% set half_first = pages.children.visible | slice (0, pages.children.visible | length / 2)%}
{% set half_second = pages.children.visible | slice (pages.children.visible | length / 2)%}

{% for p in half_first %}
   {{ macros.loop(p) }}
{% endfor %}

File macros.html.twig

{% macro loop(page, parent) %}
	{% for p in page.children.visible %}
		<li class="nav-item {% if p.children.visible.count > 0 %}dropdown{% endif %}">
			{% if p.children.visible.count > 0 %}
				<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">
					{{ p.menu }}
				</a>
			{% else %}
				<a class="nav-link" href="{{ p.url }}">
					{{ p.menu }}
				</a>
			{% endif %}

			{% if p.children.visible.count > 0 %}
				<ul class="dropdown-menu">
					{{ _self.loop(p) }}
				</ul>
			{% endif %}
		</li>
	{% endfor %}
{% endmacro %}

Unfortunately it doesn’t work :frowning: Any idea?

@q3d, It would be helpful if you shared what doesn’t work?

  • What result did you expect?
  • What is the actual result?
  • Have you tried to dump variables like {{ dump(variable) }}

I want a page menu but split into two lists.

  1. I expected that if I split something that was used to generate a complete menu, I would get the desired effect :slight_smile: In the example shown, the menu was split but only children were displayed.

  2. Currently, I have a split menu like this

{% set half_first = pages.children.visible|slice(0, pages.children.visible|length / 2) %}
{% set half_second = pages.children.visible|slice(pages.children.visible|length / 2) %}

<ul>
{% for page in half_first %}
    {% set current_page = (page.active or page.activeChild) ? 'current' : '' %}
    <li class="nav-item {{ current_page }}">
    <a class="nav-link" href="{{ page.url }}">
    {{ page.menu }}
    </a>
    </li>
{% endfor %}
</ul>

--- logo ---

<ul>
{% for page in half_second %}
    {% set current_page = (page.active or page.activeChild) ? 'current' : '' %}
    <li class="nav-item {{ current_page }}">
    <a class="nav-link" href="{{ page.url }}">
    {{ page.menu }}
    </a>
    </li>
{% endfor %}
</ul>

and it works but… of course it does not display subpages in the menu (dropdown).

  1. Yes, I’m using {{dump (variable)}} / {{debug (variable)}}

  2. My problem is probably due to not understanding the code from the file: macros.html.twig.

You’re jumping all over the place… In first example you showed you use macro, but only for first half. In second example you don’t use macro, but loop both halves. Use macro to render both halves and see what you get.


Of course it doesn’t, because you loop only top level. Again - use macro.

@q3d, Question and response to request for clarification could have been a tad clearer and informative…

Having said that…

In the example shown, the menu was split but only children were displayed.

That’s because you are slicing pages.children and the macro only displays the children of its input parameter. Hence it only displays the children of the children of pages.

The macro is the way to go, but you need to display the toplevel pages first, by wrapping the navigation macro inside your custom macro.

Your custom macro should use the outer loop from the existing macros.nav_loop().

Using theme Quark and a fresh download of Grav 1.7.33, the following code inside template /user/themes/quark/templates/partials/navigation.html.twig should do want you want:

{% macro topLevel(half) %}
  {% import 'macros/macros.html.twig' as macros %}

  {% for p in half %}
    <ul {{ tree ? 'class="tree"' : '' }}>
      {% set active_page = (p.active or p.activeChild) ? 'active' : '' %}

      <li>
        <a href="{{ p.url }}" class="{{ active_page }}">
          {{ p.menu }}
        </a>

        {% if p.children.visible.count > 0 %}
          <ul>
            {{ macros.nav_loop(p) }}
          </ul>
        {% endif %}

      </li>
    </ul>
  {% endfor %}
{% endmacro %}

{% set halfSize = pages.children.visible|length / 2 %}
{% set leftHalf = pages.children.visible.slice(0, halfSize) %}
{% set rightHalf = pages.children.visible.slice(halfSize) %}

{{ _self.topLevel(leftHalf) }}
--logo--
{{ _self.topLevel(rightHalf) }}

Note:

  • You’ll have to add some css to make the <ul>s and logo display inline.
  • You’ll need to adapt the code to the navigation structure used by your theme.
  • Of course you’ll need a child theme (or custom theme) to prevent the loss of changes to the theme’s files when the theme gets an updated version.

Thank you for your response. Sorry for the form, but I use a translator and try to form simple sentences.

@Karmalakas
I am currently using the code from the second example. I don’t have a dropdown menu for children, but if you don’t like what you like, you like what you have :slight_smile:

@pamtbaau

The code example is the best solution because of my English. I was looking for a template with such a menu, but I did not find it.

The template is my own. So CSS etc is not a problem.

You can take a look at this theme. It uses a menu divided around the logo