Arguments ignored/markup changed in wp_nav_menu if no menu is selected

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:

Read More
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.

Related posts

Leave a Reply

1 comment

  1. 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.