Extend the WordPress Menu
as add_filter, how-to, WordPress, wp_list_categories, wp_list_pages, wp_nav_menu, wp_nav_menu_items, wp_page_menu
I have written several posts regarding the use of the wp_nav_menu() function. I have written about its uses, its implementation, and even an older post regarding (some of) the CSS classes it generates. This post continues with an idea for extending the wp_nav_menu() function by adding additional items to the menu list with code versus the user interface found in the Administration Panels, such as automagically adding a self-propagating list of categories.
This idea is not necessarily new but finding an example may be a bit more difficult. Let’s have a look …
First off, there are several sources of information regarding wp_nav_menu() to take into consideration:
- The WordPress codex reference.
- The “core.trac.wordpress.org” reference.
- This web site’s references.
Each of these links will open in a new tab/window for convenience purposes.
Now that we have a list of reading material we should actually take a look at it …
- The first reference leads to the WordPress codex and provides the standard parameters that can be used with wp_nav_menu().
- The next reference and the experience that was offered by Ian Stewart from ThemeShaper.com is the real key to solving this little puzzle.
- The last reference simply leads to the wp_nav_menu() tag archive here.
I would suggest at least having a quick look at those pages before carrying on to the next page, especially the one referencing the wp_nav_menu() function in the “core”, or primary code base of WordPress, as you will find a very relevant comment there.
Let’s start by focusing on the following code snippet as found in the “core” reference:
// Allow plugins to hook into the menu to add their own <li>'s
$items = apply_filters( 'wp_nav_menu_items', $items, $args );
$items = apply_filters( "wp_nav_menu_{$menu->slug}_items", $items, $args );
$nav_menu .= $items;
The beauty of this little snippet is it shows, with the use of the wp_nav_menu_item filter, you can add specific items to the menu output if the end-user has chosen to create a custom menu. Let’s look at an example that will allow you to add a “Home” page link to the beginning of the menu.
If you add the following to your ‘functions.php’ template file it will add a home link to your wp_nav_menu() output:
// Filter wp_nav_menu() to add additional links and other output
function new_nav_menu_items($items) {
$homelink = '<li class="home"><a href="' . home_url( '/' ) . '">' . __('Home') . '</a></li>';
$items = $homelink . $items;
return $items;
}
add_filter( 'wp_nav_menu_items', 'new_nav_menu_items' );
The basic premise of the function is:
- Assign your desired output to a variable
- Concatenate the output variable with the $items variable
- Return the $items variable so it can be used in the filter
- Add the results of the function to wp_nav_menu_items with an add_filter() function
If you wish to use this when a custom menu is not being used just add the following (or similar) filter after the above code:
add_filter( 'wp_list_pages', 'new_nav_menu_items' );
But what if we wanted to add something to the end of the menu output, such as a RSS feed link, or maybe just some random text or a static URL link. Let’s look at the following example which expands upon the code above to do just that.
// Filter wp_nav_menu() to add additional links and other output
function new_nav_menu_items($items) {
$homelink = '<li class="home"><a href="' . home_url( '/' ) . '">' . __('Home') . '</a></li>';
$feedlink = '<li class="feed"><a href="' . get_bloginfo_rss('rss2_url') . '">' . __('RSS') . '</a></li>';
$random_text = '<li class="rainbows"><a href="#">OMG ... Double Rainbows!</a></li>';
$items = $homelink . $items;
$items = $items . $feedlink;
$items = $items . $random_text;
return $items;
}
add_filter( 'wp_list_pages', 'new_nav_menu_items' );
add_filter( 'wp_nav_menu_items', 'new_nav_menu_items' );
There always seems to be some new way to add more uses to the core functions in WordPress and I like to find, explore and write about them. I often implement them in the First Aid Theme, as I have done by using the above example code to add a “Home” link to the menu. On the next page I will leave you with one more example, the one I referred to in the opening paragraph.
Although this was a bit more involved it really did not make that much of a difference in the case of implementing this in a custom menu so without further ado here is the code snippet:
function new_nav_menu_items($items) {
$cat_menu_list = wp_list_categories( 'echo=0&title_li=&child_of=124' );
$items = $items . $cat_menu_list;
return $items;
}
add_filter( 'wp_nav_menu_items', 'new_nav_menu_items' );
If you are trying this at home make back-ups of your files, just in case you want to revert your edits. Your category list hierarchy may need to be noted as well.
The key to this snippet is the wp_list_categories() by default will echo its results to the screen, you will have to set the parameter ‘echo=0′ to turn off this default behavior.
As for using this technique for categories with a non-custom menu I will leave that as an exercise for those looking for a challenge … Enjoy!
- Share this:
- Share
An Implementation of wp_nav_menu
as register_nav_menu, wp_list_pages, wp_nav_menu
Please note, this might be considered a “Go Big, or Go Home” exercise. Please read this entire post before attempting this at home, or on your own site or theme.
This article will be covering the implementation of the wp_nav_menu() function using the wp_list_pages() function as a fallback. The menu will also be centered and support full drop down sub-menu items, or child pages as some would refer to them … and, the menu system now live on this site, too.
The following code will also be released in the free WordPress Theme Shades at version 1.6, and it will also be the basis for the examples used in this post.
Let’s get started …
What We Need
- wp_list_pages()
- wp_nav_menu()
- register_nav_menu()
- Upgrade wp_list_pages() to wp_nav_menu()
- Shades
- CSS
Have a look at the codex pages above for wp_list_pages(), wp_nav_menu, and register_nav_menu to get (more) familiar with the basics of these functions. As this has to do with the use of wp_list_pages() reading the article “Upgrade wp_list_pages() to wp_nav_menu()” may also prove useful.
Although not absolutely necessary, getting a copy of the Shades theme may be handy if you wish to look at the code directly rather than the examples and snippets to follow.
The last part is the CSS to make it all work. This is from a great article written by Matthew James Taylor and can be found here.
On the next page we will look at what to do …
What We Will Do
First we are going to open the functions.php template file and start with adding the following code:
wp_nav_menu( array( 'theme_location' => 'top-menu', 'fallback_cb' => 'custom_list_pages' ) );
Next we will need to incorporate the fallback menu code via wp_list_pages(), with the following:
function custom_list_pages() {
if ( is_home() || is_front_page() ) { ?>
<ul><?php wp_list_pages( 'title_li=' ); ?></ul>
<?php } else { ?>
<ul>
<li><a href="<?php bloginfo( 'url' ); ?>"><?php _e( 'Home' ); ?></a></li>
<?php wp_list_pages( 'title_li=' ); ?>
</ul>
<?php }
}
Both of these functions will need to be included in the custom function that will be the base of our new menu system. The code looks like this:
function custom_nav_menu() {
if ( function_exists( 'wp_nav_menu' ) )
wp_nav_menu( array(
'theme_location' => 'top-menu',
'fallback_cb' => 'custom_list_pages'
) );
else
custom_list_pages();
}
Then we need to register the custom function and give it a place to live. This code will accomplish that:
add_action( 'init', 'register_custom_menu' );
function register_custom_menu() {
register_nav_menu( 'top-menu', __( 'Top Menu' ) );
}
The heavy lifting is done, now we need to address the actual display of the menu. Let’s open the header.php template file and place the custom function appropriately.
<div id="centeredmenu"> <?php custom_nav_menu(); ?> </div> <!-- #centeredmenu -->
Now for all intent and purpose the CSS from Matthew James Taylor’s post can be dropped into the style.css file, like so:
/* Main menu settings */
#centeredmenu {
clear:both;
float:left;
margin:0;
padding:0;
border-bottom:1px solid #000; /* black line below menu */
width:100%;
font-family:Verdana, Geneva, sans-serif; /* Menu font */
font-size:90%; /* Menu text size */
z-index:1000; /* This makes the dropdown menus appear above the page content below */
position:relative;
}
/* Top menu items */
#centeredmenu ul {
margin:0;
padding:0;
list-style:none;
float:right;
position:relative;
right:50%;
}
#centeredmenu ul li {
margin:0 0 0 1px;
padding:0;
float:left;
position:relative;
left:50%;
top:1px;
}
#centeredmenu ul li a {
display:block;
margin:0;
padding:.6em .5em .4em;
font-size:1em;
line-height:1em;
background:#ddd;
text-decoration:none;
color:#444;
font-weight:bold;
border-bottom:1px solid #000;
}
#centeredmenu ul li.active a {
color:#fff;
background:#000;
}
#centeredmenu ul li a:hover {
background:#36f; /* Top menu items background colour */
color:#fff;
border-bottom:1px solid #03f;
}
#centeredmenu ul li:hover a,
#centeredmenu ul li.hover a { /* This line is required for IE 6 and below */
background:#36f; /* Top menu items background colour */
color:#fff;
border-bottom:1px solid #03f;
}
/* Submenu items */
#centeredmenu ul ul {
display:none; /* Sub menus are hiden by default */
position:absolute;
top:2em;
left:0;
right:auto; /*resets the right:50% on the parent ul */
width:10em; /* width of the drop-down menus */
}
#centeredmenu ul ul li {
left:auto; /*resets the left:50% on the parent li */
margin:0; /* Reset the 1px margin from the top menu */
clear:left;
width:100%;
}
#centeredmenu ul ul li a,
#centeredmenu ul li.active li a,
#centeredmenu ul li:hover ul li a,
#centeredmenu ul li.hover ul li a { /* This line is required for IE 6 and below */
font-size:.8em;
font-weight:normal; /* resets the bold set for the top level menu items */
background:#eee;
color:#444;
line-height:1.4em; /* overwrite line-height value from top menu */
border-bottom:1px solid #ddd; /* sub menu item horizontal lines */
}
#centeredmenu ul ul li a:hover,
#centeredmenu ul li.active ul li a:hover,
#centeredmenu ul li:hover ul li a:hover,
#centeredmenu ul li.hover ul li a:hover { /* This line is required for IE 6 and below */
background:#36f; /* Sub menu items background colour */
color:#fff;
}
/* Flip the last submenu so it stays within the page */
#centeredmenu ul ul.last {
left:auto; /* reset left:0; value */
right:0; /* Set right value instead */
}
/* Make the sub menus appear on hover */
#centeredmenu ul li:hover ul,
#centeredmenu ul li.hover ul { /* This line is required for IE 6 and below */
display:block; /* Show the sub menus */
}
Although this will work as is in most cases there are a few items that can be modified to better suit a theme. On the next page is the actual CSS being used in the Shades theme, version 1.6, to accommodate its requirements as well as meeting current theme review criteria as noted on the WordPress codex page here.
What May Need To Be Adjusted
Note the changes at the following lines: 231, 251, 254, 259, 262, 296, and especially 310 for multiple line menus.
/* Main menu settings */
#centeredmenu {
clear:both;
float:left;
margin:0;
padding:0;
border-bottom:1px solid #000; /* black line below menu */
width:100%;
font-family:Verdana, Geneva, sans-serif; /* Menu font */
font-size:90%; /* Menu text size */
z-index:1000; /* This makes the dropdown menus appear above the page content below */
position:relative;
}
/* Top menu items */
#centeredmenu ul {
margin:0;
padding:0;
list-style:none;
float:right;
position:relative;
right:50%;
}
#centeredmenu ul li {
margin:0 0 0 1px;
padding:0;
float:left;
position:relative;
left:50%;
/* top:1px; */
}
#centeredmenu ul li a {
display:block;
margin:0;
padding:.6em .5em .4em;
font-size:1em;
line-height:1em;
background:#ddd;
text-decoration:none;
color:#444;
font-weight:bold;
border-bottom:1px solid #000;
}
#centeredmenu ul li.active a {
color:#fff;
background:#000;
}
#centeredmenu ul li a:hover {
/* background:#36f; /* Top menu items background colour */
background: #8c8c8c;
color:#fff;
/* border-bottom:1px solid #03f; */
border-bottom:1px solid #444;
}
#centeredmenu ul li:hover a,
#centeredmenu ul li.hover a { /* This line is required for IE 6 and below */
/* background:#36f; /* Top menu items background colour */
background: #8c8c8c;
color:#fff;
/* border-bottom:1px solid #03f; */
border-bottom:1px solid #444;
}
/* Submenu items */
#centeredmenu ul ul {
display:none; /* Sub menus are hiden by default */
position:absolute;
top:2em;
left:0;
right:auto; /*resets the right:50% on the parent ul */
width:10em; /* width of the drop-down menus */
}
#centeredmenu ul ul li {
left:auto; /*resets the left:50% on the parent li */
margin:0; /* Reset the 1px margin from the top menu */
clear:left;
width:100%;
}
#centeredmenu ul ul li a,
#centeredmenu ul li.active li a,
#centeredmenu ul li:hover ul li a,
#centeredmenu ul li.hover ul li a { /* This line is required for IE 6 and below */
font-size:.8em;
font-weight:normal; /* resets the bold set for the top level menu items */
background:#eee;
color:#444;
line-height:1.4em; /* overwrite line-height value from top menu */
border-bottom:1px solid #ddd; /* sub menu item horizontal lines */
}
#centeredmenu ul ul li a:hover,
#centeredmenu ul li.active ul li a:hover,
#centeredmenu ul li:hover ul li a:hover,
#centeredmenu ul li.hover ul li a:hover { /* This line is required for IE 6 and below */
/* background:#36f; /* Sub menu items background colour */
background: #8c8c8c;
color:#fff;
}
/* Flip the last submenu so it stays within the page */
#centeredmenu ul ul.last {
left:auto; /* reset left:0; value */
right:0; /* Set right value instead */
}
/* Make the sub menus appear on hover */
#centeredmenu ul li:hover ul,
#centeredmenu ul li.hover ul { /* This line is required for IE 6 and below */
display:block; /* Show the sub menus */
z-index: 1500; /* Required for multi-line menus */
}
/* -- Extra Window Dressings -- */
#centeredmenu ul li a {
/* optional rounded corners for browsers that support it */
-moz-border-radius: 5px 5px 0 0;
-khtml-border-radius: 5px 5px 0 0;
-webkit-border-radius: 5px 5px 0 0;
border-radius: 5px 5px 0 0;
}
#centeredmenu ul li:first-child a { /* First parent menu item */
/* optional rounded corners for browsers that support it */
-moz-border-radius: 10px 5px 0 0;
-khtml-border-radius: 10px 5px 0 0;
-webkit-border-radius: 10px 5px 0 0;
border-radius: 10px 5px 0 0;
}
#centeredmenu ul li:last-child a { /* Last parent menu item */
/* optional rounded corners for browsers that support it */
-moz-border-radius: 5px 10px 0 0;
-khtml-border-radius: 5px 10px 0 0;
-webkit-border-radius: 5px 10px 0 0;
border-radius: 5px 10px 0 0;
}
#centeredmenu ul ul li:last-child a { /* remove rounded corners from sub-menu items */
/* optional rounded corners for browsers that support it */
-moz-border-radius: 0;
-khtml-border-radius: 0;
-webkit-border-radius: 0;
border-radius: 0;
}
#centeredmenu ul ul ul li a { /* "grandchild" sub-menu items */
padding-left: 10px;
}
A little extra was added at the end of the CSS to add some rounded corner emphasis to the top menu tabs as well as some additional padding for sub-sub-menu items.
Thanks again to Mathew James Taylor for the great CSS.
Enjoy!
- Share this:
- Share
Upgrade wp_list_categories() to wp_nav_menu()
in Functions
as how-to, WordPress, wp_list_categories, wp_nav_menu
In this third installment in the upgrade to wp_nav_menu() series of posts, I will be dealing with moving from wp_list_categories() to wp_nav_menu(). Let’s start with the same basic outline and list the default options for each function. We will start with wp_nav_menu() 1 first: We follow with wp_list_categories() 2, 3 which is often wrapped in [...]
- Share this:
- Share
Upgrade wp_list_pages() to wp_nav_menu()
in Functions
as how-to, WordPress, wp_list_pages, wp_nav_menu
A few options to address and with possibly a minor edit to the theme, you can upgrade wp_list_pages() easily to wp_nav_menu() in your theme.
- Share this:
- Share
Upgrade wp_page_menu() to wp_nav_menu()
as how-to, WordPress, wp_nav_menu, wp_page_menu
Upgrading from wp_page_menu() to wp_nav_menu() may be as easy as a simple find and replace operation.
- Share this:
- Share
WordPress 3.0 Navigation Menu Styles
as CSS, register_sidebar, settings, widget, WordPress, wp_nav_menu
A list of WordPress version 3.0 Navigation Menu default widget, and wp_nav_menu() function, generated CSS style elements.
- Share this:
- Share



