Last updated 10 August 2010. Created on 17 January 2007.
Edited by chrisshattuck, TheRec, chicagomom, tbartels. Log in to edit this page.


To insert an image instead of text in a menu item you may rewrite theme_menu_item_link().

Drupal 6 version

See here for a functional Drupal 6-tested version.

Step 1 of 2

Put this code into your template.php inside your themes directory:

function phptemplate_menu_item_link($item, $link_item) {
	/* Allow HTML if the menu text is an image tag: call l() with 7th argument set to TRUE
	 * See
	if( strpos($item['title'], '<img') === 0) {
	  return l($item['title'], $link_item['path'], !empty($item['description']) ? array('title' => $item['description']) : array(), NULL, NULL, FALSE, TRUE);
  return l($item['title'], $link_item['path'], !empty($item['description']) ? array('title' => $item['description']) : array());

Here we just look for the menu title starting with the HTML tag <img and if true call l() with the 7th argument set to TRUE. This will allow HTML inside the menu text. See

Step 2 of 2

Now just enter an image tag into the "Title" field inside the "edit menu item" form (administer > menus > (edit or add item)) like <img src="/sites/default/menu_item.gif" />


  • This code should work in Drupal 5.0 too. At least the l() function did not change from 4.7 to 5.0

Additional resources

Looking for support? Visit the forums, or join #drupal-support in IRC.


bdornbush’s picture

This function works for the Navigation menu, but when I try it for a primary link item, I just see the Only local images are allowed. tag as text. I would like to have images instead of text in the primary links menu in the header. Does this require rewriting another function? BTW I am using 5.1.

bdornbush’s picture

I tried the following with 5.1, and it seems to work fine.

In template.php, istead of rewriting theme_menu_item_link(),
rewrite theme_menu_links() as follows:

function phptemplate_menu_links($links) {
  if (!count($links)) {
    return '';
  $level_tmp = explode('-', key($links));
  $level = $level_tmp[0];
  $output = "<ul class=\"links-$level\">\n";
  foreach ($links as $index => $link) {
    $output .= '<li';
    if (stristr($index, 'active')) {
      $output .= ' class="active"';
    if (strpos($link['title'], '<img') === 0) {
      $output .= ">". l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment'], FALSE, TRUE) ."</li>\n";
    else {
    	$output .= ">". l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']) ."</li>\n";
  $output .= '</ul>';

  return $output;
field4000’s picture

You could use CSS to change the background image of each of the classes.

For example:

.links a:link, .links a:visited
display: block;
height: 36px;

background: url(../../images/navigation_home.gif) no-repeat;
width: 156px;

background: url(../../images/navigation_home_over.gif) no-repeat;

background: url(../../images/navigation_home_over.gif) no-repeat;
width: 156px;

optix’s picture

(which works great by the way, thanks you very much), make sure you double-check the text for wrapping. This should all be on one line:

    // See <a href="
" title="
" rel="nofollow">


    // See <a href="" title="" rel="nofollow"></a>

Otherwise you will get parse errors.

osopolar’s picture

drupal-6: Put the image in the description field and exchange title and description later to show the image with the title description.

1: Change the theme_menu_item_link function in template.php to:

* Implements theme_menu_item_link()
function your-theme-name_menu_item_link($link) {
  if (empty($link['localized_options'])) {
    $link['localized_options'] = array();

  if(strpos($link['localized_options']['attributes']['title'], '<img') === 0) {
    // Allow HTML if the menu description is an image tag:
    $link['localized_options']['html'] = TRUE;
    // exchange description with title
    $tmp = $link['localized_options']['attributes']['title'];
    $link['localized_options']['attributes']['title'] = $link['title'];
    $link['title'] = $tmp;

  return l($link['title'], $link['href'], $link['localized_options']);

2: Add the image tag to the menu items description:

Enter an image tag into the "Description" field inside the "add/edit menu item" form (administer > menus > (add/edit item))

<img src="/sites/" />
Mr Cronk’s picture

I'm using Drupal 6 so it was good to see a solution for this version of Drupal.

I've adapted template.php as you suggest, then added the img tag to the description field. But still, the title text is all I see. How do I "exchange the title and description"? What exactly does that mean?


tcom’s picture

I got this working by adding the <img> tag to :
Home › Administer › Site configuration › Input formats › Filtered HTML > Allowed HTML tags

Danny_Joris’s picture

I don't get this either. Adding < img > does not work.

Ok it works now, but not with relative paths. Only with absolute paths. Does anyone know why?
I'm happy it works, but as the website is still in development, i will need to move it later, so it will be a bit annoying to change all those paths again.

Plus: i've got another question. Is there a way to change these pictures at onMouseOver or when a certain page is Active? If i can't make this work with drupal easily, that would be a real handicap.

osopolar’s picture

If you don't want to use javascript for this purpose the only way I know is to use css. You should give your menu item a class and set a background image for that item.class. For the class:hover you should set another background image.

In the case "when a certain page is Active" you may use the body-class. If your theme don't have this classes you need to add them. Have a look on theme documentation or for example the zen-theme. If you need more help you may ask in the drupal forum or irc.

Danny_Joris’s picture

Hey ositoblanco, thank you very much for the help. In the meanwhile i already found a perfect working sollution for this by asking the at the forum. You can find it here:

pyctures’s picture

I added the php code in my "page.tpl.php" for bluemarine theme.
I entered an img tag in the description field for a menu item (<img src="sites/default/files/file.png" />)
I added img tag in the "allowedhtml tags"... I also tested Full HTML option...

But I just see the Menu TITLE.

Do I need to "exchange title and description" ?
How to do this ?

osopolar’s picture

There is also a module for menu icons at

missWilder’s picture

Hello ositoblanco,

Thanks for such a helpful post. I have everything working except the hover - I have a different color image in the design and need it to appear on hover but it does not... I've tried many approaches in the css, to no avail.

Any guidance is much appreciated!

osopolar’s picture

To do hover IMHO you have to use background images (or some javascript). Have you checked the above module? Otherwise you may check the drupal Forum for more Help.

osopolar’s picture

Create a class name from the menu item title. Add this class name to the menu item link and wrap the link text with a span tag (to disable the display of the text title via css). In the css set for each link class the background image. This is a very easy and fast but less dynamic way (you need to change the css and upload the image when you want to change the menu item title). To fix the downside you may have a look at the Textimage module and write some custom module code.

This code goes to your themes template.php

 * Formats a string to be used as class name
function THEMENAME_string_to_class($string) {
  $pattern = array("ä", "ö", "ü", "ß", " ");
  $replace = array("ae", "oe", "ue", "ss", "_");
  // lowercase, with transformed umlauts and without all other specialchars
  return preg_replace("%[^a-z0-9]%", "", str_replace ($pattern, $replace, strtolower(strip_tags($string))));

function THEMENAME_menu_item_link($link) {
  if (empty($link['localized_options'])) {
    $link['localized_options'] = array();
  if ($link['type'] & MENU_NORMAL_ITEM) {
    $class = 'menu_item_THEMENAME menu_item_THEMENAME_'. THEMENAME_string_to_class($link['title']);
    $link['title'] = '<span>'. $link['title'] .'</span>';
    $link['localized_options']['html'] = TRUE;
    $link['localized_options']['attributes']['class'] = empty($link['localized_options']['attributes']['class'])? $class : $link['localized_options']['attributes']['class'] .' '. $class;    
  return l($link['title'], $link['href'], $link['localized_options']);

css-Example for the menu item "Example" in the menu called "Menu":

#block-menu-menu-menu .menu_item_THEMENAME span {
  display: none;
#block-menu-menu-menu a.menu_item_THEMENAME_example:link,
#block-menu-menu-menu a.menu_item_THEMENAME_example:visited {
  background-image: url(images/example.png);
#block-menu-menu-menu a.menu_item_THEMENAME_example:hover,
#block-menu-menu-menu a.menu_item_THEMENAME_example:focus,
#block-menu-menu-menu a.menu_item_THEMENAME_example:active,
#block-menu-menu-menu .active-trail a.menu_item_THEMENAME_example {
  background-image: url(images/example_hover.png);
bdornbush’s picture

This solution from ositoblanco works fine for me in menus on the left, but doesn't work for me in the primary menus. In the left menu, I see my image, but with the same menu entry in the Primary Menu, I see the Menu Link Title and the description, which contains the <img> tag, is shown as "".

I assume that the primary menu processing must be different, and the code needs to be put somewhere else as well to get the primary menu substitution. Can anyone help? How is primary menu processing different from other menus?

The CSS image replacement approach doesn't seem to work due to my theme.

Jim Leichliter’s picture

Using Drupal 6x:
Install menu_icons module and nice menus. When you go to edit/create your menu item, place the image tag in the Menu link title field: <img src="/sites/default/files/icons/news.png" />. Optionally you can have an image and text if you type this in the Menu link title field: <img src="/sites/default/files/icons/news.png" />News. Note the Preceding forward slash in front of "sites" for the source.

In the "Menu Icon Settings" area of the edit menu page, make sure you have the "Use an icon" checked and the path to the icon file specified WITHOUT THE PRECEDING FORWARD SLASH. Like this: sites/default/files/icons/news.png. That's it!

ksaen’s picture

I don't really get your advice.
For what do i need nice menus?
I tried your solution, but it didn't work. It shows <img src="/sites/default/files/icons/news.png" /> and doesn't act like a image tag.

moxwai’s picture

Had the same problem - but fixed
I had the same problem as you but figured out that jim said put a foward slash in front of sites, well that depends on how your server is configured. I removed the forward slash from both places and the image appeared.

Nice menus gives you dynamically expanding menus that you see on a lot of sites.

moxwai’s picture

This should be in the core eh? I guess it could be part of themeing, but for a novice like me i had to check a couple different recommendations on ways of doing this which has taken a 2.5 hours and its working but still not 100% sure on mouseouts etc. Would take me 2 minutes in dreamweaver, for this basic website function.

netsensei’s picture

While using images as linked menu items should be possible, it's cumbersome. And I'm no fan of implementing entire modules (even use JS) to just get images as menu links.

My solution involves use of the template_preprocess_page(), knowledge about how l() and theme_links() relate to each other and Dave Shea's Image Replacement method (which works cross browser) (

Step 1:

In your page.tpl.php you'd do what you would normally do: let theme_links process the $primary_links array.

<?php print theme('links', $primary_links, array('class' => 'primary-links')); ?>

Step 2:

Add this piece of code to your template.php (or add it to
_preprocess_page($vars) if you already have that function overridden)

function template_preprocess_page($variables) {
  $primary_links = theme_get_setting('toggle_primary_links') ? menu_primary_links() : array();
  foreach ($primary_links as $key => $link) {
	 $primary_links[$key]['html'] = TRUE;
	 $primary_links[$key]['title'] = '<span></span>' . $primary_links[$key]['title'];
 $variables['primary_links']     =  $primary_links;

Step 3:

Now for the CSS part. Put this in your style.css file.

    #header .primary-links {
      width: 200px;
      height: 40px;
    #header .primary-links a {
      position: relative;
      width: 200px;
      height: 40px;

    #header .primary-links a span {
      position: absolute;
      width: 200px;
      height: 40px;
      background: url('../images/menu-item.gif') top left no-repeat;

Replace the XXX with the id of the menu item, adjust the size of the elements (width and height) to match with your image and put the image in the background attribute of the last CSS selector.

That's it. A clean linked image which gracefully degrades to a text link, doesn't hurt search engines and should work perfectly on all major browsers.

So, where does the magic happen?

Dave Shea's replacement method needs an extra - albeit empty - span element to which it attaches a background image. The replacement method will position the image on top of the link text so it gets hidden. The problem: how to add that extra span in your link? If you would take a look at the l() function in, you would notice it takes an extra $options argument. One valid option is $options['html']. If you set it TRUE, the text inside the link could also be HTML. Instead of directly putting an Only local images are allowed. tag inside the menu, my code puts in extra inside it. To do that, I need to alter the $primary_links array which is a formatted links array which theme_links() will accept. It just needs to be valid for the l() function which theme_links() envelopes. The final step is hooking the CSS onto it.


The main drawback of this method is inflexibility. If you start adding and removing items in primary_links, you need to update your CSS to add/remove the menu items you want to target with the replacement. Depending on the site, your client (or yourself),... you should guesstimate if your menu is subject to changes. If the menu is fixed (which it should be in most cases), this is a good and fast solution.

kettari’s picture

netsensei, thank you for your elegant solution! It saved my time and hair.

somanyfish’s picture

First extension: I used this technique for a menu I gave a name of "general." Drupal refers to this as menu-general, so I updated template_preprocess_page like this:

  $general_links = menu_navigation_links("menu-general");
  foreach ($general_links as $key => $link) {
    $general_links[$key]['html'] = TRUE;
    $general_links[$key]['title'] = '<span></span>' . $general_links[$key]['title'];
  $vars['general_links']     =  $general_links;

Then, in page.tpl.php, I print out this update menu via print theme('links', $general_links); .

Second extension: I have a block which displays the secondary menu. This time, the code goes in theme_preprocess_block:

function theme_preprocess_block(&$variables){
  $secondary_links = theme_get_setting('toggle_secondary_links') ? menu_secondary_links() : array();
  foreach ($secondary_links as $key => $link) {
    $secondary_links[$key]['html'] = TRUE;
    $secondary_links[$key]['title'] = '<span></span>' . $secondary_links[$key]['title'];
   $variables['secondary_links'] = $secondary_links;

In the specific block.tpl.php file, I use print theme('links', $variables['secondary_links']); to output the updated link html.

dcolumbus’s picture

What is "template_preprocess_page" ... is this theme dependent? I'm using Genesis for all of my custom themeing... where would I implement this?

netsensei’s picture

1. copy & paste the code in your template.php of your theme
2. rename template_preprocess_page(&$vars) to either <yourthemename>_preprocess_page(&$vars) OR phptemplate_preprocess_page(&$vars)

Refer to my answer in this thread: :-)

visuallemon’s picture

any ideas how to hide that text if i gonna use images with transparent background?

mzwyssig’s picture

You can do this with CSS, something like li a {visibility:hidden}

designate’s picture


Thanks for the code, works like a charm. I am only missing the sub items relating to a specific menu item. When linking them to a specific menu item [primary-links] the submenu is not shown. Any[body] ideas?

Regards, Rob

update: used module menu attributes as described in

Designate web development
+31 (0)229 708 000

itpaul’s picture


I believe I correctly followed the instructions on and added this text to the template.php file

function phptemplate_menu_item_link($item, $link_item) {
if( strpos($item['title'], 'Only local images are allowed. return l($item['title'], $link_item['path'], !empty($item['description']) ? array('title' => $item['description']) : array(), NULL, NULL, FALSE, TRUE);

return l($item['title'], $link_item['path'], !empty($item['description']) ? array('title' => $item['description']) : array());

I'm trying to add a facebook image as a menu item that links to our facebook page

Then on the secondary links (note: there actually is a '<' sign before the 'img' tags below and a '>' sign after the '/')
"Menu Links Title:" img src="/sites/default/files/facebook.gif" /
"Description:" Facebook

The link to the page works!
The link on the secondary link displays the img tag : img src="/sites/default/files/facebook.gif"
when it should show the facebook.gif

What am I doing wrong?

baff’s picture


solona’s picture

m0and1k3’s picture

I'm using megamenus for my primary links. I want an image to appear for one of the menu items and cannot get it to work. I have tried adding things to my template and no success. I have tried modules like sprite graphic menu and menu icon and have had a slight bit more success. They are able to see my picture but instead of adding it to the menu, the image appears in the menu items list alongside the title. Modules are great but I would prefer to be able to add html img tag to my menu's description and have that work. Ideas? Drupal 6

SuperRookie’s picture

I've been playing around trying to get images to work as menu items in drupal 7. Using a piece of code I was able to get here:

I was able to get the images to display and function correctly in d7. I used the following code in my template.php file:

* Implements theme_links()
function earthish_links__system_main_menu($data) {
  // Allows for images as menu items. Just supply the path to the image as the title
  foreach($data['links'] as $name=>$link) {
    if (strpos($link['title'], '.png') !== false || strpos($link['title'], '.jpg') !== false || strpos($link['title'], '.gif') !== false) {

    $variables = array(
      'path' => $link['title'],
      'alt' => $link['attributes']['title'],
      'title' => $link['attributes']['title'],
      'attributes' => array('class' => 'main-menu-image', 'id' => $name . '-image'),
    $link['title'] = $img = theme('image', $variables);
    $link['html'] = TRUE;  //otherwise theme_link will use check_plain on the title
  return theme('links', $data);

The images are now displaying correctly in the menu, but it is returning the following errors seven times, one pair for each menu item:

Notice: Undefined index: title in earthish_links__system_main_menu() (line 89 of /home/.../sites/all/themes/earthish/template.php).
Notice: Undefined index: title in earthish_links__system_main_menu() (line 90 of /home/.../sites/all/themes/earthish/template.php)

Anyone know why? I would love to leave my graphic menu!


hydde’s picture

I used the menu_attributes module to solve my imaging needs.

It allowed me to ID drupal generated menu items.

After that it was just a matter of messing with my theme's CSS.

#main-menu li a{
display: inline-block;
width: 75px;
height: 60px;
font-size: 0;

#main-menu-item-1 {
background-image: url("whateverimageyouneed.jpg");

The module places the ID on the anchor inside your menu item rather than the li item itself. This means you'll have to adjust the CSS of your anchors to allow them to have an image. I did this by first changing the inline positioning style to inline-block because only then I could effectively resize the anchor items.
Next thing I did was resizing the links to the size of the images. Font-size 0 is to hide the original menu title which is required to create the menu-item (since the CSS only targets the specific menu-items defined in your CSS, the name title stays intact inside your menu managing page, which is nice menu-managing wise.)
And I finished by using the menu list item's ID to give it its own specific image using the background-image style.

It's not a very clean way to do it, but it does the job. And a great benefit to it is that it allows for li:hover alternative images to be defined.

andabeat’s picture

Thanks for all contributions,
Using the Superfish module in D7 I could achieve the same result with out adding Menu Attributions module but by simply applying your CSS styling tips to the Superfish style sheet.

syednayab’s picture

Hi i am wondering if menu could be made like this site or something similar , you would find all the menus are done in images, some of the shopping sites even have same feature,
any tutorial like would be great. Thanks...