1

A bit of a background on the project. I have a features structure section, that has 2 levels: Parent features & Child features.

{% set features = craft.entries.section('features').all() %}

My goal is to get an active class on the parent if the parent page is active or if it's got a child that is active and also get an active class on the child if its active.

The {% children %} tag doesn't allow for custom HTML.

I am looking to get something similar to this left navigation. But instead of anchors, each feature will be its own page. https://craftcms.com/features/all#section-types

Thanks

mateostabio
  • 526
  • 4
  • 16

2 Answers2

3

After a long search and lots of trial and error, I've found the perfect solution! This is how I created a dynamic structure navigation : parent/child (2 levels deep) with class="active" on the parent and the child <li>.

<ul class="Navigation">

{# Get top-level entries in structure section 'features' #}
{% set parentFeatures = craft.entries.section('features').level(1) %}

{# Loop through top-level entries #}
{% for parentFeature in parentFeatures %}

    {# Check if entry has descendants/children #}
    {% if not parentFeature.hasDescendants %}

        {# List navigation item if entry has NO child entries #}
        <li class="Navigation-item {% if craft.app.request.absoluteUrl == parentFeature.url %}active{% endif %}">
            <a href="{{ parentFeature.getUrl }}" class="Navigation-link">{{ parentFeature.title }}</a>
        </li>

    {% else %}

        {# List navigation item if entry does have child entries #}
        {# Show an active class if it is active or if it contains a child that is active #}
        <li class="Navigation-item Navigation-item--dropdown {% if parentFeature.slug == craft.request.getSegment(parentFeature.level) %}active{% endif %}">

            <a href="{{ parentFeature.getUrl }}" class="Navigation-link">{{ parentFeature.title }}</a>
            <ul class="Navigation Navigation--subMenu">

                {# Get child entries of current iteration's top-level entry #}
                {% set subPages = parentFeature.getChildren() %}

                {# Loop through those 2nd-level entries #}
                {% for subPage in subPages %}

                    {# This is the place where you'd nest the next menu hierarchy !! #}

                    {# List sub-menu navigation item #}
                    <li class="Navigation-item Navigation-item--subMenu {% if craft.app.request.absoluteUrl == subPage.url %}active{% endif %}">
                        <a href="{{ subPage.getUrl }}" class="Navigation-link Navigation-link--subMenu">{{ subPage.title }}</a>
                    </li>

                {% endfor %}

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

</ul>

Thanks to Carlcs's old answer about this found here: https://craftcms.stackexchange.com/a/1847/6586

mateostabio
  • 526
  • 4
  • 16
  • This is interesting. Is this code designed to hide the subnav unless the parent item has child pages? Example: if a parent page with no children is active, will the child pages of another show even though that page is not active? – Adam Dec 17 '18 at 23:24
  • @Adam, It is exactly that. I wanted to be able to control everything with CSS. Now I have a way to show the parent/children of whatever page is active. Remember this is a side navigation so I wanted to be able to let the user expand and collapse navigation, similar to the craftcms.com/features/all And yes, the first if statement checks to see if it has children, and if it does not, it doesn't put class .Navigation-item--dropdown on the parent
  • and doesn't put a
      submenu in it.
  • – mateostabio Dec 18 '18 at 15:20
  • 1
    Very nice. I need something similar with Craft 4, and your example really helped. Thank you! – Dario Zadro Feb 29 '24 at 16:29