Take the 2-minute tour ×
Craft CMS Stack Exchange is a question and answer site for administrators, end users, developers and designers for Craft CMS. It's 100% free, no registration required.

This seriously can't be this hard. How are you handling complex navigation on your sites? Do you hard-code them? Do you use a dedicated "Menu" Structure Section? I am curious what everyone is doing.

I have a few customers who really need to have control over their menu and its structure, but as I build the templates, I am finding I need complete control over the first level and especially the sub/children of them. I am finding it nearly impossible to come up with a way to be able to loop through children and style them how I need to.

Basically, I am trying to access the Dropdown portion of this menu example and as you can see, I need to be able to add a class and data-toggle to those items.

<nav class="navbar navbar-default" role="navigation">
  <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
    <ul class="nav navbar-nav">
      <li class="active"><a href="#">Link</a></li>
      <li><a href="#">Link</a></li>
      <li class="dropdown">
        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <span class="caret"></span></a>
        <ul class="dropdown-menu" role="menu">
          <li><a href="#">Action</a></li>
          <li><a href="#">Another action</a></li>
          <li><a href="#">Something else here</a></li>
          <li class="divider"></li>
          <li><a href="#">Separated link</a></li>
          <li class="divider"></li>
          <li><a href="#">One more separated link</a></li>
        </ul>
      </li>
    </ul>
  </div>
</nav>
share|improve this question
    
Hey @JacobGraf, there are lots of other questions on this topic in addition to P&T's suggestion. It'd be best to focus this into a more specific, answerable question or jump into one of the many other more detailed posts. –  Matt Stein Aug 12 at 18:14
    
I have already read Pixel and Tonics answer and my questions stems from it. I need a way to customize the HTML for the "children" and I am not finding any solutions to that problem. –  Jacob Graf Aug 12 at 18:19
    
I would think that the {% ifchildren %} and {% children %} tags would be sufficient so that you could control them from a parent class, but if I'm oversimplifying then it may still be worth getting more specific with your question. –  Matt Stein Aug 12 at 18:21
    
Yes, you are oversimplifying it. {% children %} outputs list items. I need control over the classes on those list items as well as some data-options, etc. It is too simple and I need to find a way to be able to access the children loop and completely customize its output. I have modified my question slightly to help. –  Jacob Graf Aug 12 at 18:25
    

3 Answers 3

up vote 4 down vote accepted

If the {% nav %} tag doesn't give you enough control over the output, you can always replicate the behavior with custom loops and the getChildren() method. Just nest them as far as your navigation hierarchy possibly gets.

Edit:

Here an example code on how you'd dynamically call getChildren() on each top-level entry of your structure. If you need to go deeper another level in the structure's hierarchy, I marked the line where you would do that:

<ul class="Navigation">

    {# Get top-level entries in pages structure (exclude home page)  #}
    {% set pages = craft.entries.section('pages').id('not 1').level(1) %}

    {# Loop through top-level entries #}
    {% for page in pages %}

        {# Check if entry has descendants #}
        {% if not page.hasDescendants %}

            {# List navigation item if entry has NO child entries #}
            <li class="Navigation-item">
                <a href="{{ page.getUrl }}" class="Navigation-link">{{ page.title }}</a>
            </li>

        {% else %}

            {# List navigation item if entry does have child entries #}
            <li class="Navigation-item Navigation-item--dropdown">

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

                    {# Get child entries of current iteration's top-level entry #}
                    {% set subPages = page.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">
                            <a href="{{ subPage.getUrl }}" class="Navigation-link Navigation-link--subMenu">{{ subPage.title }}</a>
                        </li>

                    {% endfor %}

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

</ul>

.

Because most of your question's topics are already covered by other Q/As, I'd also recommend you to read through these too.

How to realize a client editable navigation:

More control over the HTML output of the nav tag:

share|improve this answer
    
Two questions I have for this. 1) How would you dynamically getChildren? Using an ID or something? and 2) You would need to code the exact nav structure and there wouldn't be any flexibility for the client to add another level if they needed to. –  Jacob Graf Aug 12 at 19:23
    
@JacobGraf I just updated my post. This should answer your question on how to get the child entries dynamically. And about that second concern, isn't the exact control over the HTML output of each hierarchy level what you want to achieve? –  carlcs Aug 13 at 13:40
    
This was the answer I was looking for. I appreciate your help. Not sure why you had to insert the rude comments in your responses, but I appreciate it anyway. –  Jacob Graf Aug 14 at 14:28
    
Yes you're right, @Jacob. There was no need for being rude, sorry! –  carlcs Aug 14 at 15:56

It sounds like you want utmost flexibility. So instead of trying to write any code for you, let me just describe all of the tools which should make this possible...


To begin, you definitely want a Structure section. Then your clients will have the complete control that you are looking for... adding, removing, and rearranging their entries (aka pages).

{% nav %}

This one is pretty obvious. Run the whole section through a nav tag like this:

{% nav entry in craft.entries.section('pages') %}

Within that loop, you can use some of these other tools...

{% ifchildren %}

Also pretty obvious. You'll need this to run sub-loops for all of your nested entries. Every time an entry contains sub-entries, this Twig tag will be triggered (no matter how deep it goes).

entry.hasDescendants()

Optional. If you want to check if an entry has any children without actually navigating down that branch, you can use this function. In fact, many of the EntryModel methods can be useful to you in various circumstances.

entry.level

This will tell you exactly what level you are on. So for example, "1" is the top level, "2" is their respective children, etc.

entry.type

If you're using various entry types (which you probably are), then this will help you sort out which type of entry you're dealing with at that exact moment.

Bonus: {% cache %}

You can wrap the whole nav in a cache tag to make it easier for the system to deal with in the future.


If you feel like I missed something, or that you still don't have the control that you want, just let me know what you're trying to accomplish. I can 99% guarantee that there is an existing Craft way of handling it.

Hope that helps!

share|improve this answer
    
{% nav entry in entries %} makes sense if you want to make use of {% children %}. If you want more control over the html of nested items, I'd use basic for loops: {% for entry in entries %}. –  carlcs Aug 13 at 8:54
    
I meant the self-nesting feature of the {% children %} tag. –  carlcs Aug 13 at 9:25
    
@carlcs He specifies that his nav has children... It seems like a perfect fit to me. –  Lindsey D Aug 13 at 16:24
    
Ok, I didn't know that you can use methods like level or hasDescendants within the {% nav %} tag. But that's great if you can! Always thought {% nav %} is something very special and that it is restricted to the simple use case shown in the docs. Thanks for the info, Lindsey! –  carlcs Aug 14 at 16:21
    
Using {% nav %} in combination with level is probably the cleanest way to add further HTML to a navigation. Marion's solution is really clever, but it seems kind of hacky to "misuse" macros like this. –  carlcs Aug 14 at 16:22

I am a big fan of using a recursive macro when the {% nav %} tag is not enough. This answer has an example.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.