Craftcms Hero Image

Client Controlled Site Navigation

This tutorial will show you how to provide your clients an option to add, edit, and delete items from the site navigation. You can also control how deep nested items are allowed. This can easily be accomplished out of the box with no addons in Craft CMS.

Structure and Fields

First we need to create fields and add them to a structure channel. We need three fields:

  • Link to a Site Page - fieldtype Entries using all sources and limited to 1 entry, handle of sitePageLink.
  • Off Site Link - fieldtype Plain Text, handle offSiteLink
  • Open in New Tab - fieldtype Lightswitch, handle openInNewTab

Next You'll create the structure section and uncheck the option entries in this section have their own URLS. You can also set the maximum depth for navigation here. I've set mine to 2.

Navigation Structure Settings

Navigation Entry Types

Next we create two different entry types for the navigation: one for on site links and one for offsite links. You can do that by going to Settings > Sections finding the Navigation section we just created and go to Edit entry type. Once there create two entry types. One called Internal Link (handle internalLink) and the other Offsite Link (handle offsiteLink).  In the field layout be sure to Show the Title Field and add the fields like this:

Link Field Layouts

Template Code

Below you will find the template code that checks whether the link is internal or offsite. If the link is offsite and open in new tab switch is turned on then target="_blank" will be added to the link.

We have also added data-url attributes and are replacing those with class="active" should they match the url of the current page.

{% set navigation %}

 {% set pages = craft.entries.section('navigation').level('<='~2) %}

   {% nav page in pages %}
       {# Check for entry type / get related entry #}
       {% if page.type == 'internalLink' %}
           {% set linkedEntry = page.sitePageLink.limit(1).first() %}
           <a href="{{ linkedEntry.url }}"  data-url="{{ linkedEntry.url }}">{{ page.title }}</a>
       {% endif %}

       {# Check for entry type / get offsiteLinks #}
       {% if page.type == 'offsiteLink' %}
           <a href="{{ page.offSiteLink }}"  data-url="{{ page.offSiteLink }}" {% if page.openInNewTab == '1' %}target="_blank"{% endif %}>{{ page.title }}</a>
       {% endif %}

       {% ifchildren %}
          <ul class="dropdown" style="background:pink">
              {% children %}
      {% endifchildren %}

   {% endnav %}

 {% endset %}

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


Now your client can easily create internal and external links  in the site navigation as well as reorder them. Many clients request the option to set navigation themselves even though it rarely changes. Setting this up is simple and will give clients the control they want without allowing them to touch the underlying html.