In this post I’m going to show you how to take WordPress Menu Editing to the next level. You’re going to learn how to use Primary and Secondary menus in your WordPress theme; Add descriptive sub-title links to your menu items like some popular WordPress themes and sites; Filter the menu of a WordPress theme; Add special CSS classes to wp_page_menu; and finally, how to hand-code your own WordPress menu for the ultimate in control.
Here’s how to make your WordPress menu jump through hoops.
Primary and Secondary Menus
This one’s really easy with wp_page_menu. Instead of adding it once to our theme, we’ll add it twice!—but including only select pages each time.
-
<?php wp_page_menu('exclude=24,27,28&menu_class=menu menu-primary'); ?>
-
<?php wp_page_menu('include=24,27,28&menu_class=menu menu-secondary'); ?>
Because wp_page_menu generates all the code we’ll need for a menu we simply have to exclude pages from the first menu and include some in the other. With new menu classes of menu-primary and menu-secondary we’re all set.
Here’s how to do it with a Thematic Child Theme—or any in any Child Theme where the parent theme is using wp_page_menu. Also easy, but with wp_list_pages so we can avoid any CSS styling problems with multiple drop down menus. Just use this code snippet in your Child Theme functions file.
-
// Remove the default Thematic Access
-
function remove_thematic_actions() {
-
remove_action('thematic_header','thematic_access',9);
-
}
-
add_action('init','remove_thematic_actions');
-
-
// Recreate the Thematic Access with menu-primary and menu-secondary
-
function childtheme_page_menu() { ?>
-
<div id="access">
-
<div class="skip-link"><a href="#content" title="<?php _e('Skip navigation to the content', 'thematic'); ?>"><?php _e('Skip to content', 'thematic'); ?></a></div>
-
<?php wp_page_menu('exclude=24,27,28&menu_class=menu menu-primary'); ?>
-
<div class="menu menu-secondary">
-
<ul>
-
<?php wp_list_pages('title_li=&include=24,27,28'); ?>
-
</ul>
-
</div>
-
</div><!– #access –>
-
<?php }
-
add_action('thematic_header','childtheme_page_menu','9');
Adding Sub-Titles To Menu Links
Sometimes you’re going to want to add descriptive text underneath your WordPress menu links like in the Grid Focus theme,

or like you’ve seen around the web on static, and non-WordPress sites.

Usually this is done by hand editing the menu but it can be accomplished using WordPress custom fields. Simply add a custom field to the pages in question named “subtitle” with a value of “whatever you want your descriptive subtitle text to be”. Then make sure you have the following code snippet (adapted from the clearskys.net blog ) in the functions file of your WordPress Child Theme—as long as the parent theme is using wp_page_menu. If you’re simply editing a WordPress theme directly, cut the code from the childtheme_page_menu function and use it to replace your existing menu in header.php.
-
// Adds descriptive text to link titles
-
// With help from http://blog.clearskys.net/2008/12/17/how-to-adding-menu-sub-titles-to-a-theme/
-
function sub_page_list() {
-
global $wpdb;
-
$sql = "SELECT p.ID, p.post_title, p.guid, pm.meta_value FROM " . $wpdb->posts . " AS p LEFT JOIN ";
-
$sql .= "(SELECT post_id, meta_value FROM " . $wpdb->postmeta . " AS ipm WHERE meta_key = 'subtitle') ";
-
$sql .= "AS pm ON p.ID = pm.post_id ";
-
$sql .= "WHERE p.post_type = 'page' AND p.post_parent = 0 AND p.post_status = 'publish' ";
-
$sql .= "ORDER BY p.menu_order ASC ";
-
$sql .= "LIMIT 0, 10";
-
$rows = $wpdb->get_results($sql,OBJECT);
-
if($rows) {
-
foreach($rows as $row) {
-
echo "<li>";
-
$link_url = get_permalink($row->ID);
-
echo "<a href=\"$link_url\"" . "\">$row->post_title</a>";
-
echo "<span style=\"display:block;\">$row->meta_value</span>";
-
echo "</li>";
-
}
-
}
-
}
-
-
// Filter the menu to add the list
-
function childtheme_page_menu() { ?>
-
<div class="menu">
-
<ul>
-
<?php if (is_front_page()) { ?>
-
<li><a href="<?php bloginfo('home') ?>/" title="<?php echo wp_specialchars( get_bloginfo('name'), 1 ) ?>" rel="home">
-
Home <span style="display:block;">This is the home page</span>
-
</a></li>
-
<?php } else { ?>
-
<li><a href="<?php bloginfo('home') ?>/" title="<?php echo wp_specialchars( get_bloginfo('name'), 1 ) ?>" rel="home">
-
Home <span style="display:block;">Return to the home page</span>
-
</a></li>
-
<?php } ?>
-
-
<?php sub_page_list(); ?>
-
-
</ul>
-
</div>
-
<?php }
-
add_filter('wp_page_menu','childtheme_page_menu');
Adding Class To Your Menu List
One of the problems of using wp_page_menu is that the HTML is all wrapped in the function. You can’t get at it. Which is a pain if you want to use the function but also want to add special classes for implementing javascript drop-down menus or do some trickier CSS without giving yourself a headache. Luckily, you can filter it. Here’s how to filter wp_page_menu and add a unique class to the first instance of the ul tag, using PHP’s preg_replace to find the first ul tag and adding in id and class attributes.
-
// Add ID and CLASS attributes to the first <ul> occurence in wp_page_menu
-
function add_menuclass($ulclass) {
-
return preg_replace('/<ul>/', '<ul id="nav" class="something-classy">', $ulclass, 1);
-
}
-
add_filter('wp_page_menu','add_menuclass');
Basically, wp_page_menu can be filtered with any content (I often use “bacon” as test content—mmm, bacon) which is handy to know if you ever want to code your own custom menu.
Hand Coding a Dynamic WordPress Menu
And sometimes you are going to want to code your own menu. I’ve done it and I’ll probably do it again. You could just create a simple list of links but it’s better to create a dynamic list that checks to see if you’re currently on a particular page and adds a class of current_page_item to the list item if you are. This’ll let you create more usable menus with a little bit of CSS.
If you’re doing this in a Child Theme and the Parent Theme is using wp_page_menu this’ll be pretty straight forward, we’re just going to filter wp_page_menu. And if you’re editing your theme directly just grab the code out of the function in this snippet and plop it into the appropriate spot of your theme.
-
function childtheme_menu() { ?>
-
<div id="menu">
-
<ul>
-
<li class="<?php if ( is_page('about') ) { ?>current_page_item<?php } else { ?>page_item<?php } ?>"><a href="<?php echo get_option('home') ?>/about/" title="About This Blog">About</a></li>
-
<li class="<?php if ( is_page('advertising') ) { ?>current_page_item<?php } else { ?>page_item<?php } ?>"><a href="<?php echo get_option('home') ?>/advertising/" title="Advertise on My Blog">Advertise</a></li>
-
<li class="<?php if ( is_page('contact') ) { ?>current_page_item<?php } else { ?>page_item<?php } ?>"><a href="<?php echo get_option('home') ?>/contact/" title="Contact Me">Contact</a></li>
-
</ul>
-
</div>
-
-
<?php }
-
-
add_filter( 'wp_page_menu', 'childtheme_menu' );
The key in this example is what’s happening in the list items between the li tags. If you look at line 4 you’ll see we’re checking to see if we’re on the about page, and if we are we get a class of current_page_item, otherwise, page_item. Simple!
28 Comments
Probably the most interesting tip is how to add the link descriptions in the menu. That always looks cool (if done right)
Thank you for the tricks. I’ll definitely use this for my projects.
Something to add to make it more complete is how to filter the list and add nofollow to all, or even specific links based upon an array, which can then be done conditionally based upon page type.
Great article Ian, very useful and “catchy”!
Great blog! I love the formatting tweaks that really help a site to stand out while making it easier to update.
Just a quick FYI: The email version of the blogs do not wrap the text properly. Could be the header/footer image width, or a fixed width encoded somewhere.
Best wises!
Thematic is a great theme. I’ve just posted an article on my blog about customizing the menu, starting from Justin Tadlock interesting solution (not for thematic).
The article is in italian but I’ve tried to arrange a short translation in english.
The code I wrote / adapted can be changed to add the sub-title as shown in your article, using link description.
Thanks for posting this. Just to let you know, the code for “Adding Sub-Titles To Menu Links” produces a small bug. Line 16:
echo "$row->post_title";
produces double quotes after the URL (which invalidates XHTML), something like this:
About UsCompany History
Also, the title attribute is only preserved for the “Home” link. How would I modify the code so that it displays the title attribute for the other links as well?
Thanks!
Great post! I was just thinking of a way to solve sub-titles in menus for Wordpress and got really happy when I found your example.
Getting rather attached to the Simple Sidebar Navigation plugin:
http://www.ibsteam.net/blog/web-development/simple-sidebar-navigation-plugin-wordpress
Has the makings of a rather flexible navigation plugin project.
Definitely prefer it to the (now defunct) NAVT plugin.
Do you think that this kind of plugin-based solution is tenable for robust navigation?
Great tips!
I also noticed the double quotes in Adding Sub-Titles To Menu Links that Daniel mentioned. Here’s how I fixed it, and also how I modified the
element. I wanted theas part of the link element for styling purposes, and I also moved the"display:block"declaration and put it into the style rule. Here’s my tweaked version, lines 16-17:echo "$row->post_title";
echo "$row->meta_value";
Somehow my code snipped got messed up. I’ll try again:
echo "$row->post_title";echo "$row->meta_value";
Darn! Not working! How do we post code snippets in comments?
I found that the code in Adding Sub-Titles To Menu Links seems to be incompatible with the Exclude Pages Plugin.
Thanks, useful. But I think I find it easier to do menus with a custom loop and designated custom fields indicating the menu level and additional menu content, like images, for a graphic menu. The Flutter-plugin is occasionally helpful here. It’s easier to change around in page-management than in the theme. After all, you’re still excluding and including pages in the theme, not in the backend.
would like to have a look at your custom loop solution if you don’t mind sharing? Any links to code?
@ts would like to have a look at your custom loop solution if you don’t mind sharing? Any links to code?
Oh cool, I’ve been scouring the web looking for a wordpressified hack to achieve this. I reckon it’s a plugin which would get some real attention should anyone develop something, hint hint!
I was trying to achieve the same thing using the link_after parameter for wp_list_pages, btu it doesn’t automatically allow a custom field value in the code
Anyone know of something which could solve that?
Aah shucks, seems my understanding of this code is a little too poor to mod it for a normal non-thematic non-child theme.
I also tried the functions.php solution from clearskys btu ended up with blank page.
I’m gonna live with writing sub title in the WordPress title field for now, works ok if u style it correctly. Just means I have to generate my head title using a custom field or something.
I was really hoping to could somehow add a custom field value in span tags within the link_after parameter for wp_list_pages, seems it’s not possible.
Ben fiddling around with a few solutions like this over the last few days. Finally got the clearskys.net function working with the help of @urbanrenewal who modified the code a little.
So no there’s the problem of the dynamic classes, no childpage drop downs & exclude page functionality not working.
Anyone know what can be thrown in between lines 17 & 18 to echo the child page UL for any child pages?
I’ve been fighting with thte sub-titled links too. I’ve been trying to figure out how to put the dynamic classes BACK into the list items but so far no luck. I posted in the forums but still no help there either.
Great work man! I am implementing it for one of my blogs. Thanks a lot
Any ideas how to simply INclude menu items to make a nav bar, instead of EXcluding them?
I want to build a special menu based on certain pages only.
does anyone know how I can add menus at the bottome of my page? I want to add “about us” or “contact us” or “FAQ” at the bottom of the page but I cant seem to figure it out.
appreciate any help I can get.
Thanks.
I have created something based on the sub_page_list function. New one with active class. I’ve even added som extra spice to it, hope you’ll all enjoy: http://jonkristian.no/2009/10/a-smarter-menu-for-wordpress/
Hi All
This rewriting of the menu code causes you to loose the dynamic classes. This makes styling of different menu items difficult. I have a pretty simple plug-in that allows the use of wp_page_menu(). The plug-in is a rewrite of Page Lists Plus to strip out all of the extra code to make this plug-in as simple as possible. It is available on my site if you are interested.
Dave
TheTemplateBlog
Great article , thanks for your help
Is there any way to add current_page_item to sub_page_list(); without hard coded navigation.
I think this is exactly what I need! Thanks!
12 Trackbacks
[...] WordPress Menu Tricks [...]
[...] 1. 40 nuevos temas gratuitos para Wordpress. 2. Social Networking con BuddyPress. 3. Cómo lanzar tu propio tema de Wordpress. 4. 30 temas creados en Marzo de 2009 para Wordpress. 5. Trucos para menús en Wordpress. [...]
[...] idea,欢迎和大家一起分享!!! 本文由辐射鱼翻译自:WordPress Menu Tricks(有删节) 站趣译文:wp_page_menu [...]
[...] Adding drop down’s on the menu for the children [...]
[...] WordPress Menu Tricks [...]
[...] the original template and wanted to integrate it into the WordPress version as well. Thanks to this article from ThemeShaper, I was able to do [...]
[...] Making a Categories Drop-Down Menu 18. Wordpress: “Magazine style” Horizontal dropdown menu 19. WordPress Menu Tricks 20. Creating Two-Tiered Conditional Navigation in [...]
[...] post I found by Shantanu one had to hack classes.php, a WordPress core file, and the second one by Theme Shaper was lacking one very essential thing, the active [...]
[...] the original template and wanted to integrate it into the WordPress version as well. Thanks to this article from ThemeShaper, I was able to do [...]
[...] I knew there had to be a better way so I kept searching. I ran across ThemeShaper and the post WordPress Menu Tricks and it looks like John Kristian took this a step further with his post A Smarter Menu for WordPress [...]
[...] WordPress Menu Tricks [...]
[...] code used to display the image links through custom fields was heavily modified from the WordPress Menu Tricks article at ThemeShaper, take a look at the functions.php file in the theme if you’re [...]