2

I have a nav set up which works find but I need to limit the number of top level links to the first 5 in the loop (right now we have 9 plus oodles of children links!). Have tried various flavours of loop.index etc but have run out of ideas.

Here’s my basic nav code:

{% set ppages = craft.entries.section('productPages').level('<=2') %}

<ul id="submenu" class="submenu">
  {% nav page in ppages %}
    <li class=“top-level">
      {{ page.getLink() }}
  {% ifchildren %}
    <ul>
      {% children %}
    </ul>
  {% endifchildren %}
    </li>
  {% endnav %}
</ul>
2

If this is a Craft 2 project, unfortunately there's not a super clean way to do that. You'd have to get the last top-level item in the nav you want to show, and add a bunch of conditions in the code to make sure the entry you're outputting isn't after that 5th entry.

{# get the 5th top-level page #}
{% set fifthElement = craft.entries()
    .section('productPages')
    .level(1)
    .nth(4) %}

{# get all the pages #}
{% set ppages = craft.entries()
    .section('productPages')
    .level('<=2')
    .find() %}

{# now display the nav, but only output HTML for entries that are
   within the first 5 top-level entries #}

<ul id="submenu" class="submenu">
{% nav page in ppages %}
    {% if page.lft < fifthElement.rgt %}
      <li class=“top-level">
        {{ page.getLink() }}
    {% endif %}
  {% ifchildren %}
    {% if page.lft < fifthElement.rgt %}<ul>{% endif %}
    {% children %}
    {% if page.lft < fifthElement.rgt %}</ul>{% endif %}
  {% endifchildren %}
    {% if page.lft < fifthElement.rgt %}
      </li>
    {% endif %}
  {% endnav %}
</ul>

In Craft 3 it would be quite a bit simpler, though, as you have the power to modify the element query however you want. So we can first get the 5th top-level entry’s rgt value, and then when running our main ppages query, only get the ones whose lft value is less than that 5th entry’s rgt value.

{# get the 5th top-level page #}
{% set fifthElement = craft.entries()
    .section('productPages')
    .level(1)
    .nth(4) %}

{# get all the pages that are within the first 5 top-level pages #}
{% set ppages = craft.entries()
    .section('productPages')
    .level('<=2')
    .andWhere(['<', 'lft', fifthElement.rgt])
    .all() %}

{# now output the navigation normally #}

<ul id="submenu" class="submenu">
  {% nav page in ppages %}
    <li class=“top-level">
      {{ page.getLink() }}
  {% ifchildren %}
    <ul>
      {% children %}
    </ul>
  {% endifchildren %}
    </li>
  {% endnav %}
</ul>

If you’re unfamiliar with these lft and rgt values, they are attributes of structured entries, which define their position within the structure, using the “Nested Set” model. The easiest way to think of it is, your structure section is like an XML file, and each of the entries are nodes within it. Each entry has a opening tag and a closing tag on different lines, and lft and rgt are those line numbers.

1 <top_entry>
2   <nested_entry>
3   </nested_entry>
4 </top_entry>

So when we do {% if page.lft < fifthElement.rgt %}, we are saying “make sure that this node’s ‘opening tag’ comes before the fifth element’s ‘closing tag’”.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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