Last updated October 18, 2011. Created by bradlis7 on May 6, 2006.
Edited by MGParisi, lisarex, sepeck. Log in to edit this page.
On my site, I wanted to use images instead of text for the primary tabs, so I came up with a method to do so. You'll want to look for where the primary links are generated in page.tpl.php. The default is this:
<?php if (is_array($primary_links)) : ?>
<ul id="primary">
<?php foreach ($primary_links as $link): ?>
<li><?php print $link?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>And you'll want to replace it with this snippet:
<?php if(is_array($primary_links)) : ?>
<ul id="primary">
<?php
$l2i['pattern'] = '$(<a.*>)(.*)(</a>)$ie';
$l2i['themepath'] = url($directory);
$l2i['replacement'] = "\"\\1\".'<img src=\"$l2i[themepath]/icon_'.str_replace(' ','_',strtolower('\\2')).'.png\" alt=\"\\2\" />\\3'";
foreach ($primary_links as $link) {
print "<li>".preg_replace($l2i['pattern'],$l2i['replacement'],$link)."</li>\n";
}
unset($l2i);
?>
</ul>
<?php endif; ?>The images should be stored in your themes directory. You should make your icon names be in the format of "icon_menu_item.png", where "Menu Item" is the title of the Link. Here's some more examples:
Pictures - "icon_pictures.png"
Graphic Design - "icon_graphic_design.png"
Basically, you'll want to make the title lowercase, change the spaces to underscores, and wrap it with "icon_" and ".png".
Comments
images in the menu
I came up with another solution.
Its almost doing the same thing but im also checking to se if the menu elm is active, and i put it inside my template.php file
The images is placed in: THEME_NAME/images/menu/
normale menu files: menu_1.gif, menu_2.gif ... etc
active menu files:menu_1_active.gif, menu_2_active.gif ... etc
template.php:
function phptemplate_menu_links($links) {
if (!count($links)) {
return '';
}
$i="1";
foreach ($links as $index => $link) {
//image
if (stristr($index, "active")) {
$img = '<a href="$1" title="$2"><img src="'.base_path() . path_to_theme().'/images/menu/menu_'. $i .'_active.gif" alt="$3"></a>';
}else{
$img = '<a href="$1" title="$2"><img src="'.base_path() . path_to_theme().'/images/menu/menu_'. $i .'.gif" alt="$3"></a>';
}
$output .= preg_replace('/<a href="(.*?)" title="(.*?)">(.*?)<\\/a>/i', $img, $link);
$output .= "\n";
$i++;
}
return $output;
}
call the menu inside page.php
if (isset($primary_links)) {print phptemplate_menu_links($primary_links);
}
enjoy :)
/morten.dk *king of Denmark*
/morten.dk
http://geekroyale.com | http://morten.dk
Not working
Hi mortendk , it is not working . it returns as "array". image is not displayed. i am using drupal6.10
------------------------
Sai prasad
Another solution
I modified the approach in http://drupal.org/node/110199 so that I can replace a menu name with an arbitrary image as follows:
In template.php, instead of rewriting theme_menu_item_link(),
rewrite theme_menu_links() as follows:
<?php
function phptemplate_menu_links($links) {
if (!count($links)) {
return '';
}
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
foreach ($links as $index => $link) {
$output .= '<li';
if (stristr($index, 'active')) {
$output .= ' class="active"';
}
if (strpos($link['title'], '<img') === 0) {
$output .= ">". l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment'], FALSE, TRUE) ."</li>\n";
}
else {
$output .= ">". l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']) ."</li>\n";
}
}
$output .= '</ul>';
return $output;
}
?>
Icons in Primary Links
This is another solution that allows to add images to the primary links. This is a combined solution from a few posts and themes. Also, I tested it on Drupal 5.7 - works OK.
1. FIRST SOLUTION: add images as a background
1a. Add the below code to template.php (template.php is located inside the themes/theme_you_are_using/):
<?php// allows to display icons with the primary links
function primary_links_add_icons() {
$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
if ($links) {
foreach ($links as $link) {
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$cssid = str_replace(' ', '_', strip_tags($link));
$output .= '<li id="'.$cssid.'">' . $link . '</li>';
};
$output .= '</ul>';
}
return $output;
}
?>
1b. Change primary links code in the page.tpl.php (page.tpl.php is located inside the themes/theme_you_are_using/)
Original code in Zen themes (code may vary from theme to theme but basically we are looking for $primary_links var)
<?php if ($primary_links): ?><div id="primary">
<?php print theme('links', $primary_links); ?>
</div> <!-- /#primary -->
<?php endif; ?>
Change to
<?php<!-- changed to display primary links with icons-->
<?php if ($primary_links): ?>
<div id="primary">
<?php print primary_links_add_icons(); ?> //name of the function must match the name used above in template.php
</div> <!-- /#primary -->
<?php endif; ?>
?>
1c. Add to the styles.css (style.css is located inside the themes/theme_you_are_using/)
li#Articles_and_Stories a{display: block;
background: url(../images/icons/articles_and_stories.gif) no-repeat top center;
}
li#Assess_Skills a{
display: block;
background: url(../images/icons/assess_skills.gif) no-repeat top center;
}
li#Do_Activities a{
display: block;
background: url(../images/icons/do_activities.gif) no-repeat top center;
}
Where "Articles_and_Stories", "Assess_Skills", "Do_Activities" are the primary links menu items with titles like "Articles and Stories", "Assess Skills", "Do Activities". Remember to add _ between the words used in the menu title to create a proper css code.
2. SECOND SOLUTION: add images using img src tag (which gives more options to manipulate the layout)
2a. Add the below code to template.php (template.php is located inside the themes/theme_you_are_using/):
function primary_links_add_icons() {$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
if ($links) {
foreach ($links as $link) {
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$cssid = str_replace(' ', '_', strip_tags($link));
$output .= '<li id="'.$cssid.'"><img src="'. path_to_theme() .'/images/icons/'. $cssid.'.gif">' . $link . '</li>';
};
$output .= '</ul>';
}
return $output;
}
In my case, icons are store in the current themes directory, in images/icons/ folder and have extension .gif but that can be changed by changing the line
$output .= '<li id="'.$cssid.'"><img src="'. path_to_theme() .'/images/icons/'. $cssid.'.gif"><br />' . $link . '</li>';2b. Change primary links code in the page.tpl.php (page.tpl.php is located inside the themes/theme_you_are_using/) - use the same code as listed above under 1b.
3. THIRD SOLUTION: very much like the 2nd, but allows the image to be clickable
I used the original code posted at the top of the page and modified it to include both link title and image.
3a. Add the below code to template.php (template.php is located inside the themes/theme_you_are_using/):
function primary_links_add_icons() {$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
$l2i['pattern'] = '$(<a.*>)(.*)(</a>)$ie';
$l2i['replacement'] = "\"\\1\".'<img src=\"'. path_to_theme() .'/images/icons/'.str_replace(' ','_',strtolower('\\2')).'.gif\" alt=\"\\2\" />\\2\\3'";
if ($links) {
foreach ($links as $link) {
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$output .= '<li>'. preg_replace($l2i['pattern'],$l2i['replacement'],$link) .'</li>';
};
$output .= '</ul>';
}
return $output;
}
In my case, icons are store in the current themes directory, in images/icons/ folder and have extension .gif but that can be changed by changing the line
$l2i['replacement'] = "\"\\1\".'<img src=\"'. path_to_theme() .'/images/icons/'.str_replace(' ','_',strtolower('\\2')).'.gif\" alt=\"\\2\" />\\2\\3'";3b. Change primary links code in the page.tpl.php (page.tpl.php is located inside the themes/theme_you_are_using/) - use the same code as listed above under 1b.
4. FOURTH SOLUTION: display icons (images) but no text
4a. Add the below code to template.php (template.php is located inside the themes/theme_you_are_using/):
function primary_links_icons_only() {$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
$l2i['pattern'] = '$(<a.*>)(.*)(</a>)$ie';
$l2i['replacement'] = "\"\\1\".'<img src=\"'. path_to_theme() .'/images/icons/'.str_replace(' ','_',strtolower('\\2')).'.gif\" alt=\"\\2\" />\\3'";
if ($links) {
foreach ($links as $link) {
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$output .= '<li>'. preg_replace($l2i['pattern'],$l2i['replacement'],$link) .'</li>';
};
$output .= '</ul>';
}
return $output;
}
4b. Add code to the page.tpl.php or, if you are using CCK module and want to display those links only on certain type of pages (for example, only on title pages and you created Title Pages template, add this code in node-title_pages.tpl.php, located inside the themes/theme_you_are_using/)
<?php<!-- changed to display primary links with icons but no text-->
<?php if ($primary_links): ?>
<div id="primary">
<?php print primary_links_icons_only(); ?> //name of the function must match the name used above in template.php
</div> <!-- /#primary -->
<?php endif; ?>
?>
Kasia Wakarecy
http://www.freeformsolutions.ca
IT support for NFPs
Instead of doing the
Instead of doing the preg_replace for option 4, can't you just use option 1 and wrap the link in a span tag. Then, in your CSS set the span tag so that it doesn't display. This is what they do on the csszengarden website to replace words with images using straight CSS. So, for your function, it'd be something like:
<?php// allows to display icons with the primary links
function primary_links_add_icons() {
$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
if ($links) {
foreach ($links as $link) {
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$cssid = str_replace(' ', '_', strip_tags($link));
$output .= '<li id="'.$cssid.'"><span class="menu-hidden-text">' . $link . '</span></li>';
};
$output .= '</ul>';
}
return $output;
}
?>
And then for the CSS it would be:
.menu-hidden-text {display: hidden; }Thanks,
Shane
The images aren't completely clickable.
Shane, while your code seems more streamlined and was the first code I tried, I had difficulty clicking icons (the active link did not span/cover the entire icon) so I ended up using kasiawaka's 4th option.
Making full image clickable
To make the full image clickable, you really need the span tag inside of the tag. Then, you set the span to that it has a display:none property and the has a display:block property. This will make the tag display across the entire li area. If you wanted to do that, you'd have to replace the text in the $link variable with the span variable. So, it'd be more something like this:
<?php// allows to display icons with the primary links
function primary_links_add_icons() {
$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
if ($links) {
foreach ($links as $link) {
$link = l('<span class="menu-hidden-text">'.$link['title'].'</span>', $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$cssid = str_replace(' ', '_', strip_tags($link));
$output .= '<li id="'.$cssid.'">' . $link . '</li>';
};
$output .= '</ul>';
}
return $output;
}
?>
Then, set a css property for the for that UL A to be display: block;
Thanks,
Shane
You don't need the span tag
Hi,
Acording to CSSzengarden they are just using the < a > tags to get the image replacement without the need of span.
style.css:
ul.primary-links li a { /*FOR ALL MENU ITEMS*/
text-indent: -10001px;
display: block;
width: 160px;
height: 19px;
}
li#Articles_and_Stories a{ /*MENU ITEM*/
background: url(images/icons/articles_and_stories.gif) no-repeat top left;
}
li#Articles_and_Stories a.active{ /*Set image for at Articles and stories page*/
background: url(images/icons/articles_and_stories2.gif) no-repeat top left;
}
li#Contact a{ /*MENU ITEM*/
background: url(images/icons/contact.gif) no-repeat top left;
}
li#Contact a.active{ /*Set image of this menu item at the contact page*/
background: url(images/icons/contact2.gif) no-repeat top left;
}
...
page.tpl.php
<?php if ($primary_links): ?><?php print primary_links_add_icons(); ?> //name of the function must match the name used above in template.php
<?php endif; ?>
template.php
// allows to display icons with the primary linksfunction primary_links_add_icons() {
$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"primary-links\">\n";
if ($links) {
foreach ($links as $link) {
$cssid = str_replace(' ', '_', strip_tags($link['title'])); //this first
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$output .= '<li id="'.$cssid.'">' . $link. '</li>'; //no need of span
};
$output .= '</ul>';
}
return $output;
}
And then, you'll need the gifs inside images/icons folder:
images/icons/articles_and_stories.gif
images/icons/articles_and_stories2.gif
images/icons/contact.gif
images/icons/contact2.gif
...
This way it works for Firefox3 and IE7.
Works great but Bullet shows
It works really well but I happen to have images with transparency and the bullet from the list is appearing through, both in IE and Firefox. Setting "list-style-type: none" does not work. Turns out, at least with garland, there is ul setting to change the background to an image of a bullet
I had to add the following to my css
ul.primary-links li {background-image: none;
}
re
So you simply replace (delete the old syntax line) print for primary links in page.tpl with the new primary_links_add_icons right?
p.s
trying to get rid of the silly bullets now, saw a solution just a post below good stuff :)
seabass kick his...
p.p.s
btw - This works in drupal 6 too
the other method mentioned in this thread did not work for me (see my post below)
my only concern is it causes some hidden bug.
If there's a more neat way to achieve this in drupal 6 I'll be happy to know about, Cheers.
seabass kick his...
for drupal 6
This is working great for me, but for reasons described here: http://justinhileman.info/articles/unsupported-operand-types-in-drupal-6x
I needed this to get it working in drupal 6:
$options = array('fragment' => $link['fragment'],
'query' => $link['query']);
$link = l($link['title'], $link['href'], $options);
Number 4 worked for me but...
I used a modified version of your number 4. and got it working. The only issue i have is with this bit ...
Do you know of a way to get this to stay throughout? if i navigate to a view of for example the shopping cart of my site, the primary links return to text, yet i cannot find and more page.tpl's to add the code to. Unless i am to make note of every type of page in the site and make overides for each.
Thanks for the code by the way.
It should reference the
It should reference the page.tpl.php if there is not one for that specific type of page. The default would always be page.tpl.php and then you can override it by adding other ones based on the type.
- Shane
For Drupal 6?
This seems to be exactly what I've tried to do for the last couple of hours (plenty of hours that is) in Drupal 6. But, my Google skills doesn't serve me right. Can anyone point me to how this is done in Drupal 6?
Regards
Mikael
I just spent hours looking
I just spent hours looking through threads and Google searches, but finally found the method to do this
This is the page I found: http://www.kryogenix.org/code/browser/lir/
Example: The code I used to replace the Primary Links title with an the image /themes/garland/images/primary_silver.png:
#block-menu-primary-links H2{padding: 40px 0 0 0;
overflow: hidden;
background-image: url(images/primary_silver.png);
background-repeat: no-repeat;
height: 0px !important;
height /**/:40px;
}
regarding the http://www.kryogenix.org/code/browser/lir/ method
Hi
I have the same problem and I'm also looking for a smooth non-hack css solution. I've read the linked article and tried the method myself and all it does for me is to push the actual link so it's seated just under the image and out of the screen. The problem is that the replacing image doesn't actually work as a link so you can't click on it.
I've tried this with a block header as well (thinking that maybe the method only works with non-interactive elements) so I've replaced the left side bar tittle with an image. This time the actual header just seat there visible under the new "replacing" image. maybe it's to do with my css setup and there's more padding than there should be - that's the only thing which will pops into my head right now that can cause this problem, because the height is set to 0.
Anyway regarding the first problem I've mentioned (items aren't interactive) I'm clueless. Any insightsm what am I doing wrong here???
p.s
maybe I should also mention that I'm using D6
seabass kick his...
CSS Hack
I have also tried the css, but I get the same result. I'm using drupal 6.
A list item in a drupal menu is like this.
And then go into the menu text and remove text with.
.menutext {
display:none;
}
For D6
Hi, I just did some 'plumbing' for D6. I am actually not familiar with PHP, but I got it to work using the error messages:
Changed this:
$l2i['replacement'] = "\"\\1\".'<img src=\"'. path_to_theme() .'/images/titles/'.str_replace(' ','_',strtolower('\\2')).'.png\" alt=\"\\2\" />\\2\\3'";to this: (find the /)
$l2i['replacement'] = "\"\\1\".'<img src=\"/'. path_to_theme() .'/images/titles/'.str_replace(' ','_',strtolower('\\2')).'.png\" alt=\"\\2\" />\\2\\3'";and modified:
foreach ($links as $link) {$options = array(
'fragment' => $link['fragment'],
'query' => $link['query']);
$link = l($link['title'], $link['href'], $options);
$output .= '<li>'. preg_replace($l2i['pattern'],$l2i['replacement'],$link) .'</li>';
};
Don't know if this is proper code, but it works anyway,
regards/
Solution 4 works best (IMHO!)
After searching and testing different options for a couple of days, Solution 4 worked best on a site that I'm working on (currently in dev; will post live link when it's finished). Thank you, Kasia!
I had to make one modification. In order to form the proper path for the img, an extra / is needed in before
'. path_to_theme() .'I'm also using png's instead of gif's, so this is the code that works on my D5.14 site:// Use icons for primary menufunction primary_links_icons_only() {
$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
$l2i['pattern'] = '$(<a.*>)(.*)(</a>)$ie';
$l2i['replacement'] = "\"\\1\".'<img src=\"/'. path_to_theme() .'/images/icons/'.str_replace(' ','_',strtolower('\\2')).'.png\" alt=\"\\2\" />\\3'";
if ($links) {
foreach ($links as $link) {
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$output .= '<li>'. preg_replace($l2i['pattern'],$l2i['replacement'],$link) .'</li>';
};
$output .= '</ul>';
}
return $output;
}
Thanks again!
Anne
Successfully ported to D6 too.
An update: I ported my site to D6.10 and this code worked there too. See it here: http://mouse-map.com/
Happy day,
Anne
how to make images change on click?
I used a modified version of number 4 as well. One modification was to get rid of those bullets, as the above methods didn't work for me.
I used this in the .ccs to get rid of those bullets:
#navbar ul {list-style: none;
}
Second was the use of a second image to make the buttons clickable:
li#Home a.active{ /*MENU ITEM*/
background: url(images/icons/button_home_clicked.gif) no-repeat top right;
}
li#Home a{ /*MENU ITEM*/
background: url(images/icons/button_home.gif) no-repeat top right;
}
The problem with this was that the buttons don't really "click". The image changes once the link is active, but not on the mouse click event. Using a.hover didn't seem to work.
Can anyone suggest a way of changing the image on the mouse click event?
Instead of using a.hover use
Instead of using a.hover use a:hover
In using the above function
In using the above function you must enter the base_path() function as presented in the original post at the head of this thread. If you have your Drupal installation in a subdirectory of your site the code as posted will not work on expanded admin menus. You must have the base_path() in order to find the image on the sub menu item. For example: Administer will show the menu images, but Administer > Content Management will only show the ALT name.
Change the
$l2i['replacement'] = "\"\\1\".'<img src=\"'. path_to_theme() .'/images/icons/'.str_replace(' ','_',strtolower('\\2')).'.gif\" alt=\"\\2\" />\\3'";to
$l2i['replacement'] = "\"\\1\".'<img src=\"'. base_path() . path_to_theme() .'/images/icons/'.str_replace(' ','_',strtolower('\\2')).'.gif\" alt=\"\\2\" />\\3'";will solve the issue. Of course I think this is what the original poster is attemtping to do with his If.. Then.. Else.. statement, but be aware of this in the Method 4 code above.
If you are attempting, as I am, to use the Zen Starter Theme. This will not seem to work if you attempt to show the Primary Links in the Navigation Block in the theme. You get both a Image menu and a Text Link menu one under the other. I'm not quite sure why this is doing this since I have copied the page.tpl.php into the theme directory and made the code modifications to it. I suspect that the function is building the wrong id now. I will add a post here when I have figured this out.
Thanks,
Steve
changing primary links DRUPAL 6x
I've got question. How can I change primary links to something like that :
<li><a href="#">
<img src="####.gif" alt="" />
<span>TEXT TEXT</span>
</a></li>
My Drupal sites
www.audytorzy-energetyczni.info
www.spisturystyczny.pl
www.plastikowepaznokcie.pl
Removing apostrophes from the menu links
Hiya,
This took me several hours to figure out cos it was such a pain in the ass! Read the full details here:
http://stackoverflow.com/questions/1404723/pregreplace-strreplace-apostr...
Suffice to say, if you want images linked in your menu, with text on top, this is the code I've been using. There is a commented preg_replace expression which removes the text too if you like.
<?phpfunction primary_links_add_icons() {
$links = menu_primary_links();
$level_tmp = explode('-', key($links));
$level = $level_tmp[0];
$output = "<ul class=\"links-$level\">\n";
if ($links) {
foreach ($links as $link) {
$link['title'] = str_replace('\'', '', $link['title']);
$link = l($link['title'], $link['href'], $link['attributes'], $link['query'], $link['fragment']);
$cssid = str_replace(' ', '_', strip_tags($link));
/*put the preg_replace here*/
$output .= '<li id="'.$cssid.'">' . $link .'</li>';
};
$output .= '</ul>';
}
return $output;
}
?>
This is the preg_replace code - it appears to break the php output above:
/*$link = preg_replace('#().*?()#', '$1$2', $link);*/
Nice Menus, Image Backgrounds, Sprites and Text Indent
To do image replacement on Primary Links Menu, first thing needed is unique id for each menu option, easiest way to add them automatically is to use Nice Menu module, pointing to Primary Links Menu
With #id on each li tag on menu, replace text on link with images using CSS:
#menu-708 a{background:url("images/menu-708.gif") no-repeat;text-indent:-999px;line-height:30px;width:100px;display:block;}
Hover effect using image sprite:
#menu-708 a:hover{background:url("images/menu-708.gif") no-repeat left -30px;}
Text indent hides text and is SEO friendly, using image sprites reduces load times and gives smooth image replace effects
Diseño Web
Thnak you
Brilliant - text-indent:-999px; worked perfectly. Jim