Drupal Answers is a question and answer site for Drupal developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Drupal 7.

For example no matter what menu block would be added to the header region, how can I make it replace first link (which has .first class) with image link?

So Drupal generates links as <li class=first><a href="#">Home</a></li> and then apply some function from template.php which would replace it with something like <li class=first><a href="#"><img src='../link.png'></img></a></li>

I found some code which kind of does that, but it needs to enter path to image via Add link under Title field and I don't really need that, the users of the theme won't understand how that works. And it also applies to any links. While I need to switch the very first text link with image link whose path would be given inside template.php

* Allows for images as menu items.
* Just supply the an image path in the title. The image path will be replaced
* with an img tag. The description is used as alt text and title.
* Implements theme_menu_link().
* Reference: http://chrisshattuck.com/blog/how-use-images-menu-items-drupal-simple-preprocessing-function
function YOUR_THEME_menu_link($variables) {
  $element = &$variables['element'];

  $pattern = '/\S+\.(png|gif|jpg)\b/i';
  if (preg_match($pattern, $element['#title'], $matches) > 0) {
    $element['#title'] = preg_replace($pattern,
      '<img alt = "' . $element['#localized_options']['attributes']['title'] . '" src = "' . url($matches[0]) . '" />',
    $element['#localized_options']['html'] = TRUE;

  return theme_menu_link($variables);

I can do that with CSS, but I prefer not (client side reasons).

share|improve this question
What do you mean by "I can do that with CSS, but I prefer not (client side reasons)."? Are you saying you can't use a CSS background image instead of an actual image element in the markup? – MPD Jan 29 '13 at 21:58
A CSS background image sounds like the way to go there. Either you load an image from HTML or you load an image via CSS, either way it's an HTTP request to the server. If you combine the background image in a CSS sprite, the CSS option is more performant. – David Thomas Jan 29 '13 at 22:53
Or you use css_emimage. And for the CSS selector you can use :first-child, I think the web has evolved enough to make this a viable option. – donquixote Nov 7 '13 at 20:16
up vote 2 down vote accepted

You can override theme_menu_tree. All it does is output UL tags, so you could squeeze in an LI at the beginning, like this:

    function mycustomtheme_menu_tree($variables) {
      $path = drupal_get_path('theme', 'mycustomtheme') . '/images/home.png';
      $image = theme('image', array('path' => $path, 'alt' => t('Home'), 'title' => t('Home')));
      $home_link = l($image, '', array('html' => TRUE));
      $home_li = '<li class="home">' . $home_link . '</li>';
      return '<ul class="menu">' . $home_li . $variables['tree'] . '</ul>';

I've done this exact thing on several sites (but I use nice_menus), here's the code I added to my template.php file in my custom theme:

    function mycustomtheme_nice_menus_tree($variables) {
      $menu_name = $variables['menu_name'];
      $mlid = $variables['mlid'];
      $depth = $variables['depth'];
      $menu = $variables['menu'];
      // Load the full menu array.
      $menu = isset($menu) ? $menu : menu_tree_all_data($menu_name);
      if (isset($menu)) {
        $page_menu = menu_tree_page_data($menu_name);
        $trail = nice_menus_build_page_trail($page_menu);

      // Allow i18n module to translate strings where available.
      if (module_exists('i18n_menu')) {
        $menu = i18n_menu_localize_tree($menu);

      // Assume depth == 0 by default, overriden if mlid is specified.
      $parent_depth = 0;

      // For custom $menus and menus built all the way from the top-level we
      // don't need to "create" the specific sub-menu and we need to get the title
      // from the $menu_name since there is no "parent item" array.

      // Create the specific menu if we have a mlid.
      if (!empty($mlid)) {
        // Load the parent menu item.
        $item = menu_link_load($mlid);
        // The depth for our parent item, if it exists.
        $parent_depth = ($item['depth']) ? $item['depth'] : 0;

        // Narrow down the full menu to the specific sub-tree we need.
        for ($p = 1; $p < 10; $p++) {
          if ($sub_mlid = $item["p$p"]) {
            $subitem = menu_link_load($sub_mlid);
            // Menu sets these ghetto-ass keys in _menu_tree_check_access().
            $menu = $menu[(50000 + $subitem['weight']) . ' ' . $subitem['title'] . ' ' . $subitem['mlid']]['below'];

      $output['content'] = '';

      if ($menu) {
        // Set the total menu depth counting from this parent if we need it.
        $depth =  ($depth > 0) ? ($parent_depth + $depth) : $depth;
        $output['content'] .= theme('nice_menus_build', array('menu' => $menu, 'depth' => $depth, 'trail' => $trail));

      /* my changes */
      $path = drupal_get_path('theme', 'mycustomtheme') . '/images/home.png';
      $image = theme('image', array('path' => $path, 'alt' => t('Home'), 'title' => t('Home')));
      $home_link = l($image, '', array('html' => TRUE));
      $home_li = '<li class="home">' . $home_link . '</li>';

      $output['content'] = $home_li . $output['content'];
      $output['subject'] = '';

      return $output;
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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