By default, Drupal outputs menus as this:
<ul class="menu">

How can you add an ID (or class) to the menu e.g.:
<ul id="menu_name">

I've spent ages searching for an answer, but there only seems to be techniques for modifying the <li> of the ULs (and not the ULs of themselves).

Being able to assign IDs/Classes is essential to target specific menus, so I'm surprised a solution isn't more readily available.

Comments

sagar ramgade’s picture

Check this there are lot of options available.
http://drupal.org/project/modules?text=menu%20class

Acquia certified Developer, Back end and Front specialist
Need help? Please use my contact form

big_smile’s picture

Thanks! But I would like to do without a module.

I have found this code:

 function phptemplate_menu_tree($tree) {
  return '<ul class="menu"'. 'id="' . $PUT-VARIABLE-HERE . '">' . $tree .'</ul>';
}

The code can be used in template.php to override the output of the <ul>. However, the only variable it seems to accept is $tree, which prints out all the contents of a <ul> and so is not very helpful.

Any ideas?

FranciscoLuz’s picture

Drupal in the Amazon Jungle

nevets’s picture

There are two ways to output menus. The first is as a block, since blocks have unique ids you can use those to target css to a given menu. The other way is to call the appropriate functions, in this case you can provide a wrapper div with a unique id.

big_smile’s picture

It's bad practice to wrap an element in a DIV to target when you can just as easily add a class or ID to the element directly.

Surely there must be away to assign a Class/ID to a UL.

I can't believe phptemplate_menu_tree only allows $tree. There must be a variable to get at least the name of the UL.

xpucto’s picture

I am facing exactly the same problem right now.The only way i think it can be fixed is by rewriting theme_item_list() function.Although, this doesn't seem to be the drupal way of doing it,because content is being duplicated for the sake of such a minor change.

big_smile’s picture

In the end, I used this code in template.php:

function phptemplate_menu_tree($tree) {
	foreach (count_chars($tree, 1) as $i => $val) {
  return '<ul class="menu"'. ' id="menu_' . $val . '">' . $tree .'</ul>';
}
  
}

The code works by counting how many characters there are in the menu and places it as an <UL> ID.
This is obviously a terrible thing to do, because each time you change your menus, the IDs will also change.
However, it is the only method I found for creating IDs for ULs without installing any modules.

2dareis2do’s picture

Ok I have used THEME_menu_tree_MENU as a variation:

function MYTHEME_menu_tree__MYMENU($vars) {
		  $html = '<input type="checkbox" id="toggle" /><label for="toggle" class="toggle"></label>';
	    foreach (count_chars($vars['tree'], 1) as $i => $val) {
      return $html . '<ul class="menu clearfix" id="menu_' . $val . '">' . $vars['tree'] . '</ul>';
    }
}

so this targets the specific menu but we still have derivatives that seem to be affected such as menu block. Therefore we can use this to also add a specific id, although it would be good to have a better id naming convention than count_chars.

This example is useful if you want to have a css toggle.

http://micjamking.github.io/Navigataur/

FranciscoLuz’s picture

In your template.php

//Set a global variable containing the current region name
function phptemplate_blocks($region) {
  global $_current_region;
  $_current_region = $region;
  $output = theme_blocks($region);
  
  return $output; 
} 

function YOURTHEME_menu_tree($tree) {
//get the global variable containg the current region name we've just set
global $_current_region;

switch($_current_region){
   case 'my_region_1':
       $output = '<ul class="whatEverYouLike">'. $tree .'</ul>';
       break;
   case 'my_region_2':
       $output = '<ul class="somethingElse">'. $tree .'</ul>';
       break;
    default:
      $output = '<ul class="menu">'. $tree .'</ul>';
}

  return $output;
}

Drupal in the Amazon Jungle

knospe’s picture

is there something like this for D7?

FranciscoLuz’s picture

I haven't tried but believe it is pretty much the same thing. The only difference is that $tree is no longer present but $variables.

You can find more here:
http://api.drupal.org/api/drupal/includes--menu.inc/function/theme_menu_...

Drupal in the Amazon Jungle

henrijs.seso’s picture

And another approach if you need ULs and LIs with depth classes - https://gist.github.com/henrijs/6225177.

sknightq’s picture

What i want to do: In [Header] region, I want to add two menus, one is for normal users, another one is for super admin( if normal users log in ,it will be hidden);
So, in your way, how to distinguish these menus in one region?

jaypan’s picture

Add both menus, and set the roles they should be displayed to in the block visibility settings.

Contact me to contract me for D7 -> D10/11 migrations.

sknightq’s picture

Thank you for your reply! But I don't know what you mean. There are two menus in my [header] region. I have done it as FranciscoLuz said, these two menus have the same class. As the following:
-------------------------------------------------------------------------------
case 'header':
$output = '

    '. $tree .'

';
break;
-------------------------------------------------------------------------------

    menu1

'

    menu2

'
-------------------------------------------------------------------------------
I want to have different classes for them.

jaypan’s picture

When you create a menu, it creates a block that you drop into a region to display the menu. In the block configuration settings you can choose which roles can see the menu. Set one of the menus to be shown to anonymous users, the other to be shown to authenticated users. Users will only ever be one or the other, so they will only ever see a single menu.

Contact me to contract me for D7 -> D10/11 migrations.

tumblingmug’s picture

To substitute <ul class="menu"> with your own class or id for a specific menu tree, you can do this inside your template.php:

function phptemplate_preprocess_page(&$vars) {
  $vars['nav_menu'] = str_replace('class="menu"', 'class="myclass"', menu_tree('navigation'));
  $vars['prim_menu'] = str_replace('class="menu"', 'id="myid"', menu_tree('primary-links'));
}

Afterwards you can place these newly generated variables inside your page.tpl.php:

  <!-- HTML stuff -->
  <?php print $pri_menu; ?>
  <!-- HTML stuff -->
  <?php print $nav_menu; ?>
  <!-- HTML stuff -->

Cheers.

xalexas’s picture

Is there any way to set class name to children menus? Like:

<ul class="first-level">
<li>
<ul class="second-level"><li></li></ul>
</li>
</ul>

With your solution ul in every level will have class "first-level".

Thanks.

big_smile’s picture

Thanks for the solutions FranciscoLuz & tumblingmug! Much appreciated!

It's a shame that you have to specify the name of the menus. It would be nice if you created a menu and Drupal automatically generated a menu ID based on the menu name.

Are there any solutions to UL ID's in Drupal 7?

FranciscoLuz’s picture

It shouldn't be too hard to create a module that would implement the menu core module or submit a patch to menu module maintainer.

A patch should create an extra database field in the menu_custom table called say class then add a form field in menu.admin.inc at line 410 which could also be called class and adjust that into the SQL queries at line 529 (menu_edit_menu_submit).

Drupal in the Amazon Jungle

FranciscoLuz’s picture

You could also generate a name based class by slightly changing my solution to:

$output = '<ul class="menu-"'.$tree["menu-name"].'">'. $tree .'</ul>';

Drupal in the Amazon Jungle

sashainparis’s picture

print theme('links', menu_navigation_links('menu-nav-main'),array('id' => 'nav_main'));
I used this code in my page.tpl.php: You might want to use variables and put it in your template.php file instead - so it will be automaticly available for every menu.

Alexandre

mroscar’s picture

after strugling all find some solution with less coding.. that may have performance issue please let me know if we can reduce this problem

// Preprocess_block for classes and js as vars as well-----------------------------------------------
function theme_preprocess_block(&$vars) {

.......

       $block = $vars['block'];
       if ($block->module == 'menu') {
       $block->content = str_replace('class="menu"', 'class="menu myclass"', $block->content);
	}
				
........
  
} // end preprocess_block

you can add more conditions of course

drupik’s picture

Good solution. I think instead $block->content should be $vars['content'].

wooody’s picture

porridj’s picture

Just wanted to say that this chap (drupik) was right in changing the $block->content to $vars['content']

Worked a treat, cheers to you both :)

khaledelansari’s picture

I found an easy way to add an ID or Class name, just use the function YOURTHEME_menu_tree__YOURMENUNAME, in my case the theme name is in2pixel and the menu name is menu-footer-menu

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

PS: I'm using Drupal 7, I'm not sure if this will work for other drupal versions.

eric constantinides’s picture

Worked perfectly!!