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

2 Answers 2

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

3
  • 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
    Commented Dec 17, 2018 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 <li> and doesn't put a <ul> submenu in it. Commented Dec 18, 2018 at 15:20
  • 1
    Very nice. I need something similar with Craft 4, and your example really helped. Thank you! Commented Feb 29 at 16:29
0

There is a plugin that might be doing what you are looking for. You start with building your navigation and put that into a variable. Then you run this through a TwigExtension provided by the plugin "k4navigationCraft3":

{% set mainnavigation %}
    {% cache globally using key "main-navigation" %}
    {% set entries = craft.entries.section('features').all() %}

    <ul>
        {% nav entry in entries %}
            <li>
                <a href="{{ entry.url }}">{{ entry.title }}</a>
                {% ifchildren %}
                    <ul>
                        {% children %}
                    </ul>
                {% endifchildren %}
            </li>
        {% endnav %}
    </ul>

    {% endcache %}
{% endset %}

Then you can use one of the plugins TwigExtensions to do:

{{ mainnavigation | k4NavigationGetActivePath(url(craft.app.request.pathInfo)) | raw }}

The plugin is named "k4navigationCraft3" and can be found on Bitbucket

1
  • Thanks for the answer, but I'm looking for a way to do this without a plugin and without using {% children %} if possible. Commented Dec 17, 2018 at 16:58

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.