WordPress Wp_Nav_Menu with Icons and Active Item Highlight

WordPress is a great tool, for sure, but as many other CMS’ it drives us into an “all standard” way of thinking, that is, you design things thinking that every element has to be identical to his brothers, same color, same style, same size.

How many WordPress sites with pretty menu icons do you know (with wp_nav_menu, not “static” menus)?  How many of them use a different color for some categories? Well, these little things make a big difference.

This time we will learn a simple way to customize our WordPress menu, without losing its wonderful admin options. We will be doing:

•   Home link in our wp_nav_menu that always gets current blog url
•   Customize each menu item as you want
•   Put pretty icons in our menu
•   Active item highlight

From now on, it is useful to have a little understanding about what wp_nav_menu is, and if you have a blank WordPress install, it is time to play with it ;)

So, let’s rock!

Our Final Result

This is how our demo menu will look, but you can customize yours as you need, of course. In this menu, I’ve used these great resources:

Home Link in Our Menu

Almost every site needs a home link on its menu. But if you want to put your home link in a wp_nav_menu you just can’t by default. But we have (at least) two ways to work around it. The first one is explained in WpBeginner. Just add this code in your functions.php:

<!--?php function home_page_menu_args( $args ) { $args['show_home'] = true; return $args; } add_filter( 'wp_page_menu_args', 'home_page_menu_args' ); ?-->

With this solution you enable Home as a page in your pages selection, so you can add it to your menu.

My solution is to edit the wp_nav_menu and force it to add the home menu item before the other menu items:

<!--?php<br /-->add_filter('wp_nav_menu_items','homeMenu', 10, 2);
function homeMenu($items, $args) {
	$home = '
	<li><a class="home item-0" href="' . get_bloginfo('url') . '">Inicial</a></li>
	$items = $home.$items;
	return $items;

As you can see, I’ve added a span around it and two classes. Both will be useful below.

Customizable Menu Items

When you need to customize each item of the wp_nav_menu the first thing you may notice is its standard generated HTML. Let’s see an example of wp_nav_menu output:

<!--?php //php code that call menu wp_nav_menu( 	array( 		'link_before'        =--> '',
		'link_after'          => ' 'div',
		'container_id'      => 'topMenu',
		'theme_location' => 'primary-menu',
		'fallback_cb'       => 'primarymenu',

<!-- HTML Output -->
<div id="topMenu" class="menu-topmenu-container">
<ul id="menu-topmenu" class="menu">
	<li><a class="home item-0" href="#linktoHome">Home</a></li>
	<li id="menu-item-6" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-6"><a href="#">Features</a></li>
	<li id="menu-item-8" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-8"><a href="#">Awards</a></li>
	<li id="menu-item-3" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-3"><a href="#">Pricing</a></li>
	<li id="menu-item-5" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-5"><a href="#">Blog</a></li>
	<li id="menu-item-10" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10"><a href="#">About US</a></li>
	<li id="menu-item-12" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-12"><a href="#">Contact us</a></li>

As you can see, the only option to customize these items is to use the id or the unique class of it. But you may notice that they seems to be completely random. This is because they are the menu item ID. If you edit the menu, or delete something you can lose this unique reference. This is why I use the menu-order to customize them. So, add this snippet to your functions.php:

<!--?php add_filter( 'nav_menu_css_class', 'additional_active_item_classes', 10, 2 ); function additional_active_item_classes($classes = array(), $menu_item = false){ 	//add current menu order to item classes 	$classes[] = "item-".$menu_item--->menu_order;
	return $classes;

With this code, each menu item will have on this classes now:

	<li id="menu-item-n" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-n item-1"><a href="#">Features</a></li>

Yeah, that’s it. Now you can just add .item-1 and edit the first menu item!

Working a little bit on our demo, let’s make the pricing item different from others:

#topMenu a {
	position: relative;
	float: left;
	padding: 18px 20px 14px;
	text-decoration: none;
	font-family: "arial";
	text-transform: uppercase;
	color: #949494;
	font-weight: bold;
	font-size: 12px;
	border: 1px solid;
	border-style: none solid;
	border-color: transparent #9e9e9e transparent #d8d8d8;
/* pricing item style */
#topMenu .item-3 a { color: #879A51; }
/* hover styles */
#topMenu a:hover {
	background: transparent url(MENU_hover.png) repeat-x;

Pretty easy and customizable, isn’t it? So let’s make it even better with pretty icons now.

Pretty Menu Icons

Do you remember that I’ve put a span around each element? So it will make more sense now. We will use each span to hide our text without affecting the link itself, when needed. For example, let’s say that instead of text and an icon I want just an icon for “home.” So we can use that span to hide our stuff.

Our CSS to create icons and text in all items and just an icon for “home” is this:

/******** ICONS! **********/
#topMenu .item-1 a { background-image: url(promotion.png); padding-left: 38px; }
#topMenu .item-2 a { background-image: url(prize_winner.png); padding-left: 38px; }
#topMenu .item-3 a { background-image: url(dollar_currency_sign.png); padding-left: 38px; color: #879A51; }
#topMenu .item-4 a { background-image: url(news.png); padding-left: 38px; }
#topMenu .item-5 a { background-image: url(info.png); padding-left: 38px; }
#topMenu .item-6 a { background-image: url(comment.png); padding-left: 38px; }
#topMenu ul a.home span {
	margin: -10px 0 -8px;
	width: 32px;
	height: 32px;
	text-indent: 300px;
	overflow: hidden;
	background: url(home.png) no-repeat;

Now it is missing just one more thing to get it really good: the active item highlight.

Active Item Highlight

This is really good feedback for the user, so he knows where he is without scanning too much.

To get this working we need to know which page we are on. One easy way to get this it to put a simple id (or class) in our body tag, so it could be used for more than just this menu:

//Output something like id="page-15"

Now all our magic now is done via CSS (by the way, with LESS it would be MUCH easier). You just have to set which page will be the “parent” of each item, just like this:

/* active styles */
#page-1 #topMenu .item-2,
#page-2 #topMenu .item-5
	background: #fafafa url(60degree_gray.gif);

So we are saying here that the second menu item is active when we are on page 1, and the fifth item is active when the page is 2. For a better understanding I recommend to keep it in separated lines but pay attention that the last item can’t have a comma after it.

Are You Hungry Yet?

We certainly have more ways to create cool and unique things like this, what kind of unique menus have you created in WordPress? Do you think this way is better? What would you do instead?

I recommend  that you always read the WordPress Function Reference, so you can do a better job spending less time with WordPress pre-built functions!

Rochester Oliveira

I'm a web designer and entrepreneur from Itajubá (MG), Brasil. I love writing about obscure topics and doing some cool stuff. And also I do some FREE stuff, check it out: http://www.roch.com.br/

15 Smart Tools To Help You Build Your Freelance Business

Discover the awesome tools we use in making our clients comfortable and happy in learning new things every day.

Download Now


  1. Erick says

    Thank you for this VERY helpful tutorial. Could you explain how the icons could be placed above the menu items.

    Thank you!

  2. asaduzzaman says

    This is very helpful site. I have got some good knowledge from this .

    Thanks for sharing.

  3. says

    Hey! This is a great tutorial! I’m a graphic designer by trade, which means that any program knowledge is self-taught :) I put a lot of reliance on great articles like this.

    I do have one question. I am very new to PHP. You said that after including the filter in the functions file, to edit the first list item. I’m not sure how to go about doing that. Could you be a little more specific?

    • says

      Hi Chrissie!

      Actually we have a few issues with our code formatting plugin.. But what a filter does is to change the output of another function. So in our case, we’ll get the default return (list items with a few wordpress default’s classes) and edit them to add our our classes, this is why we need those filters, to help us giving a securely stylable class.

      If it’s still unclear, just email me and I’ll try to help you a little bit more :)


  4. Jamie L says

    Yeah I’m not to sure how many I’ve seen and I’ve never really thought about doing this “all standard” way of thinking! Its about to change, thanks for the tutorial Rochester!

  5. says

    Link to the home page should be on each site. Use the icons in the menu looks attractive. You are buying these icons?
    In principle, all that you describe should be at each site and this has not been said.

    • Rochester Oliveira says

      Hi Antown,

      I don’t like to say aways, each project, each costumer has his needs. Sometimes it has a really dynamic menu, or doesn’t have space to put icons, for example.

      But I’m pretty sure that 90% of the sites could have a better menu.

      Thank you for pointing out!