Building a Statamic Navigation Menu
Have you every been bogged down by how WordPress does its navigation menus? Perhaps you’re aware of the Walker_Nav_Menu
PHP class which is a way to tap into the menu tree structure, and determine your own custom settings for a given menu when extending this class with your own instance.
But, it’s a little cumbersome, isn’t it?
Or, maybe you keep things a little simpler by using the wp_nav_menu()
function, which accepts an array of arguments to configure classes and customize the markup just a little bit. This is probably an easier way to go than the Walker above, though perhaps not quite as flexible.
But, what if you wanted something completely different? Few of us developers like to install plugins for mega menus or anything like that. They only seem to clutter things up in the back end, and decay over time for lack of use and understanding. What if you wanted total control over your menu markup, so as to perfectly match that beautiful, high-fidelity design in Photoshop Figma that you got from your designer?
You’d need to come up with something a little different. As my friend Joey discusses, you might install a 3rd party tool, or roll your own with a function that leverages wp_get_nav_menu_items()
to get an array of your nav items you can use in the template. I use this as inspiration for something really similar when I build in WP these days (thanks Joey!).
But, as he discusses there, you still have work to do to organize them into a properly nested array where children menu items are actually reflected that way in your array once you get it into the template.
There is a better way with Statamic
One of the myriad of reasons I choose Statamic these days, is that problems like this have been well thought through, and the developer experience is just that much nicer.
Overall, we could say that the editor experience in building navigation menus is comparable between WordPress and Statamic. Both offer a drag interface for ordering and nesting items, and you can create multiple menus from within that screen in the admin.
However, the actual developer experience in Statamic is much more user friendly, and even a pleasure because it’s been made so easy. At the end of the day, the nav
is simply a Tag with methods, where all the hard work is already done for us. All we need to do is to bring our own HTML for the most part.
Show me some code
Let’s assume that in both of our WordPress and Statamic sites, we have a “main_menu” configured.
Consider this WordPress example, using the wp_get_nav_menu_items()
approach so that we can have HTML output unadulterated with extraneous stuff, useful as it might be for certain things:
// based on Joey's implementation, linked above
function custom_menu_builder( $menu_id ) {
// a flat array of all menu items, including children
$menu_items = wp_get_nav_menu_items($menu_id);
// we'll need to create a new array after
// we're done working with the one provided
$new_menu = [];
foreach ($menu_items as $item) {
// check if the menu item has childen,
// and create a sub-menu for this item...
$new_menu[] = [
// properties go here
'children' => []
];
// check if this item IS a child, and configure
// the current menu item, noting its parent id...
// finally, just output a normal item
// if the above don't apply
$new_menu[] = [
// properties go here
];
}
}
Then, once we do all that work inside of a helper function, we can get into the template, and output it. This is an extremely simplistic example:
<?php
$menu = custom_menu_bulder( 'main_menu' ); ?>
<ul>
<?php foreach( $menu as $item ) { ?>
<a href="<?php echo $item['url']; ?>">
<?php echo $item['title']; ?>
<? if (isset($item['children'])) : ?>
<ul>
<?php foreach ($item['children'] as $child) : ?>
<a href="<?= $child['url']; ?>">
<?php echo $child['title']; ?>
</a>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</a>
<?php } ?>
</ul>
This is pretty nice to work with, but it does take some legwork to get the template to be in this shape. Both of the above examples need a lot more to happen (see Joey’s post, linked above for more) if you wanted a realistic menu output.
Now show me the Statamic stuff
<!-- image tag -->
<ul>
{{ nav:main_menu }}
<li>
<a href="{{ url }}">{{ title }}</a>
{{ if children }}
<ul>
<!-- children go here -->
</ul>
{{ /if }}
</li>
{{ /nav:main_menu }}
</ul>
What a difference! All of the leg work to get it into this sort of shape in WordPress is done for us in Statamic. Isn’t this so much nicer to look at and work with?
Why it’s better in Statamic
Even with just this surface-level example, it seems to me that this is a much better way to go. And we haven’t even taken a deep dive into how this can be improved with checks like is_parent
or is_current
to conditionally style things, or even to conditionally render items.
Leveraging the nav
tag with its variables and parameters gives us everything we need, right inside the Antlers template itself. We can set the max_depth
, to control what level to show, from
to determine where in the menu tree to begin, and other meta data about the content the menu items themselves reference, like is_published
and more.
Even more, we can easily create a nav in Antlers without creating a menu first. Let’s envision a simple brochure with a half-dozen or so pages - think Home, About, Contact - that sort of thing. We can create a menu just using the nav
tag with a collection
method, and this will always reflect what pages we have, whether or not we create a Menu in the control panel.
<nav>
<ul>
{{ nav:collection:pages }}
<li><a href="{{ url }}">{{ title }}</a></li>
{{ /nav:collection:pages }}
</ul>
</nav>
Again, this is a simplistic example, but it this is a realistic to build something simple when you don’t need to sweat the details. So, why would we want to do a bunch of PHP, arm-wrestling our data into something reasonable to use in the template, when Statamic’s system works so much better? You tell me…