I have a structure which controls my main site navigation. It's the same across the site so it is best to cache globally as opposed to a cache of the navigation or every url.

The last answer on this pages says that you can use Twig's replace filter to achieve this: Would you use a Structure as navigation over multiple sections (channel entries, indexes and singles)?

My code below shows the active class being placed on the li tag but that doesn't work with the cache globally.

Can it be done with Twig's replace filter?

{% cache globally for 3 years %}
  {% set entries = craft.entries.section('navigation') %}

  <ul class="right">
    {% nav entry in entries %}
    <li class="{{ entry.hasDescendants() ? 'has-dropdown' : "" }}{{ craft.request.segment(1) == entry.slug ? ' active' : "" }}">
      {# Check for entry type / get related entry #}
      {% if entry.type == 'customLink' %}
        {# Link to a custom url #}
        <a href="{{ entry.customUrl }}">{{ entry.title }}</a>
      {% elseif entry.type == 'relatedEntryLink' %}
        {% set linkedEntry = entry.relatedEntry.limit(1).first() %}
        <a href="{{ linkedEntry.url }}">{{ entry.title }}</a>
      {% else %}
        {# Link to a structure entry #}
        <a href="{{ entry.url }}">{{ entry.title }}</a>
      {% endif %}
      {# Repeat this for child entries #}
      {% ifchildren %}
      <ul class="dropdown">{% children %}</ul>
      {% endifchildren %}
    {% endnav %}
{% endcache %} 

1 Answer 1


Yes, you can!

The first thing you need to do is to add the entire cached content into a single variable:

{% set navigation %}
    {% cache globally for 3 years %}
    {% endcache %}
{% endset %}

Then you need to add some dummy placeholder tags on your <li> tag and your <a> tag which then can be used by |replace filter to make the replacement.

For <li>

<li class="{{ entry.hasDescendants() ? 'has-dropdown' : "" }} data-class-{{entry.slug}}">

For <a> (You need to modify this for each different entry type)

<a href="{{ entry.url}}" data-url="{{ entry.url }}">{{ entry.title }}</a>

After all this you'll have special "tags" in your cached content that you can run some replacement on, like this:

{{ navigation|replace({('data-url="' ~ craft.request.getUrl() ~ '"'): 'class="active"'})|replace({('data-class-' ~ craft.request.segment(1)): 'active'})|raw }}

You can run two |replace filters after each other, you could just split them up into two steps. Also, this code is untested - I just wrote it from my head so please be aware there might be some typos etc..

  • Thanks - great job - only need the active class on the li so just need the 1 filter. Cheers!
    – mmc501
    Commented Nov 18, 2014 at 9:45
  • If it solved your issue please approve the answer. Cherrio! Commented Nov 18, 2014 at 10:54

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.