How to Use the New Custom Menu Feature in WordPress 3.0

One of the most hailed features of the recent WordPress 3.0 release is the addition of customizable menus. Previously, users had to rely on their theme (or hack it) to provide them with a navigation menu for their site, but now they can edit site menus from the WordPress dashboard.

I’ll first show you how this functionality works in the default new WordPress theme, Twenty Ten; then, I’ll show you a few different ways you can use it in your own themes.

I’ll assume you have a WordPress 3.0 installation up and running. Let’s start by having a look at the new Menus interface. Click on Menus in the Appearance panel of your WordPress Dashboard, and you’ll be presented with an interface for creating your first menu:


Add a new menu

Once you’ve added a menu, the interface on the left-hand side of the page becomes activated: you can now add categories or pages to your menu, as well as any other external or internal links you’d like. You’ll also see a box telling you that your theme supports a menu, and asking you to assign a menu to the Primary Navigation:

The Twenty Ten theme’s Primary Navigation

What’s this Primary Navigation? It’s the primary menu displayed just below the header image of the Twenty Ten theme. Why, you ask, were there already elements in that menu before you created and assigned your custom menu? Good question.

WordPress 3.0’s new menu functionality rests on the wp_nav_menu function, and it’s a clever one. If the user hasn’t defined any menus, wp_nav_menu will fall back on the standard wp_page_menu, which displays a list of the site’s pages. That’s what you’ve been seeing up to now. But if you select your new menu from the drop-down menu below the Primary Navigation and click Save, your custom menu will replace the default page listing.

So, now you know how the new menu functionality works, but how do you make use of it in your theme? Well, the simplest way is to call wp_nav_menu where you’d like a custom menu to appear. Much like post thumbnails and widgetized areas, your menu will first need to be “registered” with WordPress, though. Let’s have a look at how Twenty Ten does all this. First, in header.php, we find the call to wp_nav_menu:


< ?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary' ) ); ?>

That’s a little more complicated than a simple call, but not by much: container_class simply specifies the class attribute of the div that will wrap the menu, and theme_location tells WordPress which of the registered menus we want to use.

To work out where the menus are registered, we need to travel to functions.php, where we find a call to the aptly-named register_nav_menus function:


// This theme uses wp_nav_menu() in one location.
register_nav_menus( array(
	'primary' => __( 'Primary Navigation', 'twentyten' ),
) );

The 'primary' key used here corresponds to the primary location specified in the wp_nav_menus call. Let’s break this down. We’re telling WordPress that our theme will have one menu location, called primary, and will be displayed to the user as the Primary Navigation. Then, in the header, we call wp_nav_menu, asking it for whatever the user has assigned to the primary location. Pretty simple.

Now what if you wanted to add a secondary menu to your WordPress theme? Let’s do that. Start by making a copy of the Twenty Ten theme and editing the theme info in style.css to give it your own name. Then we’ll change that section in functions.php to register an extra menu:

// This theme uses wp_nav_menu() in two locations.
register_nav_menus( array(
  'primary' => __( 'Primary Navigation', 'twentyten' ),
  'secondary' => __('Secondary Navigation', 'twentyten')
) );

Then, wherever you’d like the secondary menu to appear in your theme, simply plop in the following:

< ?php wp_nav_menu( array( 'theme_location' => 'secondary' ) ); ?>

And you’re done. If you load up the Menus interface in the Dashboard, you’ll now see another drop-down menu that allows you to select a second menu:

Our secondary menu

Where to from Here?

Of course, there’s a lot more to wp_nav_menu and the new menu functionality than I’ve just covered. As always, your first stop on the path to WordPress enlightenment is the Codex: as you’ll quickly see, wp_nav_menu has a sizeable array of options to choose from. And, of course, don’t forget the time-tested technique of every web developer coming to grips with a new toy: experimentation!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Jre

    Great article and something i really want to use on upcoming site.

    One quick question I have a site that has a horizontal menu showing level 1 (parent) pages and then a vertical menu that only child pages on the corresponding parent page, i did this using wp_list_pages and it works well…. would there be any way you could do that was this using the custom menu? Ideally by using only one custom menu?

    Cheers Guys

    • Louis Simoneau

      Yep. When you’re dragging around the menu items in the Dashboard to reorder them, you’ll see you can nest them under another menu item (the dotted outline will appear indented to the side a little.) This will generate a nested ul on the front-end. That’s a good point, actually: when designing a theme you need to keep in mind that your user might create such a nested menu, and prepare your theme accordingly.

  • mcnitt

    A quick word of caution regarding accessibility — the dropdown menus in the new WordPress Twenty Ten theme are not accessible to screenreader users. (I’m currently working on a new WordPress site for a blind organization in the U.S. After some initial screenreader testing, we found that the Twenty Ten menus are not accessible in JAWS or Window-Eyes, the two most popular screenreaders.)
    Digging a little deeper, it appears the issue is related to the use of the CSS rule “display: none” to hide the menus before a user rolls over them. In the Twenty Ten theme, this can be found at line number 404 of style.css…
    #access ul ul {
    display:none;
    position:absolute;
    top:38px;
    left:0;
    float:left;
    box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
    -moz-box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
    -webkit-box-shadow: 0px 3px 3px rgba(0,0,0,0.2);
    width: 180px;
    z-index: 99999;
    }
    Line number 434 of style.css appears to display the dropdowns on hover…
    #access ul li:hover > ul {
    display:block;
    }
    Unfortunately, it seems when JAWS and Window-Eyes encounter “display:none” they simply ignore the content. Switching the state to “display:block” via CSS on hover does not populate the content in the sreenreader later so the contents of the Twenty Ten dropdown menus are basically invisible and unreachable. Not a good situation.
    This is just a quick finding. I intend to look into the issue a bit more and do a writeup. If you have screenreader experience, I would like to hear your thoughts on how we can fix this and get the needed updates into WordPress.
    Best,
    Brian

    • Louis Simoneau

      Hi mcnitt,

      Good spotting! I’d say the thing to do would be to file a bug report on the WordPress Trac. http://core.trac.wordpress.org/ I don’t personally have screenreader experience, but a quick search turns up a number of people using left: -999em and left: 0 in place of display:none and display: block to achieve the same effect. Seems like a perfectly reasonable suggestion for the WordPress dev team!

  • job ballard

    seriously awesome… i have wondering about this, thanks yous.

  • mguillau

    Great functionality. I have something slightly different: I have 2 menus (let’s say, “Menu 1″ and “Menu 2″, and I would like to let appear either “Menu 1″ for some pages OR “Menu 2″ for other pages.
    Is this possible?

    • Louis Simoneau

      Yep :-)

      Just put different calls to wp_nav_menu in your various page templates, or use conditional tags like is_home or is_page to determine which menu to show.

  • Scott

    Hi. Thanks for the article. This is definitely very helpful. I’m wondering how — if at all — these instructions would differ for buddypress. I’ve created a custom menu in my WordPress theme, but it’s only showing up on the front page of my site. How can I get it to show up on every page of my site? Will this need to be done in header.php, functions.php and in buddypress_navigation.php? Anybody know?

  • Mesonto

    Thank you for your article. With your help adding another menu went as smooth as butter. I am still not sure I am going to use this internal menu system or not yet but I am going to give it a go. In the past (pre 3.0) I used “Menubar” by Andrea Tarantini and I am very familiar with it. Never-the-less I will try moving with the times.

  • carole

    Thanks so much for this. I was looking around for how to set up a second menu and this made it so simple to do. I love your use of, go here do this, THEN go here and add this. Most explanations I found on how to use the wordpress custom menus missed that very important where to add the code in order for it to work bit.