Adding Navigation Menu support to a WordPress theme

Adding Navigation Menu support to a WordPress theme

Register Menus

Firstly, in your theme’s functions.php, you need to write a function to register the names of your menus. (This is how they will appear in the Appearance -> Menus admin screen.) As an example, this menu would appear in the “Theme Locations” box as “Header Menu”.

function register_my_menu() {
  register_nav_menu('header-menu',__( 'Header Menu' ));
}
add_action( 'init', 'register_my_menu' );

And this would make two menu options appear, header menu and extra menu –

function register_my_menus() {
  register_nav_menus(
    array(
      'header-menu' => __( 'Header Menu' ),
      'extra-menu' => __( 'Extra Menu' )
    )
  );
}
add_action( 'init', 'register_my_menus' );

Display Menus on Theme

Once you’ve done that, your theme will be almost ready. The last preparation step is to tell the theme where you want the menus to show up. You do this in the relevant theme file. So, for example, we might want our header menu to be in header.php. So open up that file in the theme editor, and decide where you want to put your menu. The code to use here is wp_nav_menu which we will need once for each menu location. So, add this code –

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

All you need to ensure is that the theme_location points to the name you provided for your menu in the functions.php code above. (Note that it’s the header-menu being used here rather than Header Menu without a hyphen. header-menu is the name that the code understands, Header Menu is the human-readable version that you see in the admin page.)

To complete the code, you can put your extra menu someplace else. Maybe you want a menu on one of your pages, for example, and you might even want it to be jazzed up a little with a containing DIV of a certain class –

wp_nav_menu( array( 'theme_location' => 'extra-menu', 'container_class' => 'my_extra_menu_class' ) );

So you’d put the above into your Page template, and not only would the menu show up wherever you put it, it’d be styled as my_extra_menu_class so that you can work with that in CSS.

Menus Panel

That’s all the background work. To finish, you would simply visit the Appearance -> Menus panel in your site admin. Now, instead of seeing some text suggesting that your theme doesn’t natively support menus, you’ll see some Theme Location options.

You can now use the GUI menu creator on this admin panel to put your menu(s) together. Give them each a name, and then assign a menu to a location with the pull-down options.

(You will see your new navigation choices when you Add a New Menu.).

 

1. Specifying menu locations in your theme

First, define where you want menus to appear in your theme. Most themes define at least a “Top Navigation” location. Some define “Secondary” and “Footer” locations, as well. These menu location names appear in the “Theme Locations” panel of the “Appearance > Menus” screen, and allow you to later choose which menu content goes in each menu location.

How to add only one location

In your theme’s “functions.php” file, add the following at the bottom.

// This adds just one menu location
add_action( 'init', 'paukai_register_menu' );
function paukai_register_menu() {
    if ( function_exists( 'register_nav_menu' ) ) {
        register_nav_menu( 'header-nav', 'Header Navigation' );
    }
} // end paukai_register_menu()

That tells WordPress you want to use a menu location in one spot. The values passed here are:

  • “header-nav” — the menu location slug you can use behind the scenes
  • “Header Navigation” — the human-readable name describing this location on the Appearance > Menus screen

How to add multiple menu locations

WordPress Menus-Screenshot of Theme Location panel in dashboard

Before moving on with my friend’s site, I figured I should add a second menu location. I didn’t want to be caught unprepared again. There’s always the possibility she might want another menu placed in the footer. To add more than one menu location, change your code to the following. This is used instead of the code above–not in addition to it.

// This adds more than one menu location
add_action( 'init', 'paukai_register_multiple_menus' );
function paukai_register_multiple_menus() {
    register_nav_menus(
        array(
            'header-nav' =>  'Header Navigation',
            'footer-nav' =>  'Footer Navigation'
        )
    );
}

This function “register_nav_menus” takes an array of location slug / description pairs. Save these changes to “functions.php”, reload the “Appearance > Menus” screen, and you should see two menu locations listed.

2. Calling menus in your theme template

Next, you need to update your WordPress theme template files to request these menu locations and put their assigned menus in the places you want them to appear.

Add the header navigation

The header navigation menu–intended to be the global navigation for my friend’s site–would need called in the “header.php” file. You need to find the spot in “header.php” where the current menu method is used so you can replace it.

In the Elegant Grunge header.php file, I found:

<div id="menu">
    <ul>
        <li><a href="<?php bloginfo('url'); ?>"><?php _e('Home', 'elegant-grunge') ?></a></li>
        <?php wp_list_pages('title_li=&depth=1'); ?>
    </ul>
    <div class="clear"></div><!-- clearing div -->
</div>

In most older themes, you’ll find something similar. The function “wp_list_pages” was very commonly used in themes before the new navigation menus came around. For my situation, I replaced all that code with the following:

<div id="menu">
    <?php
    wp_nav_menu (
        array (
            'theme_location' => 'header-nav',
            'container' => false
        )
    );
    ?>
    <div class="clear"></div><!-- clearing div -->
</div><!-- /#menu -->

The “wp_nav_menu” function takes an array of key > value pairs. The two important ones here:

  • “theme_location”–the location slug we used when registering the menu we intend to place here
  • “container”–set to false so WordPress would not automatically wrap the entire menu in a container.
Once you get the hang of this simple tutorial, check out the wp_nav_menus page in the WordPress Codex to see the other optional parameters.

Understanding the “container” parameter

Wait–why did I set “container” to false? After all, the menu is indeed wrapped in a “div#menu,” and I could have the “wp_nav_menu” function do that for us.

At issue here is the clearing DIV just before closing the “div#menu.” If I let WordPress create the “div#menu,” I would not have an opportunity to add that clearing DIV before WordPress closed the “div#menu.” So, I had to open and close the container — “div#menu” — myself.

Featured Plugin – WordPress Google Maps Plugin

Simply insert google maps into posts, sidebars and pages – show directions, streetview, provide image overlays and do it all from a simple button and comprehensive widget.

Find out more

Add the footer navigation

Since I also added “Footer Navigation” to the “Theme Locations” panel, I should include it somewhere in my template files–even if my friend doesn’t plan to use it yet. For Elegant Grunge, I edited the “footer.php” file to add this menu location in. The theme has a widget sidebar in the footer, followed by a clearing DIV. I decided to put the footer menu code after that clearing div.

I edited the “footer.php” file  to read as such:

<?php get_sidebar('footer'); ?>
<div class="clear"></div>
<?php
    // begin modifications to add footer menu
    wp_nav_menu (
        array (
            'theme_location' => 'footer-nav',
            'container_id' => 'footer-menu'
        ) );
?>
<div class="clear"></div>
<?php
    // end modifications to add footer menu
?>
<div class="legal"><?php echo get_option("copyright"); ?></div>

I told “wp_nav_menu” to use the menu referenced by the slug “footer-nav,” which we registered before. There was no menu at all in the footer before I came along, so this time I wanted WordPress to wrap the menu in a container DIV (the default) and to give that DIV an ID of “footer-menu” so we could target it with CSS and such.

Preventing output if no menu is assigned

The problem here is the lack of any menu assigned to the footer-nav menu location. If I don’t have any menu assigned to the footer-nav menu location, WordPress will pick up the first menu it can find and sub it in. What I need to do is check to see if footer-nav has a menu assigned to it, and only output menu code if there is a menu.

After adding this conditional test for menu assignment, the code change became:

<?php get_sidebar('footer'); ?>
<div class="clear"></div>
    <?php
    // begin modifications to add footer menu
    if ( has_nav_menu( 'footer-nav' ) ) {
    // a menu is assigned to the footer-nav location
    wp_nav_menu (
        array (
            'theme_location' => 'footer-nav',
            'container_id' => 'footer-menu'
        )
    );
    ?>
<div class="clear"></div>
<?php
} // end if
// end modifications to add footer menu
?>
<div class="legal"><?php echo get_option("copyright"); ?></div>

Building the contents of menus to hook in

WordPress Menus-Screenshot of Menus Theme Location panel with first menu assignedTo check my work, I needed to create a menu using the “Appearance > Menus” interface and hook it up to the new menu locations. I added a menu name of “Global Navigation,” clicked “Save Menu,” and then added a number of pages in primary, secondary, and tertiary positions.

Once I did this, I was able to select “Global Navigation” for our “Header Navigation” menu in the “Theme Locations” panel. I reloaded the page to see what we would get.

WordPress Menu-Screenshot of header menu without proper CSSThe results were not encouraging! My menu items were all stacked vertically, and this messed up the site’s logo and tagline, as well. So much for a simple, quick site, right?

I didn’t panic, though, as I knew right away some simple CSS changes would fix things up. This is the kind of hassle we used to deal with all the time before WordPress added the navigation menus. I decided to copy the CSS rules from the 2011 theme and modify them to meet my needs.

Styling menus for proper display

To make your new menus display properly, you need to add some rules in your “style.css” file. For Elegant Grunge, I copied the styles from Twenty Eleven theme first, then modified from there.

The menu container element

The Twenty Eleven theme uses an ID of “access” on the menu’s containing element. In the Elegant Grunge theme, the menu’s containing element is “#menu,” so in the style rules I change “#access” to “#menu” in all spots.

Combining two different styles

As soon as I made the “#access” to “#menu” change in the style rules, the menu looked a lot better. However, it was tucked way up in the upper left corner instead of under the site logo and such. I had a look at Elegant Grunge’s original style rules for #menu to see what was the matter.

Theme authors can position elements in a variety of ways. When combining styles from two different themes, you need to look at differences between positioning and sizing declarations. Key properties to compare and combine are:

  • position / top / bottom / left / right
  • width / height
  • padding / margin
  • float / clear
  • display

In my case, I needed to comment out some of the Twenty Eleven styles on #menu and #menu ul, then add in a few of the elements as Elegant Grunge originally styled them. That’s all explained in the following downloadable CSS snippet.

Note: The downloadable is an excerpt of the hybrid Elegant Grunge / Twenty Eleven style.css file, reflecting changed styles to make the dropdown menu work.

The downloaded style file makes it all work nicely. Experiment with the CSS from there to get different looks. Current page highlighting and other effects are possible, purely in CSS.

Adding Custom Classes per Menu Item

Sometimes menus can get pretty crowded. You’ve probably seen some horizontal menus that could stand some trimming. With our current styles, a menu near the right side of our page will open further to the right and potentially off screen. If you have this problem, you can fix it by adding a special class for those right-most menu items.

Advanced menu options

On the Appearance > Menus screen, click the “Screen Options” tab near the top. When this pops down, put a check in the option for “CSS Classes.”

WordPress Menu-Screenshot of Menu screen options panel

Assigning special classes to menu items

WordPress Menu-Screenshot of menu item with additional custom class fieldNow, click the disclosure triangle for any menu item. You’ll see a “CSS Classes” field you can optionally fill in. If you have menu items that open too far to the right, try this:

  1. Add the class “leftlevel3.” My intention was to make 3rd-level dropdowns open to the left of their parent menu instead of the right.
  2. In your style file, add a suitable class and declarations. You will need to experiment to get the right placement. For my Elegant Grunge theme, I added the following:
 /* special class manually applied to open submenu left */
 .leftlevel3 {
     right:375px;
 }

Note the more correct way of positioning the entire 3rd-level dropdown would be to position the <ul> element containing all those 3rd-level list items. Unfortunately, we cannot add classes to the <ul> itself in the Menus interface.

Menus the way they should be

If you followed all that, you should end up with WordPress Navigation Menus available for use–even in your older themes. The styling might take a bit of debugging, depending on how well the CSS was coded in your original theme. Just think, though: once you get it working the way you like, you won’t have to worry about again! You or your clients can simply use the Appearance > Menu screen to easily make menu changes.

Credits