I'm trying to insert an image for each of my navigation items without any plugins. I'm not much of a coder, but I googled for something called walker, but not sure if this should be done for my case. please suggest what should and how I should do this.

<ul id="blabla" etc>
     I want to insert image here: <img src="#">
     <a href="#">some text</a>
     and here: <img src="#">
     <a href="#">some text</a>

Thanks! :)

  • Yes, the menu walker is what you need. Or, maybe better, depends on the exact needs, CSS background images. – cybmeta Feb 8 '16 at 13:42
  • I am using right now css background images, but I want to change them for foreground ones, because of the accessibility needs. But I'm not really sure how – bewodean Feb 8 '16 at 14:22

There are a few ways to do this and they mostly revolve around the walker_nav_menu_start_el filter.

I'd be inclined to add custom fields to the nav menu items: one for the image and one for the image's alternate text. That way, users can update the images and developers aren't required to keep a hash of all menu items and related image URLs/alt text in code (and up to date with the actual menu items).

There are plenty of google's that will land you on 'wordpress custom fields for menu items'. Once that's set, you can use something similar to the snippet below.

Short of adding custom fields, you could abuse the Menu Item's Description field for similar purposes.

  1. In Appearance->Menus->Screen Options, make sure 'Description' is visible.
  2. For each menu item, insert the URL of the image. You can't (easily) simply put an image tag in here as WP strips HTML before saving it.
  3. Then, in your functions.php or similar, add this snippet. You will probably need to tweak the HTML a bit to get what you're after. This snippet, for instance, inserts the image inside of the <a> tag.

function mynamespace_nav_add_images( $item_output, $item, $depth, $args ) {
    // You can limit it to certain menus with this check
    if ( 'primary' == $args->theme_location && !empty( $item->description )  ) {
        // NOTE: by default, link_after will be empty.
        // It's here in case it's added via wp_nav_menu(['link_after'=>'xyz'])
        $old =  $args->link_after . '</a>';
        $new = '<img src="' . $item->description . '">' . $args->link_after . '</a>';

        $item_output = str_replace( $old, $new, $item_output );
    return $item_output;
add_filter( 'walker_nav_menu_start_el', 'mynamespace_nav_add_images', 10, 4 );

To insert the image before the opening <a> tag, something like this should work:

$old = '<a';
$new = '<img src="' . $item->description . '">' . '<a';

This is basically lifted straight from the Twenty-Fifteen theme. http://themefoundation.com/menu-item-descriptions/ has a fairly good walk through of similar code.

This gets you part of the way there. Problem is these images do not have alternate text—particularly bad if your stated purpose is accessibility.

If you're confident in the folks who will be entering text into the description box, you can use something like a | to split the URL and the alternate text. That would look something like this:

if ( 'primary' == $args->theme_location && !empty( $item->description ) ) {
    // Description content:
    // http://path.to/image.jpg | This is the alternate text.
    $description = explode('|', $item->description);
    $url = trim($description[0]);
    $alt = trim($description[1]);
    $old =  $args->link_after . '</a>';
    $new = '<img src="' . $url . '" alt="' . $alt . '">' . $args->link_after . '</a>';

    $item_output = str_replace( $old, $new, $item_output );
return $item_output;

That sort of thing is easy to mess up. Plus, you're asking users to enter URLs which in and of itself is easy to mess up. But it'll work if the input is ok. Custom fields would be better and, sorry to say, a plugin is likely even better. :) https://wordpress.org/plugins/menu-image/

  • Thank you! I will try this, but if it won't work I'll go for this plugin you suggest, after all it is seems to be very effective. – bewodean Feb 9 '16 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.