Practical Theme Support For WordPress 3.0 Menus

I’ve read quite a few articles on theme support for the new Menu functionality introduced in WordPress 3.0. However, these have all been theoretical rather than practical. I wanted a real life, working example, including support for users on older versions of WordPress. In the end, I wrote it myself.

WordPress Theme developers, listen up! When updating your themes to work with the new menu functionality, you need to make sure that it still works with older versions of WordPress.

Scope

I’m not going to delve into all the different options you can use when adding support for menus. There are enough articles out there that cover this in depth: I highly recommend you read Justin Tadlock’s excellent Goodbye, headaches. Hello, menus!.

Instead, I’m going to focus on the things missing from most articles, such as adding support for users on older versions and including support for static pages in the fallback menu. If you write themes that are used by other people, you need to include these.

Functions.php

First, this is the code to add to the functions.php file. I’ll explain it below.

// add menu support and fallback menu if menu doesn't exist
add_action('init', 'sjc_register_menu');
function sjc_register_menu() {
	if (function_exists('register_nav_menu')) {
		register_nav_menu('sjc-main-menu', __('Main Menu'));
	}
}
function sjc_default_menu() {
	echo '<ul>';
	if ('page' != get_option('show_on_front')) {
		echo '<li><a href="'. get_option('home') . '/">Home</a></li>';
	}
	wp_list_pages('title_li='); 
	echo '</ul>';
}

Check If register_nav_menu Exists Before Calling It

On line 2, we add an action to call a function (from line 3 to 7). The purpose of this function is to register the menu via the register_nav_menu function.

Most tutorials out there focus on how to use register_nav_menu (line 5). Fair enough, it’s new and we’re all interested in how to use it. However, I want you to notice line 4:

if (function_exists('register_nav_menu'))

Surprisingly, most tutorials leave this out. No problem if your theme will only ever run on WordPress 3.0. However, if you have users on an older version of WordPress, your theme will crash and burn if you leave this out. Visitors will be greeted with the following error:

Fatal error: Call to undefined function register_nav_menu() ...

Not cool.

The Fall Back Menu Catering For Static Pages

Lines 8 to 15 contain a function that provides a fall back menu that is used if the user has not added a menu via the new interface. The code for the fall back menu is pretty standard stuff. I’m sure someone will point out that I could use wp_nav_menu, but we’ll call the fall back menu directly for older versions of WordPress (see below) and wp_nav_menu only exists in 3.0 and above.

It’s worth noting the IF statement on line 10, wrapping the Home link. This says to only create the Home link IF the site is NOT using a static home page. If it is, then the Home link will not be created. Why? Without this, the Home page option will appear twice in the menu (if users have a static home page).

There are other ways of dealing with this, but my way seems simplest to me.

Note: To get the static home page to appear first, the user can adjust the Page Order of the static page in the Edit screen. The easiest way to ensure that it appears before other pages, apart from editing the Page Order of all the other pages, is to simply set it to -1.

Header.php

Moving on to header.php, we add the following code where we want the menu to appear:

<div id="nav">
	<?php 
	if (function_exists('wp_nav_menu')) { 
		wp_nav_menu(array('theme_location' => 'sjc-main-menu', 'fallback_cb' => 'sjc_default_menu')); 
	}
	else {
		sjc_default_menu();
	}
	?>
</div>

Call The Fallback Menu Function Directly For Pre WordPress 3.0

The menu is called via the wp_nav_menu function (see line 4 above). This function is what the other articles all focus on. Once again, fair enough, this is a new function that can give us access to the cool new menus. But note the IF statement in line 3:

if (function_exists('wp_nav_menu'))

Leave this out and anyone using your theme on versions of WordPress older than 3.0 is going to be serving the following up to their visitors:

Fatal error: Call to undefined function wp_nav_menu()

Checking that the wp_nav_menu exists is obviously essential, unless you are certain that your theme will only ever run on WordPress 3.0 or above.

But what do we do if wp_nav_menu doesn’t exist (ie the user is on an older version of WordPress)? Should we serve up the original code that we originally used to create the menu pre WordPress 3.0?

Well, we’ve already moved our old code into the fall back menu function. There’s nothing to stop us from calling the fall back menu function directly (line 7) assuming it doesn’t use wp_nav_menu. Simple! And good reuse of code.

As you can see the menu is wrapped in a div element with an id of “nav”. This is entirely optional, depending on how you choose to implement your CSS. An unordered list will be created by the PHP code. You may want to add a class directly to the ul element, instead of including the div. You can do this using the menu_class parameter in line 4 above.

Final Thoughts

WordPress Theme developers, what have you done to ensure menu support for your users on older versions of WordPress? Is your approach different from mine? Can you see a better way of doing this?

I’d love to hear from you in the comments.

7 responses on “Practical Theme Support For WordPress 3.0 Menus

  1. Anonymous

    While I appreciate the work you have put in creating this article I can’t say I agree with backward compatibility approach to developing in general.

    The whole backward compatibility thing has always puzzled me as I feel it drains forwards momentum and wastes time supporting old or outdated technologies instead of that time being better spent on innovation.

    My car is not backwards compatible with a horse and nor should it be.

    In my opinion new themes should take full advantage of all the new features available and encourage users to upgrade to the latest version if they want to use them.

    Drive technology forwards at all levels.

    1. Stephen Cronin

      Hi Martin,

      I hear what you’re saying, but there’s a basic level of support that’s necessary.

      Say my theme has been downloaded by 10,000 users. If I release an update that only works with the latest version of WordPress (which in this case is only a week old), then I’m bound to get some customers who upgrade the theme before they update WordPress (no matter what I say). I’m asking for trouble.

      Now say that this is a commercial theme and the users have paid for it. Is it okay for that theme to not work for them if they choose to stay on the last version of WordPress?

      If my theme is used by other people, especially if they’ve paid for it, then I have a duty to make it degrade gracefully, rather than just dying.

      Okay, there’s no need for me to support really old versions, but I should support the version which was the latest until a week ago.

      Note I don’t actually have a theme that I’ve released, but I’ve been working on a suite of themes for a client who does have many paying customers using them.

  2. Anonymous

    I forgot to add this…..I like your policy on comments. So many times the comment is not relevant to the discussion and smacks of spammy behavior. Kind of like this one ;)

  3. James Morrison

    I don’t understand why people would need “backwards compatibility” for WordPress. If you’re not running the latest version (currently 3.0) you should be upgrading now.

    Have a look at header.php in Twenty Ten (the theme that ship with WP 3.0). Do you see “backwards compatibility” for menus?? NO.

    It runs along the same lines as people who use (whether by their own choice or not) older versions of web browsers such as IE6 / IE7 etc. and wonder why sites that are build using standards compliant methods don’t “look right”.

    Forget adding conditional coding to add “old style” menus, why not give them a message that they should be upgrading? This would avoid the fatal error which most users won’t understand and explain what they need to do next.

  4. Martin

    Haha, I can’t help but to laugh at Anonymous’ comment: “My car is not backwards compatible with a horse and nor should it be.”
    But he actually does have a point. Some technical so called solutions might come in handy from time to time, but if it steels competence from innovation in itself, and the discovery of new, greater communication ways for example – then it is not worth the time of day.
    Good post thought, thanks a bunch!

  5. Steve Hippel

    Very helpful to me as I have just started using WordPress rather a lot.
    As a web developer, I’m finding that it’s better to give many of my low budget clients a cheap deal on design and concentrate the budget on SEO and development.

    WordPress is just ideal for a lot of them and it’s flexibility leaves the door open for design to be implemented later.

  6. nomadone

    Hi Thanks for the tutorials, we’re definitely missing a few pieces in terms of the full explanation of what to consider when using custom menus in public release themes.

    My question about your exmaple, and many other examples is this.

    Is add_action(‘init’, ‘sjc_register_menu’); absolutely necessary? Can we just stick with the if statement part solo? What kind of problems would we encounter?

    Also is it not enough to have an if statement in the placement code which then defaults to a plain wp_list_pages code instead of including it into the functions as well.

    I’m just trying to understanding exactly why you’ve decided to include those parts. So many different ways to skin this specific cat

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Anti-Spam Quiz: