Displaying WordPress Menu Item Descriptions

WordPress has the capability to store descriptions for each menu item in a custom menu. However, by default those descriptions are never displayed on the front end. In this post, we’re going to look at how to display those descriptions.

This post is part two in a three part series which walks through the process of adding menu description support to the Custom Menu widget that ships with WordPress:

Adding Descriptions

By default, WordPress hides the description input field. Before we do anything else, we’ll need to make sure we can see this field. On the Appearance > Menus page of the dashboard, click the “Screen Options” tab at the top right corner of the screen, next to the “Help” tab. Then make sure the “Description” checkbox is checked.

Description checkbox screenshotNow for each menu item in the menu editor, there will be a box to enter a menu item description (If you haven’t already, go ahead and enter a few descriptions so you can see them show up as we move through this tutorial). Now lets move on to actually displaying these descriptions.

Displaying Descriptions

There are quite a few tutorials around the web explaining how to use a custom walker class to walk through the menu and customize the output. However, I was really hoping to not have to recreate an entire class for something as simple as adding a description to each menu item. Thankfully I stumbled upon this article: Adding Menu Descriptions to WordPress Menus by Ben Gillbanks. He pointed out that the Twenty Fifteen theme uses a simple filter to add descriptions, rather than using an entire walker class.

Please note: The code below will add description support to all menus. The final post in this series will cover how to use the Custom Menu widget option we created in the first post of the series to control which menus display the descriptions. If you want to add description support to a specific menu location defined by the theme, please see the tutorial by Ben Gillbanks mentioned in the previous paragraph.

function prefix_nav_description( $item_output, $item, $depth, $args ) {
	if ( !empty( $item->description ) ) {
		$item_output = str_replace( $args->link_after . '</a>', '<span class="menu-item-description">' . $item->description . '</span>' . $args->link_after . '</a>', $item_output );
	}

	return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'prefix_nav_description', 10, 4 );

Notice that we’re adding our function to the walker_nav_menu_start_el filter. This filter passes four parameters to our function.

$item_output string The menu item’s starting HTML output.
$item object Menu item data object.
$depth int Depth of menu item. Used for padding.
$args array An array of wp_nav_menu() arguments.

First we check if a description exists for the current menu item. If it does, we insert the description into the link using the str_replace() function. This places the description after the main link text.

Alternate Output: Changing Description Placement

Now let’s say we want to place the description before the main link text instead of after it. To do this, we will need to modify our call to the str_replace() function. Before, this was the string we were looking to modify:

$args->link_after . '</a>'

We were using str_replace() to replace that string of text with this:

'<span class="menu-item-description">' . $item->description . '</span>' . $args->link_after . '</a>'

To place the description before the main link text, we’ll need to replace this section of the string instead:

'">' . $args->link_before . $item->title

Here’s what we’ll want to replace it with:

$args->link_before . '<span class="menu-item-description">' . $item->description . '</span>' . $item->title

So our new function should look like this (only the $item_output line has changed):

function prefix_nav_description( $item_output, $item, $depth, $args ) {
	if ( !empty( $item->description ) ) {
		$item_output = str_replace( '">' . $args->link_before . $item->title, '">' . $args->link_before . '<span class="menu-item-description">' . $item->description . '</span>' . $item->title, $item_output );
	}

	return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'prefix_nav_description', 10, 4 );

Styling the Description

How you style the menu is really up to you. However, since we placed the description in a span tag instead of a div, it will be displayed on the same line as the main link text. Typically, we will want to display it either above or below the main link text. To do that, we will want to make sure we set the description element to display as a block level element, rather than inline. We can do that by placing the following code in our stylesheet:

.menu-item-description {
	display: block;
}

Since menu styles are so diverse, I won’t go into more detail about styling them here, except to point out one small issue I ran into while styling my own menus. If you only add descriptions to some menu items but not all of them, you may need to specify the vertical alignment of the text in your menu. For some reason, my main link text was aligning to the bottom for links without descriptions but being pushed up to the top on links with descriptions. I had to do something like this to fix the problem:

.menu a {
	vertical-align: top;
}

Hopefully that helps you on your way to adding menu descriptions to your site. If you have any questions, please feel free to use the form the contact page to get a hold of me.