Tell me more ×
Drupal Answers is a question and answer site for Drupal developers and administrators. It's 100% free, no registration required.

How do you set an id for the menu's root <ul> tag?

I know about the module "Menu Attributes" but that doesn't let me add an ID to the root <ul>, or at least I do not know how.

Also, I've seen a solution which uses theme_menu_tree() and a regex check, but that's just too hacky for my taste.

share|improve this question

3 Answers

In D7 default theme bartik, you can see the main menu is rendered using a theme hook links__system_main_menu:

 <div id="main-menu" class="navigation">
    <?php print theme('links__system_main_menu', array(
      'links' => $main_menu,
      'attributes' => array(
        'id' => 'main-menu-links',
        'class' => array('links', 'clearfix'),
      ),
      'heading' => array(
        'text' => t('Main menu'),
        'level' => 'h2',
        'class' => array('element-invisible'),
      ),
    )); ?>
  </div> <!-- /#main-menu -->

links__system_main_menu is a theme hook pattern of the form [base hook]__[context]. When links are themed with theme('links__system_main_menu', $vars), theme() will search for and use theme_links__system_main_menu() if it has been defined. If not, it will use theme_links().

Drupal will use MYTHEME_links__system_main_menu(), if you define it in your theme. Thus, you could implement the hook_links__system_main_menu as follows. Probably you will do that in the template.php file in your theme folder.:

function mytheme_links__system_main_menu($variables) {
  $html = "<div>\n";
  $html .= "  <ul id=\"your_id\">\n";  
  foreach ($variables['links'] as $key => $link) {
    $html .= "<li>".l($link['title'], $link['path'], $link)."</li>";
  }
  $html .= "  </ul>\n";
  $html .= "</div>\n";

  return $html;
}

This will override the links__system_main_menu theme and customize HTML output for the main menu.

[Edit]

If you are looking for the quickest way, you just need to tweak your page.tpl.php by adding an extra wrapper to the menu ul.
For example, in the Bartik theme,

  <div id="main-menu" class="navigation">
    <div id="your-id">
    <?php print theme('links__system_main_menu', array(
      'links' => $main_menu,
      'attributes' => array(
        'id' => 'main-menu-links',
        'class' => array('links', 'clearfix'),
      ),
      'heading' => array(
        'text' => t('Main menu'),
        'level' => 'h2',
        'class' => array('element-invisible'),
      ),
    )); ?>
    </div>
  </div> <!-- /#main-menu -->

Then, you can access it using #your-id ul{ } in CSS or $('#your-id ul') in JS. But, the above code is just for example, you should not hack the core themes or modules. I assume you have your own theme.

share|improve this answer
So I basically have to recreate the whole menu structure just so that I can put a html attribute in an already existing menu? I am not sure about this. Why is this better than just search/replace? – Ashnur Nov 15 '12 at 3:54
So, you used the hook mytheme_links__system_main_menu as my answer? – Sithu Nov 15 '12 at 4:20
yes, I did try out this solution, and it does work, but it kinda freaks me out. I have to edit two files, add a lot of arbitrary code which does not have any correlation with the original issue, which is, adding a simple html id attribute to a specific ul tag. – Ashnur Nov 15 '12 at 4:24
I just updated my answer. Please see the Edit section. It would be a simplest solution. – Sithu Nov 15 '12 at 4:53
1  
@Ashnur: if you want to create the html document as you like, I think you should not use Drupal. If you use Drupal, you have to follow Drupal's rules, standards and API, but you can feel the power of Drupal. Theming in Drupal is not as simple as creating a custom html file. – Sithu Nov 16 '12 at 3:13
show 6 more comments

You want to overwrite menu tree theming function as I mentioned in IRC. Easiest way would be to copy the attribute usage from theme_links.

Using this method does affect all menus, but it doesn't change anything for those which doesn't use attributes.

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

// Overwritten theme_menu_tree
function YOURTHEME_menu_tree($variables) {
  $attributes = array("class" => array("menu"));
  if(isset($variables['attributes']))
    $attributes = array_merge_recursive($attributes, $variables['attributes']);
  return '<ul' . drupal_attributes($attributes) . '>' . $variables['tree'] . '</ul>';
}
share|improve this answer
2  
That will affect every call to theme_menu_tree() though. As the OP wants to add a css ID (most likely a specific one), this isn't really an option as it will result in multiple elements with the same ID. You wouldn't even get away with using drupal_html_id() as I imagine the whole point of this is so that the OP can set a predictable ID to target with CSS – Clive Nov 15 '12 at 15:38
I found a working hack with this approach where we use a string lookup to be sure we are modifying the one node we want to modyfy. I guess if this function could get a bit more info about what it's contents are going to be, it wouldn't be so hacky, but I am unsure if that's possible to achieve just with hooks. – Ashnur Nov 15 '12 at 17:16

I managed to get it right with the following code, based on @Sithu's response

function themename_links__system_main_menu($variables) {  
    $html = '<ul id="menu">'."\n";  
    foreach ($variables['links']['system_main-menu'] as $key => $link) {  
        if(is_array($link)){  
            $html .= "<li>".l($link['#title'], $link['#href'], $link)."</li>";  
        }                                                                                                                       
    }  
    $html .= "  </ul>\n";  
    return $html;  
}
share|improve this answer
but I still don't think that this should be the accepted answer. It's just way to much code for such a simple thing. – Ashnur Nov 15 '12 at 4:21
Why did you post the same answer as a different post? This is not a way of this community. – Sithu Nov 15 '12 at 4:55
If you read it carefully you will see that it's not quite the same answer. The one you posted thrown a lot of errors, this one worked for me. – Ashnur Nov 15 '12 at 12:28
Yes, I can see that, but the logic and hook usage are the same. I did not expect from you to accept my answer. And you should not also expect error-free ready-made codes from this community. You can also see some accepted answers in this site are just advice. – Sithu Nov 15 '12 at 15:30

Your Answer

 
discard

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.