I was wondering if there is an override or a module out there that would allow me to set a custom CSS id for a menu item.

It would help me greatly so I can style each menu item separately.

Comments

derekwebb1’s picture

Hello,

You may try creating your own function and then using that one for the links that you want to modify.

I created a custom function to handle JUST my primaries and that works well for me.

I called mine theme_name_custom_primaries() -- Note that this function does not end in (links), this is for a reason. Using the theme override (as in - theme_name_links()) to manipulate just one set of links is a bad practice as it can quickly get out of hand if you need different changes for different menus.

Regards, Derek
http://collectivecolors.com

mruzekw’s picture

Hello,

Could you give a concrete example what you mean? I learn by example, and I'm a complete novice compared to others.

Thanks,
Will (linuxlover101)

derekwebb1’s picture

This is the function that I use to render my primaries at the (NEW) CollectiveColors site (You cant see it yet - still in the works)

/**
 * Return a themed set of links.
 *
 * @param $links
 *   A keyed array of links to be themed.
 * @param $attributes
 *   A keyed array of attributes
 * @return
 *   A string containing an unordered list of links.
 */
function cc_primary_links($links, $attributes = array('class' => 'links')) {
  global $language;
  $output = '';

  if (count($links) > 0) {
    $output = '<ul'. drupal_attributes($attributes) .'>';

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

    foreach ($links as $key => $link) {
      $class = $key . ' link-' . $i;
			$link['attributes']['class'] = 'link-' . $i;  

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

      if ($i == 1) {
      	$link['html'] = TRUE;
      	$output .= l('<div id="home-button"></div>', $link['href'], $link);
      }
      else {
      	// Pass in $link as $options, they share the same keys.
      	$output .= l($link['title'], $link['href'], $link);
      }
      $i++;
      $output .= "</li>\n";
    }

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

  return $output;
}

You may notice that it is simply just a hacked up version of the regular theme_links function. I used this to number the links classes and, subsequently, modify the first (Home links)...

Here is what it looks like in use (page.tpt.php)

<?php print cc_primary_links($primary_links, array('id' => 'primary')) ?>

Hope that helps. I am not saying what I did was "right" though. But it does work, and it leaves all the other links alone.

Regards, Derek
http://collectivecolors.com

mrugesh_drupal’s picture

Hi linuxlover,

I want to suggest you to store the menu id in the varibale_set('_', ''); and get the varibale according the menuid. I think it will solve your problem easily.

OR

one hard way is to create one another table table and write the trigger when insertion goto menu_links store the menuid and your css id into the table. Same thing for update and delete the menu item.

And get the css id from custom table by querying into our custom table.

Hope this will help you. Or you have better solution than this plz let me know.

Thanks,
Mrugesh Panchal

mruzekw’s picture

Hello,

Your second option seems very complicated, so I'd like to focus on the first one.

I'm fairly new to Drupal and consider myself a novice compared to others. Could you give an example of a variable set for my situation?

Thanks,
Will (linuxlover101)

mrugesh_drupal’s picture

Please call this function in your main page.tpl.php file.

Please read and every line carefully. Might be it would be helpful to you.???

/**
 * get primary menu items as per theme's style css
 */
function phptempalte_get_primary_links($primary_links) {
	global $user, $base_url; 
	$strPLinks = "";
	
	if (count($primary_links) > 0) {
		
		foreach ($primary_links as $pl) {
			
			//getting the alias for menu
			if(drupal_lookup_path('alias', $pl['href'])) {
				$link = $base_url .'/'. drupal_lookup_path('alias', $pl['href']);  // If alias found return this link
			} else {
				$link = $base_url.'/'.$pl['href']; // If alias not found return this link
			}
			
			// Applyin class for selected menu item.
			if (strcmp(drupal_lookup_path('alias', $pl['href']), drupal_lookup_path('alias', 'node/'.db_escape_string(trim(arg(1))))) == 0) {
				$class .= "mnuItemSelected ";
			}
			
                        // Here write your custom code for applying class 
                        if (menu_get_active_title() == 'HOME') {
                                $class .= " homeclass"; // applying home class for home link or home menu item
                        }
			
                        $strPLinks .= '<li><a href="'.$link.'" title="'.$pl['title'].'" class="'.$class.'">'.$pl['title'].'</a></li>';
			$class = '';
			
		}
	}
	
	return $strPLinks;
}

Thank you,
Mrugesh Panchal

mruzekw’s picture

I did some more research and looked through the API and found the theme_menu_item function.

I'm thinking more along the lines of this snippet of code (stolen from http://drupal.org/node/67457#comment-864218):

function YourThemeName_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
  $class = ($menu ? 'expanded' : ($has_children ? 'collapsed' : 'leaf'));
  if (!empty($extra_class)) {
    $class .= ' '. $extra_class;
  }
  if ($in_active_trail) {
    $class .= ' active-trail';
  }
  //Strip link of tags to reveal the link name only to use as the CSS id
  $id = preg_replace("/[^a-zA-Z0-9]/", "", strip_tags($link));
  return '<li id="'.$id.'" class="'. $class .'">'. $link . $menu ."</li>\n";
}

With this snippet I can just use the link name as the id, which is adequate if the site I'm building has static primary links.

When I place the snippet in my template.php file, clear the cache, and load the page: nothing changes.
I then used the devel module to show me what function was rendering the primary links (what I mainly want to style). It said theme_links() rather than theme_menu_item() was rendering the menu. Could this be an explanation why something didn't happen? Should I override the theme_links() instead?

Thanks,
Will

mruzekw’s picture

I went ahead and tried an override for theme_links() and it worked.

Here is the code:

function theme_links($links, $attributes = array('class' => 'links')) {
  global $language;
  $output = '';

  if (count($links) > 0) {
    $output = '<ul'. drupal_attributes($attributes) .'>';

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

    foreach ($links as $key => $link) {
      $class = $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) {
        $class .= ' last';
      }
      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))
          && (empty($link['language']) || $link['language']->language == $language->language)) {
        $class .= ' active';
      }
      //Strip link title of spaces and make everything undercase to use as the CSS id
      $id = strtolower(preg_replace("/[^a-zA-Z0-9]/", "", strip_tags($link['title'])));
      $output .= '<li id="'.$id.'"'. 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);
      }
      else if (!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;
}

Any ideas why theme_menu_item() didn't work?

Is there a way I could just focus on the primary links instead of all of the links on the page?

Any simpler fixes?

Thanks,
Will

derekwebb1’s picture

That's why I was saying to make a special function to deal with only those menus that you wanted to manipulate. Then you call that function instead of the regular theme links.

Having a series of cases to deal with each of your menus is not a good practice as it can rapidly escalate into incomprehensible garbage code... It looks like what you have should not have too much adverse impact though so good work. That will, as you noted, apply to (almost) all links but if it doesn't get in your way I see no reason why what you have would not be a decent solution.

Derek
http://collectivecolors.com

mruzekw’s picture

Thank you very much for your help; I have implemented a solution that seems to be working fine. I'll make sure to refer back to this if I need to change anything.

apt94jesse’s picture