I've created a menu using wp_nav_menu in my theme using the most simple setup as possible:

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

And in my functions.php:

register_nav_menus(
    array('my_theme_top_menu' => 'Top Menu' )
);

However, I'm running into strange behaviour when the user creates a menu in wp-admin and assigns it to this menu. When you first select the theme, it defaults to the default menu built from pages, the markup looks like this:

<div class="menu">
    <ul>
       <li class="page_item page-item-51">
           <a href="http://www.mdunham.co.uk/bligs/">About Us</a>

But, if a user selects one of their pre-defined menus the markup that builds the menu completely changes:

 <div class="menu-main-menu-container">
    <ul id="menu-main-menu" class="menu">
           <li id="menu-item-102" class="menu-item menu-item-type-post_type menu-item-object-page current-menu-item page_item page-item-29 current_page_item menu-item-102">
               <a href="http://www.site.co.uk/">Home</a></li>

Why is this happening? It's like when uses a defined menu WP menu it WP defaults(or settings I've defined), yet when there is no defined menu and it falls back it uses a different, bastardized set of options which I haven't actually set anywhere myself.

link|improve this question

Is that the right way round? Looks like the top one is the actual menu assigned via admin and the bottom one is the wp_list_pages fallback. – sanchothefat Oct 26 '11 at 9:35
Ah yeah you're right, the underlying point still stands though. Are you aware of a work around for this? I am thinking a custom callback function to emulate wp_nav_menu with the default list of pages. – Dunhamzzz Oct 26 '11 at 9:49
To be honest I typically put in a custom callback that checks if a user is logged in with menu editing capability and show a link to the menus admin page to choose a menu. Alternatively copy the wp_list_pages() function and change the markup it generates. – sanchothefat Oct 26 '11 at 9:55
feedback

1 Answer

up vote 1 down vote accepted

Here's the default usage of wp_nav_menu():

<?php 
$defaults = array(
  'theme_location'  => ,
  'menu'            => , 
  'container'       => 'div', 
  'container_class' => 'menu-{menu slug}-container', 
  'container_id'    => ,
  'menu_class'      => 'menu', 
  'menu_id'         => ,
  'echo'            => true,
  'fallback_cb'     => 'wp_page_menu',
  'before'          => ,
  'after'           => ,
  'link_before'     => ,
  'link_after'      => ,
  'items_wrap'      => '<ul id=\"%1$s\" class=\"%2$s\">%3$s</ul>',
  'depth'           => 0,
  'walker'          => 
);
?>

Notice that the default fallback for wp_nav_menu() is wp_page_menu(), for which the defaults are:

<?php 
$args = array(
'sort_column' => 'menu_order, post_title',
'menu_class'  => 'menu',
'include'     => '',
'exclude'     => '',
'echo'        => true,
'show_home'   => false,
'link_before' => '',
'link_after'  => '' 
);
?>

These should produce mostly the same output, with the same set of pages. However, if you need more specific control, you have a couple options:

  1. Assign a custom callback here:

    'fallback_cb' => 'mytheme_wp_nav_menu_cb'

    ...and then, define:

      function mytheme_wp_nav_menu_cb() {
          // Output whatever menu you want here
      }
    

    ...so that you override wp_page_menu()

  2. Wrap your wp_nav_menu() call in a has_nav_menu() conditional:

    if ( has_nav_menu( 'my_theme_top_menu' ) ) {
        // User has applied a custom menu
        // to the my_theme_top_menu location;
        // output it
        wp_nav_menu( array( 'theme_location' => 'my_theme_top_menu') );
    } else {
        // User has NOT applied a custom menu;
        // Do something else
    }
    

    ...in the else statement, you can do whatever.

link|improve this answer
Thanks Chip, I see you've ran into this before! – Dunhamzzz Oct 28 '11 at 8:30
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.