How to add support for navigation menus to your WordPress theme

The new navigation menus system in WordPress 3.0 looks promising, but in my opinion it's not very usable yet. Anyway, here's one way to add navigation menus to your theme while maintaining backward compatibility:

In your theme's functions.php add something like the following code:

<?php
function mytheme_addmenus() {
	register_nav_menus(
		array(
			'main_nav' => 'The Main Menu',
		)
	);
}

add_action( 'init', 'mytheme_addmenus' );

function mytheme_nav() {
    if ( function_exists( 'wp_nav_menu' ) )
        wp_nav_menu( 'menu=main_nav&container_class=pagemenu&fallback_cb=mytheme_nav_fallback' );
    else
        mytheme_nav_fallback();
}

function mytheme_nav_fallback() {
    wp_page_menu( 'show_home=Start&menu_class=pagemenu' );
}
?>

In line 1 we add support for the navigation menus. The mytheme_nav() function is what you will use in the theme to display the menu. Inside that function we check if wp_nav_menu() exists, that means if we're running WordPress 3.0 (or later). If not we'll use the fallback function mytheme_nav_fallback().

Notice that the fallback also gets called if no navigation menus have been created in the admin area. That's what the fallback_cb parameter on line 4 does.To keep the HTM markup and the CSS consistent you'll have to use the container_class parameter on wp_nav_menu but the menu_class parameter for wp_page_menu.In your template use the following code to use your new custom function:

<?php mytheme_nav(); ?>

Resources

Ramblings

What's good about the new menu system:
  • Total control over what appears in the menu
  • You can add posts, pages, categories and tags in the menu
  • Very nice drag and drop interface
What's bad:
  • You will have to teach your users how to use the system properly.
  • If you create new pages they won't be added to your existing menu (except for top level pages).
  • You can not control your page menus through the navigation menus interface. I think it is... very very odd that WordPress doesn't have a simple drag-and-drop interface to arrange pages.
  • The previous point means that the new menu system is useless unless you update your theme.
  • The wp_nav_menu() call is inconsistent with the existing wp_page_menu() function.
Published on June 8, 2010 at 3 p.m. by Nicolas and tagged template, usability, navigation, WordPress, WordPress theme, theme, howto, development, wp_nav_menu. You can follow the discussion with the comment feed for this post.

28 comments

  • avatar
    Lox wrote this comment on June 12, 2010, 8:29 p.m.
    Don't be to exited about the new menu system. It is is intentionally incomplete. For example there is NO filter to filter the generated array of menus items. So, say goodbye to sub-menu and portions of menu display, you won't be able to do it with a powerful wordpress filter. Why? Because the wordpress dev team has refused to include ONE more line of code and delayed it to WP 3.1.
    Reply to this comment
    • avatar
      nicolas wrote this comment on June 12, 2010, 9:02 p.m.
      Yeah. I'm really disappointed by the menu system. I've worked with it for maybe 30 minutes and found several flaws and omissions. The method I describe in the post is useful because users who want to use the nav menus can, but they don't have to.
      Reply to this comment
    • avatar
      MichaelH wrote this comment on June 14, 2010, 11:22 p.m.
      Lox - I believe the developers addressed that isssue in 3.0.
      Reply to this comment
  • avatar
    yalamber wrote this comment on June 21, 2010, 3:02 p.m.
    How can we get the menu array or object to customize it the way we want. like we could do get_pages() to get pages is there any function like get_nav_menu().??
    Reply to this comment
    • avatar
      nicolas wrote this comment on June 21, 2010, 5:27 p.m.
      <code>wp_nav_menu()</code> can return instead of printing. If you'd rather get some data structures, a quick look at the <a href="http://xref.yoast.com/trunk/nav.html?_functions/wp_nav_menu.html" rel="nofollow">source</a> seems to indicate that one of the <code>wp_get_nav_menu*()</code> could do what you want.
      Reply to this comment
  • avatar
    John Crumpton wrote this comment on June 30, 2010, 9:39 a.m.
    add_theme_support( 'nav-menus' ); has changed to add_theme_support( 'menus' );
    Reply to this comment
    • avatar
      nicolas wrote this comment on June 30, 2010, 10:36 a.m.
      Thanks John! Looks like this has changed before the 3.0 release. I updated the article. nav-menus still works but it apparently has been removed from the docs.
      Reply to this comment
  • avatar
    LoneWolf wrote this comment on July 3, 2010, 1:36 p.m.
    Do you have links to a better description of add_theme_support () -- i.e. information about where this actually is useful? Can we add our own functionality in here? For example, could a plugin define something and then check to see if the theme supports it? Also, using register_nav_menu () or register_nav_menus () call add_theme_support ('menu') internally.
    Reply to this comment
    • avatar
      nicolas wrote this comment on July 4, 2010, 11:09 a.m.
      The only docs I'm aware of are http://codex.wordpress.org/Function_Reference/add_theme_support and the source of course http://phpxref.ftwr.co.uk/wordpress/nav.html?_functions/add_theme_support.html Looks like it's flexbile at first glance. Thanks for the register_nav_menu() hint!
      Reply to this comment
  • avatar
    holger wrote this comment on July 13, 2010, 8:19 a.m.
    hi, very promessing! especially since i'm planning to call anchors with submenu items (which works in ten twenty). to get it into my theme didn't work yet. i included what you say goes into the functions.php, after that the menu system shows up, but doesn't work, what i create doesn't show up, only the regular pages...? what did i forget? thank you holger
    Reply to this comment
  • avatar
    ian wrote this comment on Aug. 9, 2010, 11:26 a.m.
    Thanks Nicolas. It worked great for me ... "straight out of the tin" and just what I was looking for. I was able to add a 2nd menu to the theme I was using in moments! I really appreciate the info! Ian
    Reply to this comment
  • avatar
    matt wrote this comment on Aug. 10, 2010, 1:01 a.m.
    Why won't it work to simply have the wp_page_menu call after the else rather than a new function? I gave it a try and it doesn't work. Can anyone shed light on this for me? Thanks...
    Reply to this comment
  • avatar
    schumi1331 wrote this comment on Sept. 23, 2010, 5:11 p.m.
    the first tutorial (of three) that worked... :)
    Reply to this comment
  • avatar
    Vaseem Ansari wrote this comment on Feb. 4, 2011, 2:46 p.m.
    Hello Dear i read your blog, its really nice i have a query and i know that you know the answer of this i am using wp nav menu to show 6 navigation menu in header here http:// showprojects.net/projects/csrc/ Now i want when user clicks on any item(post,page,category,tag) in sub menu then the left sidebar will show all the submenus of that parent. My question is similar to this thread http://wordpress.stackexchange.com/questions/2802/display-a-only-a-portion-of-the-menu-tree-using-wp-nav-menu Explaination Root Menu Sub menu 1 Sub menu 2 (clicked) My sidebar will show only child sub menus of clicked root menu Sub menu 1 Sub menu 2 (clicked) Waiting for your answer. Thanks Vaseem Ansari
    Reply to this comment
    • avatar
      nicolas wrote this comment on Feb. 5, 2011, 9:13 p.m.
      Hello Vaseem, If you need general wordpress support I'd recommend you check out http://wordpress.org/support/ or http://codex.wordpress.org/IRC
      Reply to this comment
  • avatar
    Matt wrote this comment on Feb. 10, 2011, 1:23 p.m.
    Do you have any ideas why my wp nav function will not accept parameters? I don't think it has anything to do with your function because even if I add it directly to the header.php without worrying about backwards compatibility it doesn't like the arguments. Have you heard of any such things happening? Thank you
    Reply to this comment
    • avatar
      nicolas wrote this comment on Feb. 10, 2011, 2:01 p.m.
      I'd guess that you haven't defined the nav menu in the admin properly and that wordpress falls back to listing pages.
      Reply to this comment
  • avatar
    shawn wrote this comment on Feb. 10, 2011, 10:02 p.m.
    One way to adjust so not have to list separate classes for container in wp_nav_menu and wp_page_menu is this: <code> function mytheme_fallback() { $output = '&lt;nav class="pagemenu"&gt;'; $output .= wp_page_menu('show_home=Start'); $output .= '&lt;/nav&gt;'; echo $output; }
    Reply to this comment

Start a new thread

Cancel reply
Markdown. Syntax highlighting with <code lang="php"><?php echo "Hello, world!"; ?></code> etc.