Let’s Put Icons in Our Menus

by on March 22, 2011

Have you noticed our main menu (at the top of the page). Most items have functionally suggestive icons to the left of the text … just like desktop applications. And, parent menus have arrows to indicate that there's a submenu available.

How'd we do this? Is this a custom plugin? Is it specific to a particular theme? Well … actually … you can do the same with your blog with just about any theme. This visual embellishment is accomplished by subclassing WP 3.0's new menu functionality. So … if you wanna have menu icons too … read on.

First though, if your current theme is not upgraded to 3.0 features, you might want to read this article. Also, we covered several resources where you can get NICE, free icons here.

It's worth noting too that this menu looks the same with all modern browsers (CSS2 or CSS3). In short, it has cross-browser and multi-theme support.

Of course, you're not restricted to menubars. You can use this technique anywhere that you display navigation menus created with the 3.0+ menu editor. Plus, some menus can implement the feature while allowing others to utilize the WP default menu appearance.

Also, I'd like to give credit to the originators of the menu editor code, WooThemes.com. They made the product and donated it to Automattic. Then, WP developers modified the code to blend in with the WP dashboard layout.

Here's the PHP Function

Some time after installing 3.0, I began experimenting with the new menu feature. It is vastly superior to the old method of constructing menus by sequencing the order of ID's and parents. Finally, I inserted an image tag inside the Navigation Label  for one menu item … and saved the menu. Next … off to the home page … and … WOW … it worked!

But, there was a drawback. The entire HTML code for the image tag appeared in the menu editor for that block's header title. Thus, I would never be able to know what menu items were in the editor without first opening each block that had a menu icon.

Okay … so to overcome this challenge, I dug into WP source code for the menu. And, there it was … a walker function in the menu class. WP uses these walkers in many of its list output processing functions. But, let me tell you; I have a loathing for walker subclassing that's tantamount to dental extraction.

Nonetheless, I persevered. And along the way, I added another capability. How about the ability to include separators in menus? Yep, it's there too.

Now, let's look at the workhorse code that performs these tasks for us. PUT THIS CODE in your theme's functions.php file.

Code: PHP (plus WordPress)Function: wcs_menu_icon_walker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
class wcs_menu_icon_walker extends Walker_Nav_Menu
{
    function start_el(&$output, $item, $depth, $args)
    {
        // reference:        includes/nav-menu.php -> (line #528) wp_setup_nav_menu_item()
        // reference:        includes/nav-menu-template -> (line #57) start_el()
 
        // Title Attribute    = URL of arrow image for parent menus
        // Description        = URL of menu item icon
        // images can be:    gif, ico, jpg, or png
        // set Navigation Label to - for a separator
 
        // user-defined menu icon parameters
        // top-level (menubar) items can have icons too
        $menu_icon_style    = 'margin-left:-5px; padding-right:5px;';
        $menu_icon_width    = '16';
        $menu_icon_height    = '18'; // top image padding: 2 pixels (blank)
 
        // horizontal menu padding for item with no associated icon
        $menu_no_icon_style    = 'margin-left:12px;'; // tweak per theme
 
         // user-defined horizontal arrow parms
        $menu_arrow_style    = 'float:right; padding-top:3px;';
        $menu_arrow_width    = '16';
        $menu_arrow_height    = '16';
 
        // user-defined vertical arrow parms (top-level menubar)
        $menu_arrow_top_style    = 'padding-left:5px;';
        $menu_arrow_top_width    = '16';
        $menu_arrow_top_height    = '16';
 
        // if Navigation Label is a dash (-), a separator is displayed
        $menu_separator_style    = 'background:#C0C0C0;';
 
        // init
        global $wp_query;
        $indent = ($depth) ? str_repeat( "\t", $depth ) : '';
        $class_names = $value = '';
 
        // gather data
        $classes = empty($item->classes) ? array() : (array) $item->classes;
        $class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item));
        $class_names = ' class="' . esc_attr($class_names) . '"';
 
        // start the list item (concatenate incoming string)
        $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
 
        // process separator option
        if (trim($item->title) == '-')
        {
            $item_output = $args->before;
            $item_output .= $args->link_before;
 
            $item_output .= '<div style="height:1px;">';
            $item_output .= '<a href="#" style="';
            $item_output .= $menu_separator_style . '"></a></div>';
 
            $item_output .= $args->link_after;
            $item_output .= $args->after;
 
            $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
            return;
        }
 
        // extract anchor attributes
        $anchor_attr = !empty($item->url)        ? ' href="'   . esc_attr($item->url       ) . '"' : '';
        $anchor_attr .= !empty($item->xfn)        ? ' rel="'    . esc_attr($item->xfn       ) . '"' : '';
        $anchor_attr .= !empty($item->target)     ? ' target="' . esc_attr($item->target    ) . '"' : '';
 
        // start the anchor tag
        $item_output = $args->before;
        $item_output .= '<a' . $anchor_attr . '>';
        $item_output .= $args->link_before;
 
        // add the menu icon (substitute for "menu description")
        if (trim($item->description) != '')
        {
             $item_output .= '<img src="' . esc_attr(trim($item->description));
             $item_output .= '" width="' . $menu_icon_width;
             $item_output .= '" height="' . $menu_icon_height;
             $item_output .= '" style="' . $menu_icon_style . '" />';
         }
         elseif ($item->menu_item_parent != 0)
         {
             $item_output .= '<span style="' . $menu_no_icon_style . '">';
             $item_output .= '&nbsp;</span>';
         }
 
        // apply title text filters
        $item_output .= apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
 
        // add the submenu arrow icon (substitute for "menu title attribute")
        if (!empty($item->attr_title))
        {
             $item_output .= '<img src="' . esc_attr($item->attr_title);
            if ($item->menu_item_parent == 0)
            {
                 $item_output .= '" width="' . $menu_arrow_top_width;
                 $item_output .= '" height="' . $menu_arrow_top_height;
                 $item_output .= '" style="' . $menu_arrow_top_style . '" />';
            }
            else
            {
                 $item_output .= '" width="' . $menu_arrow_width;
                 $item_output .= '" height="' . $menu_arrow_height;
                 $item_output .= '" style="' . $menu_arrow_style . '" />';
             }
         }
 
        // TEST (type: Custom, Post, Page, Tag, or Picture)
        //$item_output .= ' (type:' . $item->type . ')';
        //$item_output .= ' (type_label:' . $item->type_label . ')';
 
        // TEST (object ID of post, page, taxonomy, etc.)
        //$item_output .= ' (object_id:' . $item->object_id . ')';
 
        // TEST (featured image: Posts and Pages)
        //if(has_post_thumbnail($item->object_id))
        //{
        //    $thumbnail_img_tag = get_the_post_thumbnail($item->object_id, 'thumbnail');
        //    $item_output .= ' (featured image:' . $thumbnail_img_tag . ')';
        //}
 
        // complete the anchor tag
        $item_output .= '</a>';
        $item_output .= $args->after;
 
        // exit
        $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
    }
 
    /**********************************************************************
     Copyright © 2011 Gizmo Digital Fusion (http://wpCodeSnippets.info)
     you can redistribute and/or modify this code under the terms of the
     GNU GPL v2: http://www.gnu.org/licenses/gpl-2.0.html
    **********************************************************************/
}

I started off, as is typical with walkers, by simply copying the original WP source code and experimenting. So … about a third of this code is directly WP source.

Now since we're subclassing the menu functionality and not reconstructing it, a caveat  is in order about what we have to sacrifice. I couldn't ADD new data blocks within the dashboard for additional user-defined values.

So … I hijacked two existing fields that are rarely used … the Title Attribute and the Description. I've commented the code so that you can easily figure out how to use other fields, if these original two are vital to your blog(s).

BTW, if you don't see these fields in your menu editor, here's what to do. While on the menu editor page, click Screen Options at the top right. Then, just click/check the appropriate options.

Also, WP automatically adds the description for menu items that are links to posts and pages. It's the content excerpt. So … BE SURE to clear out these default descriptions … even for menu items that won't have icons.

When using the menu editor, you use the Title Attribute field for the URL of the arrow image for parent menus. And, you use the Description field for the URL of the item's icon.

You should upload your icons using the Media utility of the dashboard. I use 16×16 icons (in PNG format). But first, I add TWO blank pixels to the top (with PaintShop Pro X3) making the final icon 16×18.

Also, although I'm not doing it on this blog, you can use menu icons on the very top level menu too. In fact, you'd probably want to do that if you don't have any submenus for a particular blog.

In lines 13 – 33, you can set your own CSS styles for the various menu components … the menu icons, a placeholder for items without icons, horizontal arrows, vertical arrows (top level), and the separator color. Lines 35 – 46 are directly from the WP code … basic (but required) setup.

In lines 48 – 63, we process the separator option. Any menu with a Navigation Label as a DASH is handled, instead, as this horizontal rule. In this case, the function returns without any further processing.

In lines 65 – 73, we again use the standard WP code. In lines 75 – 87, we insert the menu icon code into the output string variable. In lines 92 – 108, we handle the menu arrows … top level menu arrows are processed differently.

In lines 110 – 122, I included some code that you can experiment with to view the results. Just uncomment the segments you want to test. This should help you to add other features … or … to use different menu fields for the processing of the icons.

Finally, we return the entire output string to the calling function. It looks fairly simple here; but, there was some trial-and-error getting it to work right.

Now that we're done, add this code to your theme's functions.php file. But, you won't see any change until we actually implement the code in your header.php file. And, of course, you'll need to modify an existing menu with the editor to add the image URL's.

Here's How to Implement Menu Icons

When you're ready … in your theme's header.php file, find the lines that look similar to the following:

Code: PHP (plus WordPress)

        $menu_html = wp_page_menu('echo=0&title_li=&depth=5&sort_column=menu_order&show_home=' . get_theme_mod('menu_home_text'));
        echo $menu_html;

Comment them out, and add this line … or a reasonable facsimile thereof contingent upon your particular theme's setup. Be SURE to replace the menu slug (menu-1 in this example) with your own top menu's slug. Of course, if you're already using a 3.0 menu-compliant theme … just add the walker portion to your existing function call.

Code: PHP (plus WordPress)

wp_nav_menu(array('theme_location' => 'menu-1', 'walker' => new wcs_menu_icon_walker()));

That's it. Even though this function adds the menu icon capability … there will be some work required for you to find the right icons and to upload them. But, the final result will be well worth it.

Also, I'd recommend that you use this PHP function as is (without any modifications … style changes, etc.) to begin with. Forget about possible minor position and size alignments until you've got several icons uploaded (Dashboard -> Media) and you've added the URL's to the menu editor.

Share This Article: “Let's Put Icons in Our Menus”

(Also Available: Press CTRL+D to Bookmark this Page)

Comments

Share Your Thoughts  7 Responses to “Let’s Put Icons in Our Menus”
  1. 1
    Ted Thompson says:

    This is still a bit advanced for me about putting icons in my blog menu. But it worked after all. Good site man.

  2. 2
    johnnie b says:

    It took some work on my part changing my menus. But I love the icons. Thx.

  3. 3
    Jake Thomas says:

    I wasn’t sure if these menu icons would work with my theme. But they did. Thanks.

  4. 4
    Thanushka says:

    Nice article. Thank you! It’s so hard on the eye though. Would you consider reducing the font color to a lighter gray? or change the font’s opacity? 

  5. 5
  6. 6
    amenAssaurn says:

    Get Ready-to-use Elegant Icons to Apply Them for Your As Well Delightful Apps

    When developing the app or whatever, do not ignore the worth of carefully elected icons. We offer you to glance through our compilation of delightful, professional icons that could convey completeness and unison into your application appearance together with cleanness in its navigation.

    Visit this CoolDesignIconSite: icon blog to get discount for stock icons.

  7. 7
    Annie says:

    This looks like a great tutorial, but I got stuck on the first step because it doesn’t look like I have a file called “functions.php” I went to Appearance>Editor and then looks at the list on the right side and that file isn’t listed. I’m using the Suffusion template. Can you help please?

Share Your Thoughts

(Some editor features are restricted unless you're logged in.)

(When replying to a specific comment, your browser may require Shift+Enter instead of just Enter.)


(get a gravatar)


Notify me of followup comments via e-mail. You can also subscribe without commenting.