Skip to content

Instantly share code, notes, and snippets.

@mildlygeeky
Last active January 3, 2019 11:43
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mildlygeeky/14b814ec8c815a1f5c6f to your computer and use it in GitHub Desktop.
Save mildlygeeky/14b814ec8c815a1f5c6f to your computer and use it in GitHub Desktop.
Dynamic Navigation using native Craft CMS and Twig templates
{# For this, I wanted the nav to show the top-level node and second-level nodes #}
{# when on level 1, and then show the second-level and its children when on #}
{# level 2 or level 3 (so we get good parent, child, and sibling navigation. #}
{# Requires string 'sectionName' to be passed with Structure section name #}
{% if entry.showLeftNavigation %}
<nav class="interior-page__nav">
{# Need to manually step through our entries and apply some logic to see if #}
{# they should show in our our dynamic nav, based on how far down in the #}
{# structure we are. Start out by initializing an empty array. #}
{% set pages = [] %}
{# For everything in our structure section #}
{% for page in craft.entries.section(sectionName) %}
{# If it is one of our "top-level" pages (we are going to manually bring #}
{# in an overview page for our level 1 page #}
{% if (page.level == 2) %}
{# Automatically add it to the array #}
{% set pages = pages|merge([page]) %}
{% endif %}
{# If it is a deep page, and (is the current page, or is a sibling of the #}
{# page common second-level parent, or is a child of this page) #}
{% if (
( page.level == 3 ) and (
( page.id == entry.id ) or
( page.isSiblingOf(entry) ) or
( page.isDescendantOf(entry) and ( entry.level != 1 ) )
)
)%}
{% set pages = pages|merge([page]) %}
{% endif %}
{% endfor %}
{% set aboutPage = entry.ancestors|length ? entry.ancestors[0] : entry %}
<ul>
{% nav page in pages %}
{# Long story, but even though "About" is a level 1, I wanted it to look #}
{# to be on the same level as its child pages #}
{% if loop.first and sectionName == 'aboutSection' %}
<li {{ aboutPage.id == entry.id ? 'class="here"' : '' }}><a href="{{ aboutPage.getUrl() }}">{{ aboutPage.title }}</a></li>
{% endif %}
<li class="{{- loop.first ? ' first' : '' }}{{- entry.id == page.id ? ' here' : '' }}{{- loop.last ? ' last' : '' }}" >
{{ page.getLink() }}
{% ifchildren %}
<ul>
{% children %}
</ul>
{% endifchildren %}
</li>
{% endnav %}
</ul>
</nav>
{% endif %}
@mildlygeeky
Copy link
Author

For anyone who may be looking at this, my structure section looked like this:

- A
  - A.1
    - A.1.1
    - A.1.2
    - A.1.3
  - A.2
    - A.2.1
    - A.2.2

But I didn't want all of that spit out into my side nav — I wanted "A" to appear to be at the same level as A.1 and A.2 (think an "Overview" page in EE Structure Nav or Navee), but also show children of only A1 when on A1, and show siblings when on A.1.1. So, for example, if I was on A.1 or A.1.1, I wanted the frontend ULs and LIs to look like this:

- A
- A.1
  - A.1.1
  - A.1.2
  - A.1.3
- A.2

I spent way too much time trying to hack around with if's in my nav tag until I realized that it was futile — the ifchildren function can't be messed with. That's when I realized that the nav tag was way smarter than the example code on buildwithcraft.com leads you to believe — if you feed it an array of just the pages you want, it is smart enough to figure out any nav you can come up with the logic for.

Definitely very rewarding once I got it working the way I wanted to, and gave me new respect for the guys who build out-of-the-box nav plugins (though with code like above, they are less needed, though still faster to implement).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment