How to add a new navigation menu to your WordPress site
Do you need to show an extra navigation menu on your WordPress site? Or perhaps you need to show a bunch of links someplace? No matter your use-case, WordPress provides navigation menus that are very easy to create, manage and display. If you like the drag and drop interface of the navigation menus management screen, and you so you figured you’ll create a menu to show them.
However, you neither want to show them in the sidebar (“Custom Menu” widget), nor in the content (“menu shortcode” plugin), and your theme doesn’t quite allow you to display it exactly where you want. What do you do? You need to register a new menu location. Let’s see how.
For this tutorial, we’ll use the free and popular Olsen Light theme. Let’s say we want to add a top menu, right above the logo. I’ll assume you’ll be using a child theme, so future theme updates won’t discard your customizations. Let’s start!
Registering a menu location
To register our new menu location, we’re going to use the register_nav_menu() function. Open your functions.php and add the following:
It’s pretty straightforward. The first parameter, ‘top_menu’ is just the location ID that we’ll refer to the location with, programmatically. The second parameter is a human readable title, that will be displayed in the WordPress UI. The above line could also be rewritten as:
register_nav_menus() allows us to define multiple new menu locations in a single call. In fact, register_nav_menu() itself calls register_nav_menus() in the background.
Creating and assigning a menu
If you now go to Dashboard → Appearance → Menus, you’ll notice that a new location is available, with the name “Top Menu“, just like we defined in functions.php.
Go ahead and press the “create a new menu” link, assign a few menu items, and assign it to the “Top Menu” location. Also make sure you have one or more sub-menu items, as we’ll need them for the purpose of this tutorial. If you’re not sure how to do that, read the related codex page first and come back. I named my newly created menu simply as “Top”.
Displaying the menu
We’re gonna need to add some code in header.php so if you don’t have it in your child theme, grab a copy from the parent theme. Right after the opening <body> tag (around line 10, might change from version to version) you’ll see these lines:
To be exactly, here’s where our code will go, as I’ll not be including the surrounding HTML elements in the code listings that are to follow:
Now that we have identified an appropriate place for our code that is above the logo, let’s go ahead and add it:
Two interesting things happen in those 7 lines. First, in line 1 we check if there’s a menu assigned on the ‘top_menu’ location using the has_nav_menu() function. If there is, then we echo the wrapping div and the menu. This helps to avoid having an empty div if there isn’t a menu to show.
Second, we display assigned menu by using wp_nav_menu() and passing the ‘theme_location‘ parameter we’re directing it to show whatever our ‘top_menu‘ location is assigned to.
At this point, we can refresh our page and see what happens.
Success! It’s ugly, but it works! Now it’s mostly a matter of styling it according to our needs. If you inspect the new menu with your browser’s developer tools, you’ll find that this markup has been generated (yours will differ, but should be quite similar):
We can see on lines 2 and 3 that WordPress has generated the class .menu-top-container and the id #menu-top for us. These are based on the nav menu we created via the UI and we named “Top”, and don’t relate to the location name, which would include the string “top_menu” verbatim. So, let’s remove the div.menu-top-container altogether, and change the class and id of the <ul>:
‘menu_class‘ and ‘menu_id‘ set respectively the classes and ids that the <ul> element will get. Just add/remove anything you need. Similarly, there are ‘container_class‘ and ‘container_id‘ parameters that behave exactly the same but apply on the container. We could have used, but we don’t need a container anyway, so we set ‘container‘ to an empty string to no longer include it, but we could have instead set it to ‘nav‘, ‘span‘ or any other non self-closing element if required.
Classes .nav and .navigation are already used by the theme, so I’m reusing them for brevity. They are enough to demonstrate how menus are affected.
If you now refresh your page, you should see that the menu has been transformed. If you also hover over the item that has sub-menu items, you’ll see them expanding to show.
But hey, this is a top menu and we don’t actually need sub-menu items. Should you (or your other administrators) always have to remember not to assign a sub-menu at this location? Heck no!
You can simply pass ‘depth‘ as 1 (the default is 0, which means no limit), which will limit the menu to just one level. Or change it to any other non-zero number that suits your requirements. Now refresh again, and witness the marvel of WordPress automatically discarding sub-menu items!
Conclusion
That covers most of what you ever going to need regarding native WordPress navigation menus. With just a few lines you can add a full fledged menu in any part of your website. All you have to do now is style. Style responsively (pun intended).
3 responses to “How to add a new navigation menu to your WordPress site”
Very detailed and helpful…Thank you!
Stuck with an slightly older theme w/ only one menu and using a one-pager layout I was in desperate need of a second mobile-only menu for scrolling to unique ID’s. Registering is simple – but understanding how to code the new menu into the existing ‘container’ – was beyond my php understanding. Your breakdown of the has_nav_menu() and wp_nav_menu() functions and passing the ‘theme_location‘ parameter was exactly the insight I needed. I was able to fit my new menu directly into the existing mobile menu formatting. No additional css req – THANKS
Unbelievably, I have spent HOURS trying to do something relatively simple: display an alphabetized menu of links on a page. Your tutorial took care of it on the first go, effortlessly and painlessly. Thank you very, very, VERY much! :D