Large, Complex Navigation For a while I've been having difficulty handling large navigation in craft. I built this site a while ago, and if I am honest I would probably change the structure if I was doing it again, but that's for another time.

The nav is stored in a structure and each navigation entry is either linked to an entry or a custom url is entered. There are approximately 300 pages in the entire nav.

Here is the code I use to generate the nav:

{% macro navigation(pages, id='') %}
    &lt;nav role="navigation"&gt;
        &lt;ul role="menu" {% if id|length %} id="{{ id }}" {% endif %}&gt;
        {% nav node in pages %}
            {% set url          = node.url|length ? node.url : node.linkedEntry|length ? node.linkedEntry.first().url : node.customUrl %}
            {% set active       = node.slug == craft.request.getSegment(node.level) %}
            {% set class        = node.children|length ? "has-children" %}
            {% set class        = active ? class ~ " active" : url == craft.request.url ? class ~ " active" : class %}
            {% set separator    = node.separator  ? 'separator' %}

            &lt;li class="{{ class is not empty ? class  : "" }}{{ separator }} level-{{ node.level }}" &gt;
               &lt;a href="{{ url }}"&gt;
                   &lt;span&gt;{{ node.title }}&lt;/span&gt;
               &lt;/a&gt;

                {% ifchildren %}
                    &lt;ul class="children"&gt;
                        {% children %}
                    &lt;/ul&gt;
               {% endifchildren %}
            &lt;/li&gt;
        {% endnav %}
        &lt;/ul&gt;
    &lt;/nav&gt;
{% endmacro %}


The problem I have is that this is incredibly slow, in some cases I see load times of over 10s, which is unacceptable! I know that this is caused by the nav and not the rest of the page content.

I use caching to speed rendering up, and this works fine, but that only really masks the problem. 

I reckon that the bulk of the time is taken up checking whether it is active, what class it has etc. Is it possible to store it as a blob and run some kind of regex match on it as a whole?

I'd prefer it if the user could change the nav through the CMS, but if I am honest, this is not a necessity. I've even thought about hardcoding it!

Any one have any pointers or experience in the past?
It's those two lines that trigger database queries

{% set url = node.url|length ? node.url : node.linkedEntry|length ? node.linkedEntry.first().url : node.customUrl %}
{% set class = node.children|length ? "has-children" %}


The first one can be optimized by using the first method in the ternary condition. You just need to know if there is a linked entry, not how many. node.linkedEntry|length queries for all matching entry models and is slower than
just calling node.linkedEntry.first(). So change it to

{% set url = node.url|length ? node.url : node.linkedEntry.first() ? node.linkedEntry.first().url : node.customUrl %}


Same applies to the node.children criteria model in the second line. Change it accordingly

{% set class = node.children.first() ? "has-children" %}


That's about all you can do to optimize the code, now you should definitly add caching to it. It's not as straightforward to implement in this situation, as there's the dynamic "active" class you want to add to the output. So you have to either cache the whole navigation for each page it's used individually (each with the active class at the right place) or you use the string replacement technique described in this SE to cache the navigation globally for all pages.