0

I need to remove class .last from menu's <li>. I browsed this nice website for a solution and find some code that removes ALL classes:

function THEME_menu_link(array $variables) {
  //unset all the classes
  unset($variables['element']['#attributes']['class']);

  $element = $variables['element'];

  if($variables['element']['#attributes'])

  $sub_menu = '';


  if ($element['#below']) {
    $sub_menu = drupal_render($element['#below']);
  }
  $output = l($element['#title'], $element['#href'], $element['#localized_options']);
  return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}

And:

function mymod_menu_tree__menu_about_us($variables) {
  return '<ul class="side-menu">' . $variables['tree'] . '</ul>';
}

function mymod_menu_link__menu_about_us(array $variables) {
  $element = $variables['element'];
  $sub_menu = '';
  if ($element['#below']) {
    $sub_menu = drupal_render($element['#below']);
  }
  $class = "";
  $classes_of_this_li = $element['#attributes']['class'];
  if (in_array($classes_of_this_li, 'active-trail')) {
    $class = 'active';
  }
  $output = l($element['#title'], $element['#href']);
  return '<li class="' . $class . '">' . $output . $sub_menu . "</li>\n";
}

I need to remove only .last class and also somehow I need it to work only on a selected region. What I mean is that the function must apply to menus that are rendered i.e. in Sidebar region.

  • have you tried using str_replace function to replace the word last in the class variable. some thing like. str_replace(" last", " ", $class); – Mohammed Shameem Jan 31 '13 at 17:38
  • Can you give me a full code please? I am a beginner on this. – user13176 Jan 31 '13 at 18:52
0

You can do it like this:

/**
 * Theme menu links.
 */
function THEME_NAME_menu_link(array $variables) {
  $element = $variables['element'];
  $sub_menu = '';

  // This is the part that removes or changes the last class.
  if (!empty($element['#attributes']['class'])) {
    foreach ($element['#attributes']['class'] as $key => $class) {
      if ($class == 'last') {
        // Use only one of the two following lines.

        // To change the last class.
        $element['#attributes']['class'][$key] = 'new-last-class';
        // To remove the last class.
        unset($element['#attributes']['class'][$key]);
      }
    }
  }

  if ($element['#below']) {
    $sub_menu = drupal_render($element['#below']);
  }
  $output = l($element['#title'], $element['#href'], $element['#localized_options']);
  return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}

However, if you are referring to the primary links and secondary links as printed out by default in most themes, they do not run through that function, because they are generated by menu_main_menu() and menu_secondary_menu(), which in turn use theme_links() to generate the links instead of theme_menu_link() - very annoying.

So to get to those you either need to stop using theme default theme menus and use the menu blocks provided by default by the menu module. These blocks use the theme_menu_link() function to generate links so will be affected by the above code.

Alternatively, you would have to override theme_links() also, like so:

/**
 * Theme links.
 */
function THEME_NAME_links($variables) {
  $links = $variables['links'];
  $attributes = $variables['attributes'];
  $heading = $variables['heading'];
  global $language_url;
  $output = '';

  if (count($links) > 0) {
    $output = '';

    // Treat the heading first if it is present to prepend it to the
    // list of links.
    if (!empty($heading)) {
      if (is_string($heading)) {
        // Prepare the array that will be used when the passed heading
        // is a string.
        $heading = array(
          'text' => $heading,
          // Set the default level of the heading. 
          'level' => 'h2',
        );
      }
      $output .= '<' . $heading['level'];
      if (!empty($heading['class'])) {
        $output .= drupal_attributes(array('class' => $heading['class']));
      }
      $output .= '>' . check_plain($heading['text']) . '</' . $heading['level'] . '>';
    }

    $output .= '<ul' . drupal_attributes($attributes) . '>';

    $num_links = count($links);
    $i = 1;

    foreach ($links as $key => $link) {
      $class = array($key);

      // Add first, last and active classes to the list of links to help out themers.
      if ($i == 1) {
        $class[] = 'first';
      }
      if ($i == $num_links) {
        // *** Use this line to change the last class. ***
        // *** Or comment it out to have no last class. ***
        $class[] = 'new-last-class';
      }
      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))
           && (empty($link['language']) || $link['language']->language == $language_url->language)) {
        $class[] = 'active';
      }
      $output .= '<li' . drupal_attributes(array('class' => $class)) . '>';

      if (isset($link['href'])) {
        // Pass in $link as $options, they share the same keys.
        $output .= l($link['title'], $link['href'], $link);
      }
      elseif (!empty($link['title'])) {
        // Some links are actually not links, but we wrap these in <span> for adding title and class attributes.
        if (empty($link['html'])) {
          $link['title'] = check_plain($link['title']);
        }
        $span_attributes = '';
        if (isset($link['attributes'])) {
          $span_attributes = drupal_attributes($link['attributes']);
        }
        $output .= '<span' . $span_attributes . '>' . $link['title'] . '</span>';
      }

      $i++;
      $output .= "</li>\n";
    }

    $output .= '</ul>';
  }

  return $output;
}

I have added * to the start and end of comments for the line you need to be interested in. The problem with this approach (maybe it isn't a problem for your site) is that this affects a lot of other lists of links on the site, not just the two menus in question.

It is possible to use if ($attributes['id'] == 'main-menu-links') and if ($attributes['id'] == 'secondary-menu-links')

to distinguish between the main menus however that isn't foolproof and isn't the best idea.

For example, the important part of the above theme_links() would be:

if ($i == $num_links) {
  // This would skip the last class for main & secondary menus
  // but would keep it for other links lists.
  if ($attributes['id'] != 'main-menu-links' && $attributes['id'] != 'secondary-menu-links') {
    $class[] = 'last';
  }
}

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.