A CSS ID for Every Menu Item

As you can see, these menu links have unique icons. Yet another miracle accomplished using Drupal's PHPTemplate. This technique is especially cool because it automatically generates CSS ID's from the menu link's name.

TEMPLATE.PHP: Override theme_menu_item() (includes/menu.inc)

<?php function phptemplate_menu_item($mid, $children = '', $leaf = TRUE) { return _phptemplate_callback('menu_item', array( 'leaf' => $leaf, 'mid' => $mid, 'children' => $children )); } ?>

Now create a menu_item.tpl.php file.

menu_item.tpl.php

<?php $link = menu_item_link($mid); // replace spaces with "_", and strip HTML $css_id = str_replace(' ', '_', strip_tags($link)); // render the menu link with unique CSS id. $output = '
  • '. $link . $children ."
  • \n"; print $output; ?>

    Now, we just include some CSS to make it work:

    CSS file

    ul.menu { margin-left:0; padding:0; } ul.menu ul { margin-left:1.5em; padding:0; } ul.menu li { list-style-image:none; list-style-type:none; margin:0; padding:0; } ul.menu li a{ background-repeat:no-repeat; padding:0 0 0 1.5em; background-position:left; font-size:1.1em; margin:0; } li#my_account a{ background-image:url(../art/menu_links/my_account.png); } li#administer a{ background-image:url(../art/menu_links/administration.png); } li#my_blog a{ background-image:url(../art/menu_links/my_blog.png); } li#create_content a{ background-image:url(../art/menu_links/create_content.png); } li#recent_posts a{ background-image:url(../art/menu_links/recent_posts.png); } li#log_out a{ background-image:url(../art/menu_links/log_out.png); }

    The icons, and CSS files are included in a downloadable example theme here.

    Comments

    This is a great tutorial but

    This is a great tutorial but could you possibly explain how one would remove the actual text link? So the image would act as the link, hope this makes sense. I've tried to work around the issue but no luck, any advice you could give would be greatly appreciated.

    Thanks

    Link this to taxonomy, too?

    I got this solution working for my main nav. I also wish for my main nav to know which item is "active" based on clicking a node in my secondary nav. That node will be linked by taxonomy to the main nav.
    How do I extend this to take what category the node I am viewing is on and tell the main nav which item should be active.

    Thanks for any help.
    Cheers,

    Adam

    download not found

    Hello,
    Would you be able to forward on the attached .zip file. I'd be very grateful. Many thanks in advance.
    vilmar@pti.org.br

    1-st thanks a lot:) This

    1-st thanks a lot:) This solution works fine for Drupal 5.2, but all child menu items have same icon as parent, so i made some changes I'd like 2 share with u;)

    menu_item.tpl.php

    <?php

    $link = menu_item_link($mid);
    // replace spaces with "_", and strip HTML
    $css_id = str_replace(' ', '_', strip_tags($link));
    // render the menu link with unique CSS id.
    $output = '

  • '. $link . "
  • \n

  • " .$children ."
  • \n";
    print $output;
    ?>

    Just what I needed

    I knew this was the kind of thing I needed. Thank god I found this site before reinventing the wheel. You're a star.

    Not for 5.1?

    First, thanks for this cool little tutorial. My main question: Is this not valid for 5.1? I commented out 'function theme_menu_item' in menu.inc, added your 'function phptemplate_menu_item' code to the end of menu.inc and created menu_item.tpl.php. The menu code is being output the same as before - with just an active class for the active link. I'm guessing that either I'm doing something wrong, or something different needs to be done for 5.1.

    I have the same problem.

    I have the same problem. Nick?

    I was confused for a little

    I was confused for a little while too.
    He meant to say: Add that code in the TEMPLATE.PHP file in your theme- in effect it will override "theme_menu_item()"

    Actually solved the localization problem

    If I had waited just two moments before pressing submit to my previous post I would have posted the solution right away. Instead of using str_replace(' ', '_', strip_tags($link)); to generate the id I used $mid in the following way:

    $css_id = 'menu-item-'.$mid;

    It will give you an css id (or class) like id="menu-item-82" for all languages. It's not as nice looking av accessible as the original solution but it seems to be the only way when dealing with multilingual content.

    Nice! But how about localization?

    This method looks like it's will work just fine for most people. However, if one has a numerous amount of languages this method will cause problems. $css_id = str_replace(' ', '_', strip_tags($link)); will return a separate id for each language. This can come in handy offcourse, but most of the time it wil cause a problem. Is there a better way of doing this for multilingual menus?

    The drupal articles you write are great by the way! :)

    Very helpful tutorial

    I was looking for a way to manipulate menu items based on node types. Not exactly what is described here, but still your tutorial helped me a lot. Looks like it’s worth to visit your page regularly, thanks!

    The link to download the file still isn't working

    Great site! I love your design.

    Download not working

    Hey Nick, The download is (still) not working. Thanks for all the useful info! Marco

    Link to downloadable example theme

    It just sends me back to the homepage. Can you fix this???

    more than one menu

    What if you have more than one menu? How can you make the function single out, for instance, the Primary Links menu only? thanks!

    handling special chars

    I had a menu item with an '&' in it... so I borrowed a little bit of code from pathauto for use in the menu_item.tpl.php file: <?php $link = menu_item_link($mid); // Preserve alphanumerics, everything else becomes a separator $css_id = strtolower(strip_tags(html_entity_decode($link) )); $pattern = '/[^a-zA-Z0-9]+/ '; $separator = '_'; $css_id = preg_replace($pattern, $separator, $css_id); // render the menu link with unique CSS id. $output = '\n"; print $output; ?>

    ID vs CLASS

    Hi Nick, Nice ideas here. It probably shouldn't be setting IDs on elements based on a link's text though -- the possibility of duplicate IDs and/or IDs that are already used elsewhere for the design is just too great. I think CLASS would work just as well? Jeff

    Actually this happened to me

    Actually this happened to me and to correct it I changed the class to read class="link_'.$css_id.'" By adding the link_ to the class identifier the chances of duplication are slim.

    Problems with Friends Electric

    $css_id = str_replace(' ', '_', strip_tags($link)); This line causes problems with "Content" menu in the Friends Electric theme, but I can't figure out why...

    Don’t know… this

    Don't know... this technique, I've decided is REALLY primitive and needs some refinement. I'll post whatever improvements I can come up with.

    I’m looking for a way to

    I'm looking for a way to assign icons to vocab/terminology, so each post has an icon displayed with the title. Would this method be a good direction to examine, or am I way off course?

    No this method is right on

    No this method is right on -- but see this tutorial for a clue: http://www.nicklewis.org/node/825

    Any idea how to implement

    Any idea how to implement this in conjunction with nice_menus.module?

    link to downloadable example theme (still) not working

    It said file not found. :)

    $(**$&#&! Well, you can

    $(**$&#&! Well, you can always use that ugly file list link at the top of the page (I need to fix that, and 1000 other things on this blog... Oh! Why do I always have to have 1000 other htings that I need to do?). It works.

    Same thing on book menu ?

    Neat trick ! However I noticed it is not applied to menus created by a "book" hierarchy. Do you know if there is a way to achieve this ?

    I actually don’t think it

    I actually don't think it is possible... if I recall correctly, the book hierarchy is built with theme_book_navigation(). In that function, $outline is created with book_outline() which rudely hoardes the options that would make this possible with a book outline. Retheming the book module is actually on my for-work to-do list, so I'll be sure to report back if I find anything.

    I had a look at book.module,

    I had a look at book.module, and found book_tree and book_tree_recurse functions. I'm a bit new to Drupal, but what I understand is they are not themable (they don't begin with theme_). So it seems I could add a CSS ID like you do, but I would have to edit a core file (book.module), which is not a good idea. Or save it as mybook.module ?

    There seems to be a line break missing

    In menu_item.tpl.php, should not $output... be on a new line? As is, it's lost in the comment.

    remind me not write

    remind me not write tutorials while on deadline

    link to downloadable example theme not working

    It looks very good, but the link to the downloadable example theme is not working

    Sorry bout that:fixed

    Sorry bout that:fixed

    Download link not working

    I'd like to tinker around with this - although I'm pretty terrible at coding and stuff...(!)
    Please, please, please can you make the link active again? or maybe you could email me the file?

    Thanks

    dj

    Ditto

    Hi Nick,
    Would you be able to forward on the attached .zip file. I'd be very grateful. Many thanks in advance.
    ubahnclothing@yahoo.co.uk

    Post new comment

    The content of this field is kept private and will not be shown publicly.
    • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd><p><h1><h2><h3><h4><h5><h6><code><cite><blockquote><img>
    • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
    • Lines and paragraphs break automatically.

    More information about formatting options