Add unique IDs to menu items

Last modified: August 25, 2009 - 02:44

This adds unique IDs (using the link's text) to any menu items so you can style them uniquely in your CSS.

In your template.php:

<?php
function phptemplate_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';
  }
 
$id = preg_replace("/[^a-zA-Z0-9]/", "", strip_tags($link));
  return
'<li id="'.$id.'" class="'. $class .'">'. $link . $menu ."</li>\n";
}
?>

Can't seem to get this to work

parkej60 - November 4, 2008 - 18:47

Do I simply copy this into the header of my page.tpl.php file or do I copy it into a different file.

It says template.php

Flying Drupalist - November 4, 2008 - 23:42

It says template.php

i copied it into

linwj - April 7, 2009 - 06:44

*for drupal 6*
i copied it into template.php

other functions such as phptemplate_menu_local_tasks are there

but i dont see a phptemplate_menu_item function

after i updated template.php

it doesnt seem to work




how is the function called ?

i looked in page.tpl.php

this is the part which renders the menu but i dont see how it gets linked to phptemplate_menu_item

<?php
if (isset($primary_links)) {
?>

<?php
print theme('links', $primary_links, array('class' =>'links', 'id' => 'navlist'))
?>

<?php
}
?>

This is not technically unique

zzolo - January 20, 2009 - 03:49

This is not technically accurate since you could have the same menu items on different menus or even the same menu. The following is actually unique.

This makes each item unique and adds the semi-unique as a class instead.

<?php
/**
* Theme override for theme_menu_item()
*/
function phptemplate_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';
  }
 
 
// Add unique identifier
 
static $item_id = 0;
 
$item_id += 1;
 
$id .= ' ' . 'menu-item-custom-id-' . $item_id;
 
// Add semi-unique class
 
$class .= ' ' . preg_replace("/[^a-zA-Z0-9]/", "", strip_tags($link));
 
  return
'<li class="'. $class .'" id="' . $id . '">'. $link . $menu ."</li>\n";
}
?>

--
zzolo
Chicago Technology Cooperative
AlanPalazzolo.com

Very helpful, thank you.

Flying Drupalist - January 23, 2009 - 20:40

Very helpful, thank you.

I was looking for this

vivianspencer - February 7, 2009 - 00:27

I was looking for this everywhere for this functionality, and it works perfectly, thank you

I also needed the same functionality for Drupal 5, here's what I used

<?php
function phptemplate_menu_item($mid, $children = '', $leaf = TRUE, $extraclass = '') {
 
// Add unique identifier
 
static $item_id = 0;
 
$item_id += 1;
 
$id .= 'menu-item-custom-id-' . $item_id;
  return
'<li id="' . $id . '" class="'. ($leaf ? 'leaf' : ($children ? 'expanded' : 'collapsed')) . ($extraclass ? ' ' . $extraclass : '') . '">'. menu_item_link($mid, TRUE, $extraclass) . $children ."</li>\n";
}
?>

- Vivian

I found a few glitches with

vivianspencer - February 7, 2009 - 10:03

I found a few glitches with the code used above for Drupal 5, here's a better version I found here and adapted for D5: http://drupal.org/node/267231#comment-873005

<?php
function getMenuItemCounter($case=null){
  static
$counter = 1;
  return (
$case == 'reset') ? $counter=1 : $counter++ ;
}

function
YOURTHEME_menu_tree($pid = 1) {
 
getMenuItemCounter("reset");
  if (
$tree = menu_tree($pid)) {
    return
"\n<ul class=\"menu\">\n". $tree ."\n</ul>\n";
  }
}

function
phptemplate_menu_item($mid, $children = '', $leaf = TRUE, $extraclass = '') {
 
$counter = getMenuItemCounter();
  return
'<li id="menu-item-custom-id-' . $counter . '" class="'. ($leaf ? 'leaf' : ($children ? 'expanded' : 'collapsed')) . ($extraclass ? ' ' . $extraclass : '') . '">'. menu_item_link($mid, TRUE, $extraclass) . $children ."</li>\n";
}
?>

- Vivian

$item_id to Node ID

green2009 - July 7, 2009 - 04:02

Hello.

  // Add unique identifier
  static $item_id = 0;
  $item_id += 1;
  $id .= ' ' . 'menu-item-custom-id-' . $item_id;

How can replace $item_id to Node ID?

item id counter

mojos - March 23, 2009 - 05:46

the item_id counter gets incremented too many times. seems like it gets incremented even if the link is not part of the given menu. how can I test to see if the menu_item belongs to a given menu before incrementing it?

Alternate solution using javascript

yougo - July 4, 2009 - 01:25

I know these posts are about theming but I think this could help.
In my page I need to have unique IDs for navigation menu items AND the IDs must be in ascending order 1, 2, 3, 4, ... (I have to link a background img depending on item position so the second item must have id 2).
The solutions I've found here, although they guarantee an unique ID, can result in unordered IDs in case of submenus. E.g. a father node has ID 3 while the two children 1 and 2.

I was able to fix the issue adding this javascript that makes use of jquery:

Drupal.behaviors.doIt = function(context) {
  $("#navigation-menu").children().attr("id", function(index) {
    return "item-id-" + index;
  });
}

Just created a js file and added it to the mytheme.info file, and that's it.

Hope this helps.
yougo

Primary likns

Mike-K - January 28, 2009 - 20:39

It seems I can only get this to work on the "navigation" menu. How do I implement unique IDs on the Primary menu links?

How to add/link icons from CSS

balik kampung - March 3, 2009 - 03:21

Could some one help me on the next step. It is explained of how to create unique ID's for menu items but how to add icons for those unique ID's?.
How do i know which ID is for which menu item? Sample code/example please.

Thanks

Greatness!

ionz149 - March 27, 2009 - 20:43

This is just what I was looking for, many thanks.

Keepin' it creature

Zen

GreenSkunk - September 15, 2009 - 18:11

If you are using a Zen-based theme you can use the Zen function zen_id_safe
replace line
$id = preg_replace("/[^a-zA-Z0-9]/", "", strip_tags($link));
with
$id = zen_id_safe(strip_tags($link));

It is a damn poor day when you don't learn something!

so close...

njacobson - October 1, 2009 - 03:12

So, I need to add a unique class to each secondary menu ul. If that doesn't make sense, here's an example

I have one menu. My menu has 4 primary items and about 6 secondary items under each primary.
My page design shows all primary items and the expanded secondary menu for that section.

I need to be able to style (through css) the secondary menu items differently for each section. So for sectionA, the secondary menu has a margin of 100px. For sectionB, the secondary menu has a margin of 300px and on...

There is currently only an id="secondary-links" on my ul tag. I need to add a unique class or id for each secondary ul based on the primary link.

Using the genesis theme starter if that makes a difference. Help appreciated!

Hi, Njacobson. I don't know

pawel.traczynski - October 30, 2009 - 00:15

Hi, Njacobson.

I don't know what exacltly are you trying to achieve but you can use jQuery to do what you want.
The jQuery code should by added to your script.js file, in your theme directory.

First let's select all the 'li' elements of the menu, but without selecting their children 'li' elements (only top-level li elements).
Also for each selected 'li' tag select it's first 'a' child tag, and check it's value of "title" parameter (configurable via admin interface Admin -> Build -> Menus).

We save the 'title' value in a variable parentATitle (and optionally we remove the title parameter from the 'a' tag).

$(document).ready(function() {
  $('#secondary-links ul li').not($('#secondary-links ul li li').each(function() {
    var parentLi = $(this);
    var parentATitle = $(parentLi + ' a:first').attr('title').removeAttr('title');
  });
});

Now we will add more code, which will use the parent 'a' tag value to add a new class to the child 'ul' tag.

$(document).ready(function() {
  $('#secondary-links ul li').not($('#secondary-links ul li li').each(function() {
    var parentLi = $(this);
    var parentATitle = $(parentLi + ' a:first').attr('title').removeAttr('title');

    $(parentLi + ' ul').not(parentLi + ' ul ul').addClass('class-' + parentATitle);
  });
});

So now if you have a structure like:

<ul id="secondary-links">
  <li>
    <a href="" title="main">X</a>
    <u>
        <li><a href="">A</a></li>
        <li><a href="">B</a></li>
        <li><a href="">C</a></li>
    </ul>
  </li>
  <li>
    <a href="" title="second">Y</a>
    <u>
        <li><a href="">D</a></li>
        <li><a href="">E</a></li>
        <li><a href="">F</a></li>
    </ul>
  </li>
</ul>

and you use the above jQuery code, it will first select the X link, read it's title and apply this title as a part of a new class for the 'ul' containing link A, B and C (it's class will be "class-main"). The same will happen for the Y link. So the class of the 'ul' containg link D, E, F will be "class-second".

I hope it will help you somehow. jQuery is a nice javascript library :-)

Cheers!

Unique <ul>s

nelslynn - November 21, 2009 - 07:46

njacobson, did you find a solution to get unique UL s?

Sorry the JQuery above does not work for my situation. Really need unique IDs for the ULs in the secondary menu.

Thanks for any help.

 
 

Drupal is a registered trademark of Dries Buytaert.