DiggingIntoWordPress

by Chris Coyier & Jeff Starr

Using Menus in WordPress 3.0

Posted by on

The menu system in WordPress 3.0 was hotly anticipated. But perhaps unbeknownst to many average WordPress users, actually using this feature takes some coding work. In fact, even enabling the features take a bit of code.

Below we’ll go through the steps for inserting a custom menu into your theme. Note that many themes will have menu functionality built-in. This is for Do-It-Yourself folks who are trying to add it to their existing theme.

1. Register menus in functions.php file

if ( function_exists( 'register_nav_menus' ) ) {
  	register_nav_menus(
  		array(
  		  'foot_menu' => 'My Custom Footer Menu',
  		  'sidebar_menu' => 'Super Sidebar Menu'
  		)
  	);
}

2. Create menu in Admin

Now that the feature is enabled, go to Appearance > Menus and build and save a custom menu.

3. Attach custom menu to your “declared” menu

Now that you’ve declared a menu (in functions.php) and built a menu (in the admin), you’ll need to connect them to each other.

4. Insert the menu into the theme

Now anywhere in your theme you want to display that menu, use:

<?php wp_nav_menu( array('menu' => 'Footer Menu' )); ?>

Change the name of the menu in the code above to match whatever you named the menu in the admin. This very site uses a WordPress 3.0 menu in the footer. The output HTML looks like this:

<ul class="menu" id="menu-footer-menu"><li class="menu-item menu-item-type-post_type menu-item-2636" id="menu-item-2636"><a href="http://digwp.com/contact/">Contact</a></li>
<li class="menu-item menu-item-type-post_type menu-item-2633" id="menu-item-2633"><a href="http://digwp.com/about/">About&nbsp;Site</a></li>
<li class="menu-item menu-item-type-post_type menu-item-2634" id="menu-item-2634"><a href="http://digwp.com/advertising/">Advertising</a></li>
<li class="menu-item menu-item-type-post_type menu-item-2635" id="menu-item-2635"><a href="http://digwp.com/archives/">Archives</a></li>
</ul>

5. Rejoice

Now any time this menu needs to be updated, we can do it from the comfort of the WordPress admin area.

52 Responses

  1. There is an error with your code, I think you meant:

    <?php wp_nav_menu(‘Footer Menu’ ); ?>

    Great post otherwise!

  2. I had to learn this the hard way, I wish I had seen this post first.

  3. Daniel B. August 2, 2010

    Rockin-n-rolling! I can’t wait for DIW 3.0+ later this month… I take it this is an excerpt?

  4. Sergei Filippov August 2, 2010

    Loving it. Will totally use this on my new site =]. Thanks Chris. PS. Love the book.

  5. Thanks for the insight, although I already figured it out by looking into the twentyten theme =)

    The menu creation was a necessary step for WP but what’s a HUGE lack with custom post types is, that you can only attach a specific post of a post type, not the actual post type (as it’s possible with categories), which is not only sad but seems completely illogical to me, since a custom post type is a pimped category … isn’t it? And why would I i.e. attach a movie (of post type movies) to a menu, rather than the movies post type/category?

    Does anybody know a way other than creating a page, with a custom loop for the targeted post type? Is that even the right place to discuss this?

    greets

  6. One thing that it badly lacks is the to define settings, like show 3 depth of this category and exclude this and this. For that I find myself still hacking around this within themes.
    And, always remember to click save after you changed something. I did this mistake because of the Ajaxy interface. It will not save automatically.

  7. You make it sound sooo easy!

  8. Hi Chris,

    If you’re doing this for a publicy released theme, you probably want to add:

    if (function_exists('wp_nav_menu'))

    before calling wp_nav_menu in step 4 above.

    Not necessary if all of your customers are using WordPress 3.0, but if they’re not, they’ll be serving up “Fatal error: Call to undefined function wp_nav_menu()” to their visitors…

    Of course for a publicly released theme, you probably want to include a fall back menu.

    At the risk of spamming you, if people are interested in providing robust menus that work for all versions (using Custom Menus for 3.0 and wp_list_pages for earlier versions)), they can read myPractical Theme Support for Menus post.

  9. Change the name of the menu in the code above to match whatever you named the menu in the admin.

    Don’t you mean the name you gave it in the functions.php ?

    • Nope, I mean the name you gave it in the admin. That’s how the function knows exactly which menu to put there. The functions.php name just “declares” it, but the menu in the admin is where you attach a real menu to it and that’s the name you need.

  10. I must be missing something because I just don’t understand why everyone is so excited about the new wp menus. It seems like a lot of work to essentially create a bunch of links within a list structure. What’s the benefit of doing it this way opposed to simply coding a menu?

    • Mike,

      For my own site, there’s no real advantage as I’m happy to code the menu manually. But if you are writing a theme that other people will use, that makes it much easier for the end user.

      Note also, that the vast majority of the 10 million people using WordPress are not web developers, so they are probably much more comfortable using a menu interface compared to manually coding a menu.

    • It’s just a matter of being able to update menus without touching code. Obviously, better for non-coders. But better for us coders too, especially when you are building gigantic/complex menus that can really benefit from a UI to control position of things and whatnot.

  11. Does anyone know how to add a “home” link t0 these menus?

    I know i can add the whole link to the homepage as a custom link, but it doesnt get the current page class if i do that…. or does it?

    • chris Jangelov October 7, 2010

      In the area where you choose pages to include, choose the tab View all. Now the choice Home is available.

  12. Noe Ruiz August 4, 2010

    Adding a filter in the functions for displaying custom post types in a tag index page has broken my register_nav_menu, has anyone else experienced this? Below is my filter

    add_filter('pre_get_posts', 'query_post_type');

    function query_post_type($query) {
         if(is_category() || is_tag()) {
              $post_type = get_query_var('post_type');
              if($post_type)
                   $post_type = $post_type;
              else
                   $post_type = array('post','portfolio'); // replace cpt to your custom post type
                   $query->set('post_type',$post_type);
                   return $query;
         }
    }

  13. Hey guys,

    does anyone know how to duplicate the main menu in the footer? ie.. if you create one menu it shows in both the main nav area and in the footer. The code currently outputs div id, so I do want to duplicate the div id. I don’t want to be creating 2 menus just using the one in 2 places.

    Cheers

    Ad

    • “The code currently outputs div id, so I do NOT want to duplicate the div id. I don’t want to be creating 2 menus just using the one in 2 places” Sorry

  14. Thanks Chris, I hope you cover more WordPress 3 stuff

  15. 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. I tried positioning the menus off-screen instead of hiding them but this broke the functionality on iPhone and iPad.

    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.

    Brian

    • Thanks for the findings on that Brian. Pretty interesting stuff. Display: none is a classic problem in that way. WordPress even includes a standard class name “screen-reader-text” that is normally used to hide things in an accessible way (booting it off the screen with absolute positioning). I’m almost certain the dropdowns could be rewritten in such a way to not use display none;

      Do you know how visibility: hidden bodes with screenreaders? Since these menus are positioned to not effect other elements layout-wise anyway, maybe that would work.

      • Visibility:hidden and display:none are basically the same — both ignored by JAWS and Window-Eyes. Switching to off-screen absolute positioning solves the screenreader issue but breaks iPhone and iPad functionality.

        Not sure if it’s an intended feature, but one of the neat things about the dropdowns implemented in Twenty Ten is that they actually work on iPhone and iPad. Tapping on a top level menu item displays and holds a submenu in open position allowing iPhone/iPad users to navigate submenu items. When I tried switching the submenus from display:none to use CSS off-screen absolute positioning it fixed the screen reader issue but broke iPhone/iPad functionality (tapping a top level menu simply launched the page).

        Given all Twenty Ten sites using dropdowns with display:none are basically inaccessible to screen readers, thinking display:none should be updated in core to off-screen positioning. To restore iPhone/iPad functionality, maybe serve a special stylesheet that uses display:none? Of course, that’s heading down the road of device detection which gets messy. What do you think? Maybe there’s a better solution?

        • Is the case the using the position absolute method breaks the iPhone/iPad in this exact particular instance of how the CSS was written, or is that technique in general just always break the iPhone/iPad?

        • Hi Chris,

          Good question. I don’t have a quick answer. It’s on my to-do list to investigate.

  16. Eric Boyer August 13, 2010

    Chris,

    If you were to display a category in the nav, how do you then list the posts in that category IN the nav. (to do a drop down)

    Seems like common functionality, but I can’t for the life of me figure it out.

  17. epschmidt August 18, 2010

    I know you can add a specific class to the li items, but what about the link itself? The a tag? I want to be able to add a class to that from within the custom menu so I can use a menu item to launch a thickbox pop-up.

  18. Dear Chris:
    As usual a complete guide to whatever topic you cover, thank you for making it so easy to follow and implement by anyone.

    I had done a quick video screen cast on using the New Custom Menus in WP 3.0 here,
    http://www.elmalak.info/create-custom-menus-wordpress-3-0/

    Hope it’s useful as well.

    elmalak

  19. There’s an issue with how you’re displaying the menu.

    As is, it requires an end user to know what you’re referencing the menu as, and naming their custom menu just that. So if they named their new menu ‘foo’ and put that in the drop down for the ‘Footer Menu’ slot under ‘Theme Locations’ it wouldn’t work. It’s pretty confusing.

    instead try this for displaying the menu:

    wp_nav_menu(array('theme_location' => 'footer_menu'));

    that way no matter what they name their custom menu, they can just put it in the correct slot and it will work.

  20. When building your menu within the admin, you can add URL, Navigation Label, and Title Attribute to each menu item. Is there any way of adding a class or ID to specific menu items?

    Also, is there any way of adding any additional code into the menu? ie. – the last menu item is search, but rather than making ‘search’ a link, have a search box after it instead.

  21. Great, as always, Chris.
    I have a question I hope you or a reader can take a sec to answer: can one use a jquery accordion-like menu using the built in menu system? seems like not, since when you click the parent item that would normally pop down the accordion to show the sub-items, WP is dutifully delivering you to the parent item page – I tried putting Javascript:; in the url, but it nixed that next time I went in to edit.

    here’s the site I’m working on, and the jquery menu is in place – roughly – and I’ve been pullin’ my thin hair out trying to figure out a way to stick to the designer’s idea.
    here.

    Also, the Home button won’t work. Weird.

    Thanks for being there for me over and over again. I’m much obliged.

  22. Great article! Quick question. At least with the Twenty Ten template it wants to repeat the navigation menu vertically – how can I force it to repeat horizontally instead? I’ve placed it in the footer section of code…but its getting squished over vertically instead of spreading out nice horizontally. Can see what I mean on http://www.cccpenndel.org. Thanks!

  23. Does anyone have an idea on how to separate the children from parents to place them elsewhere on the page? A split menu so to say.

    The internet is full of how to use the new wp_nav_menu but little about modifying it.

  24. Hi! I’m using the wp-menu for a client website, and I’m trying to keep the parent page of sub-subpages active, but it isn’t working.

    My menu outputs:

    <li id="menu-item-61" class="menu-item menu-item-type-post_type current-page-ancestor menu-item-61"><a href="http://www.bronsonco.com/future/resources/">Resources</a>
    <ul class="sub-menu">
    	<li id="menu-item-51" class="menu-item menu-item-type-post_type current-page-ancestor menu-item-51"><a href="http://www.bronsonco.com/future/resources/checklists/">Checklists</a></li>

    and my css for that active effect:

    ul.menu li.current_page_item a,
    ul.menu li.current_page_ancestor a{
        background: #0e5181;
        border: none;}

    When I’m in one of the children pages of the page Checklist, the tab Resources isn’t turned on. Those children aren’t part of the menu though.

    Any ideas on how to make that work?

  25. I ended up putting my menus in my page templates, that way, for the about page, which has lots of sub pages, I can put ‘active’ on both the top (about) and on the sub-menu item. Why fight it. :-|

    Phil

  26. Here’s the test site – click on the about page. I struggled with the same thing, and realized that it wasn’t 2nd rate to put the menus in the page templates. it’s fine.

  27. chris Jangelov October 7, 2010

    I too haven’t found a way to include “home” in the menu. Anyone knows?

  28. chris Jangelov October 7, 2010

    So this is how you include a Home link in the menu:
    In the area where you choose pages to include, chose the tab View all. Now the choice Home is available.

  29. ignore: subscribing to post…

  30. @Marc – thanks for the links!

    I tried the simple section navigation but it doesn’t seem to order SubPages in the order that the actual custom menu is in.

    I’d like to stay away from plugins (if possible) and find the best way to code it.

    The thing is that NO ONE seems to know the code answer to this :-/

    Thanks again! – Alex

    • I agree, but after I couldn’t find any code snippets or explanation for this problem I decided to go with the plugin. Would you let me know if you find something?

      • Absolutely – I’ve asked this question in on quite a few places and will report back ASAP.

  31. cheers for this m8 have been trying to activate the menu option in my wordpress theme for the past few hours, thought i was gona be stuck with having to edit the menu in my websites html every time i needed to add or change a nav.

  32. Rode the link in my DigWP book pdf here and it answered all my Q’s but one:

    How do I display a custom top/primary menu for a custom page template? Every other page/post/home on the site has the standard site menu at top of page, but for the custom page menu I want just a single “Home” menu up there. I created a custom “Home_solo” menu but can’t assign it to the top/primary nav or it shows on all pages/posts. I’ve tried various ways of calling it in my custom page template to no avail, but am a newbie so I might be missing something obvious. (Am using a twenty eleven child with WP3.4.) example Any tips or suggested reading appreciated. Thanks for a great post (and book).

  33. Moments ago found a solution via WP forums where someone used Custom Fields for their custom page menu problems; something I hadn’t even considered. Thanks again for a great article!

  34. Good post! Thank you

Comments are closed. Contact us with any critical information. Thank you!

Code is poetry