1

I have a navbar built out based on a pages section (structure) that has a field hideFromNav that when set to on hides the item from the nav bar - this is on line 8 of the code below.

This works fine for first and secondary levels, but once there is a tertiary entry,with hideFromNav turned on, the if children conditionals are activated making the parent unclickable and the child doesn't display (as expected) but the parent being unclickable is wrong. If the tertiary item is visible to the menu, i.e hideFromNav is set to 0, then everything works fine and that item displays.

The screenshot shows where the hidden item is triggering the dropdown at the tertiary level

enter image description here

What do I need to do to fix this issue?

{# main nav #}
<nav
  class="flex-col hidden pb-4 lg:w-full lg:flex-grow h-screen123 lg:pb-0 lg:flex lg:justify-end lg:flex-row lg:h-auto"
  aria-label="Main Navigation"
  :class="{'flex': open, 'hidden': !open}">
  <ul class="flex flex-col flex-wrap pl-0 m-0 lg:items-center lg:flex-row">

    {% set pages = craft.entries.section('pages').hideFromNav('0').level('<='~4).all() %}

    {% nav entry in pages %}
      <li class="group relative font-proxima font-semibold
        {# conditionally add classes to either top level entries or child entries #}
        {{ entry.level =='1' ? 'block lg:px-0 xl:px-0 mr-1 py-2':'border-b border-white border-opacity-[0.2]' }}"

        {# if entry has children make it a dropdown/flyout #}
        {{ entry.hasDescendants ? 'x-data="{isOpen:false }"  @mouseleave="isOpen = false"':'' }}>

        <a href="{{ entry.hasDescendants ? '#' : entry.url }}"
          class="text-grayBrand-dark text-18
            {% if entry.isButton %}
              btn btn-nav inline-block
            {% elseif entry.level == '1' %}
              py-1 px-2 group-hover:text-greenBrand
            {% else %}
              text-grayBrand-dark bg-transparent hover:text-grayBrand lg:text-sm
            {% endif %}"

          {% if entry.hasDescendants %}
            @click="isOpen = !isOpen"
            x-on:click.prevent
            :class="{'' : isOpen}"
          {% endif %}>

            {{ entry.title }}
            {% if entry.hasDescendants %}
              {{ svg('@webroot/assets/images/svg/down-chevron.svg')|attr({
                class:'w-6 h-6 inline-block fill-current'
              }) }}
            {% endif %}
        </a>

        {# display all child entries #}
        {% ifchildren %}

          {#
            if has children and is not a top level entry
            then add a left chevron
          #}
          {% if entry.level !="1" %}
            <svg xmlns="http://www.w3.org/2000/svg" fill="white" width="16" height="16" class="hidden lg:inline-block fill-white absolute top-[10px] right-0" viewBox="0 0 16 16">
              <path fill-rule="evenodd" d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"/>
            </svg>
          {% endif %}

          {# wrap children with ul and display them #}
          <ul
            class="p-2 bg-grayBrand-light"
            aria-label="submenu"
              x-show="isOpen"
              x-cloak
              @click.away="isOpen = false">

              {# display parent entry again
                since it's not reachable by click
              #}
              <li class="group relative border-b border-white border-opacity-[0.2] font-proxima font-semi-bold">
                <a href="{{ entry.url }}" class="py-2 bg-transparent text-grayBrand-dark hover:text-grayBrand lg:text-sm">{{ entry.title }}</a>
              </li><!-- /.p-3 bg-green-200 -->
              {# end show parent entry #}

            {% children %}
          </ul>
        {% endifchildren %}
        {# end children #}

      </li>
    {% endnav %}

  </ul>
</nav>

1 Answer 1

3

The issue is that the way you check whether the current entry has children is inconsistent. You're using the {% ifchildren %} tag, which will only check if the entry has children in the pages array, which it doesn't if all children are hidden from the navigation. However, everywhere else you're checking entry.hasDescendants. That's a property of the element class and doesn't know about the {% nav %} tag or the pages array – it only tells you whether the current element has any children in the database, which it does even if all of them are hidden from the navigation.

What you want to check is whether the element has children within the array, i.e. what the {% ifchildren %} tag does. However, you can only use one {% ifchildren %} tag within the {% nav %} tag. To replicate the child checking logic, you need to check if the pages array includes any children of the current element. For example:

{% set hasChildren = pages has some el => el.parentId == item.id %}

Then use hasChildren everywhere instead of element.hasDescendants.


Because of issues like this, I never use the {% nav %} tag. A recursive macro does the same thing, but is way more flexible when it comes to special display logic.


Note for Twig versions <3.5.0

The has some operator was added in Twig 3.5.0 and is not available in Twig 2.x. For older versions, this snippet is equivalent to the one above:

{% set hasChildren = pages|filter(el => el.parentId == item.id) is not empty %}
4
  • {% set hasChildren = pages has some el => el.parentId == item.id %} not sure how to use this. I get errors about unexpcted token name of value has. also tried changing el to entry
    – CreateSean
    Commented Mar 20, 2023 at 16:46
  • @CreateSean The has some Operator was added in Twig 3.5.0, you're probably using an older version of Twig. I recommend you update to the latest version, but I've added a code example that will work on older Twig versions as well.
    – MoritzLost
    Commented Mar 20, 2023 at 16:51
  • the new code works perfectly. I checked my twig version and it is below 3.5 - it's set by Craft afaik.
    – CreateSean
    Commented Mar 20, 2023 at 17:01
  • @CreateSean You're right, Craft actually requires Twig 3.4.x at the moment, I didn't think it locked the minor version. Good to know. Hopefully they update it soon.
    – MoritzLost
    Commented Mar 21, 2023 at 8:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.