Can I modify theme_menu_link for a specific menu? - drupal

I would like to add pipes ("|") between menu items for one of the menus on my Drupal 7 site (theme name is "thompson"). I figured the best way to do this is to create a function in my template.php file called thompson_menu_link. I did that and it is successfully modifying the menus, but it's changing all the menus. Is there a way I can do this for just one menu on my site?
Currently, I used the admin pages to add my footer menu (url path: menu-footer-menu) to the Footer block. Should I call it a different way?

Apparently Drupal core provides the ability to theme menu links by menu name. For the Main menu the following theme function should work
THEMENAME_menu_link__main_menu()
Alternatively you could use the Menu Block module to create menu blocks. Among other things the module creates additional theme suggestions. From the module's README:
Menu block uses Drupal core's menu theme functions. However, it also
provides theme hook suggestions that can be used to override any of
the theme functions called by it. ...
theme_menu_link() can be overridden by creating one of:
[theme]_menu_link__[menu name]()
[theme]_menu_link__menu_block()
[theme]_menu_link__menu_block__[menu name]()
[theme]_menu_link__menu_block__[block id number]()

I've messed with the thompson_menu_link() function a bit. I don't like how I did it, but it got the job done. Basically, it reads in the menu name, and uses a conditional to return the <li> element with a pipe afterward. Here's the whole block:
function thompson_menu_link(array $variables) {
$element = $variables['element'];
$menuName = $variables['element']["#original_link"]["menu_name"];
$sub_menu = '';
if ($element['#below']) {
$sub_menu = drupal_render($element['#below']);
}
$output = l($element['#title'], $element['#href'], $element['#localized_options']);
if ($menuName == "menu-footer-menu" && !in_array("last",$element['#attributes']['class']) {
$finalString = '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>|\n";
}
else {
$finalString = '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}
return $finalString;
}

the best way you can make it is installing the following module:
http://drupal.org/project/menu_attributes
This module lets you add special classes to some menu entries, so you just have to add a class rightpipe and define that class like:
.rightpipe { border-right: 1px solid black }
or
.rightpipe { background: url(1pixel_line_separator.png) no-repeat center right }

Related

Wordpress Menu + Bootstrap + Glyphicon Instead Text

So I'm working on a Wordpress site with Bootstrap.
I'm using Bootstrap's navbar for the menu integrated with WP.
I have my homepage as a link in the navbar as "home".
Instead of "Home" as a text I want a glyphicon to appear and not text.
I think I could use CSS for that... something like this:
#menu-item-55 {
/* something that removes text and adds the icon */
}
But in bootstrap I have to use the icons like this
<span class="glyphicon glyphicon-search"></span>
Anyone?
Thanks
I figured that I can do it by adding a custom link and putting the inside the navigation label.
I still would like another way to do it. :D
Cheers
If you are using the wordpress 3+ wp_nav_menu with your theme adding this snippet to the functions.php will add a glyphicon-home link of bootstrap to your navigation.
function addHomeMenuLink($menuItems, $args)
{
if('header_menu' == $args->theme_location) // make sure to give the right theme location for the menu
{
if ( is_front_page() )
$class = 'class="current-menu-item active"';
else
$class = '';
$homeMenuItem = '<li ' . $class . '>' .
$args->before .
'<a class="glyphicon glyphicon-home" href="' . home_url( '/' ) . '" title="Home">' .
$args->link_before .
/* 'HOME' . //add home text if you want. */
$args->link_after .
'</a>' .
$args->after .
'</li>';
$menuItems = $homeMenuItem . $menuItems;
}
return $menuItems;
}
add_filter( 'wp_nav_menu_items', 'addHomeMenuLink', 10, 2 );
source
Navigate to Appearance > Menus
Find the menu item that you want to add an icon to
Expand the menu item
Inside the Navigation Item you will want to add your icon code either before or after or in place of your existing menu item label. For this example I’m going to use the home icon. Here’s what you would type:
< i class='icon-home icon-white'>< /i> Home
Note: Make sure to use single quotes!
5.Important: This is something you want to make sure to do, it could negatively impact your SEO if you ignore this step. You will want to make sure to put the plain text in the Title Attribute field.
6.Save the menu. (Also make sure you have selected one of the menus from the Theme Locations drop downs) That’s it!
http://jasonbradley.me/icons-in-the-wordpress-menu/

Drupal - Add custom html in li to menu ul?

Is there any way to write some html (as you might in a block), and have that html appear as a menu item?
My situation is that I want some text that is not a link to say 'Follow us on:', and then I want 2 images which are both links to twitter and facebook.
Menu html cant do this as it requires any html you write to be part of a link, and to be the same link for that menu entry.
http://drupal.org/project/menu_html
I really want the html I add to be within the menu list.
Thanks
UPDATE
Code doesn't work well in the comments so im adding it here. This link seemed to be the closest to what you were suggesting:
http://api.drupal.org/api/drupal/includes--menu.inc/function/theme_menu_item/6
So I added this to my template.php:
function localhost_petitpim_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 myactive';
}
return '<li class="' . $class . '">' . $link . $menu . "</li>\n";
}
All ive done is add a class of 'myactive' so I can see if its working. My theme name is 'localhost_petitpim'. Ive refreshed the cache. My theme is set to 'Rebuild theme registry on every page.' I cant see the new class being applied. Have I done something wrong?
Thanks
You can simply hard-code text and linked images in your tpl.php file(s).
Just put html block with desired code in tpl.php after menu. Make new wraper around menu & block if current html structure of your theme is not supporting this solution. Block should be floated right or displayed inline depending on HTML+CSS of your theme.
Hope this helps.
Not a nice solution, but it works.
Add two dummy menu entrys to your menu.
Override the theme_menu_link method by implementing phptemplate_menu_link in your template.php file.
Inside the phptemplate_menu_link filter for your dummy entry and replace them with what ever html code you like.

Is it possible to *optionally* override a theme in Drupal 6?

I want to override the theming of only one (custom) menu. I can do this with phptemplate_menu_tree() but - of course - it overrides the rendering of all menus.
I've tried returning FALSE (an obvious technique IMO) if the menu is not the specific one I want to override - but this doesn't cause the overridden theme function to be called.
My only alternative (when the menu is anything other than the specific one) is to call the overridden function from within phptemplate_menu_tree() - but this seems to defeat the whole point of the override system, since the default rendering function will be hard-coded therein.
I hope the explanation is clear, and any help is greatly appreciated - tks.
UPDATE
For the sake of future reference, I'll explain how I solved this.
First off, the menu rendering starts with this function in menu.module:
function menu_block($op = 'list', $delta = 0) {
$menus = menu_get_menus();
// The Navigation menu is handled by the user module.
unset($menus['navigation']);
if ($op == 'list') {
$blocks = array();
foreach ($menus as $name => $title) {
// Default "Navigation" block is handled by user.module.
$blocks[$name]['info'] = check_plain($title);
// Menu blocks can't be cached because each menu item can have
// a custom access callback. menu.inc manages its own caching.
$blocks[$name]['cache'] = BLOCK_NO_CACHE;
}
return $blocks;
}
else if ($op == 'view') {
$data['subject'] = check_plain($menus[$delta]);
$data['content'] = menu_tree($delta);
return $data;
}
}
If you only want to override how individual item (links) are rendered then you can use the theme system (there are loads of references on how do this) - but if you want complete control on how the entire menu tree is rendered (for example, wrapping the output in nested DIVs so it can be centred on the page) then there is no way to override menu_block().
Therefore, I removed the menu I wanted to render differently from the administer blocks page (site building->blocks) and rendered the menu directly in my page.tpl.php using code something like this: (angle brackets removed)
$m = menu_tree_page_data('my-menu-id');
$o = "DIV";
foreach($m as $k => $v){
$o .= "SPAN {$v['link']['title']} /SPAN";
}
$o .= "/DIV";
echo $o;
I hope this helps.
I've had mixed success doing template.php menu overrides to force CSS classes and ids or HTML into the output.
You could make use of Block Theme when enabling the menu as a block, but I've never tried it.
http://drupal.org/project/blocktheme
If you want to tackle the template way, here are the zen menu override funcitons...
function zen_menu_item_link($link) {
if (empty($link['localized_options'])) {
$link['localized_options'] = array();
}
// If an item is a LOCAL TASK, render it as a tab
if ($link['type'] & MENU_IS_LOCAL_TASK) {
$link['title'] = '<span class="tab">' . check_plain($link['title']) . '</span>';
$link['localized_options']['html'] = TRUE;
}
return l($link['title'], $link['href'], $link['localized_options']);
}
function zen_menu_local_tasks() {
$output = '';
if ($primary = menu_primary_local_tasks()) {
$output .= '<ul class="tabs primary clear-block">' . $primary . '</ul>';
}
if ($secondary = menu_secondary_local_tasks()) {
$output .= '<ul class="tabs secondary clear-block">' . $secondary . '</ul>';
}
return $output;
}
You could use sections module, or look at how it switches theme for certain menu-items.
what I did was register a new theme function in my template.php called primary_links (because I wanted to only customize this menu in certain way) created the function mytheme_primary_links() in my template.php refreshed the cache so Drupal would add my theme function to the system then changed theme function on primary_links from links to my custom theme function primary_links - this allows me to customize only this 1 menu - could you do this and hook into where ever to change the theme function being called for your links?
Chris

Drupal theme preprocess function - primary links

I recently wrote a theme function to add a class to my primary links that works great. I then wrote some css classes to style these links with custom background images. Worked out great. Now comes the problem, the link text for the primary links still is displayed. Normally this isn't a problem as I would just wrap the in a with a custom "hide" class. For example:
<span class="hide">Link Text</span>
So my question is how can I loop through the primary links and wrap the text w/ a <span> like my example? Here's my theme function that I used to add my classes.
function zkc_preprocess_page(&$vars, $hook) {
// Make a shortcut for the primary links variables
$primary_links = $vars['primary_links'];
// Loop thru the menu, adding a new class for CSS selectors
$i = 1;
foreach ($primary_links as $link => $attributes){
// Append the new class to existing classes for each menu item
$class = $attributes['attributes']['class'] . " item-$i";
// Add revised classes back to the primary links temp variable
$primary_links[$link]['$attributes']['class'] = $class;
$i++;
} // end the foreach loop
// reset the variable to contain the new markup
$vars['primary_links'] = $primary_links;
}
Is jQuery an option?
Try something like this:
$(document).ready(function(){
$('#primary li a')
.wrapInner('<span class="hide">' + '</span>');
});
EDIT:
Or if you want to go Drupal, put this guy in your foreach loop:
$link['title'] = '<span class="hide">' . check_plain($link['title']) . '</span>';
If all you want is to hide the link text, why don't you just use something like text-indent: -9999px;?
The correct methods for altering the output of the menu links can be done at the theming layer. You were on the right path with the preprocessing hook use, but there is a little more to it.
Refer to this for more information:
http://drupal.org/node/352924#comment-1189890
http://api.drupal.org/api/function/theme_links/6
Typo?
$primary_links[$link]['$attributes']['class'] = $class;
Should read;
$primary_links[$link]['attributes']['class'] = $class;

How to alter a MENU_LOCAL_TASK tab menu in Drupal

I have built a tabbed menu in my custom Drupal 6 module. I want to position an html dropdown list to the right of the tabbed menu at the top of my module page. The list will fire some ajax events on change e.g. changing the LIMIT clause on SQL query by specifying 10,20,50,100 results. How can I achieve this in Drupal without hacking templates?
Thanks,
You could do this by overriding theme_menu_local_tasks() within your theme:
function yourTheme_menu_local_tasks() {
// Prepare empty dropdown to allow for unconditional addition to output below
$dropdown = '';
// Check if the dropdown should be added to this menu
$inject_dropdown = TRUE; // TODO: Add checking logic according to your needs, e.g. by inspecting the path via arg()
// Injection wanted?
if ($inject_dropdown) {
// Yes, build the dropdown using Forms API
$select = array(
'#type' => 'select',
'#title' => t('Number of results:'),
'#options' => array('10', '20', '50', '100'),
);
// Wrap rendered select in <li> tag to fit within the rest of the tabs list
$dropdown = '<li>' . drupal_render($select) . '</li>';
}
// NOTE: The following is just a copy of the default theme_menu_local_tasks(),
// with the addition of the (possibly empty) $dropdown variable output
$output = '';
if ($primary = menu_primary_local_tasks()) {
$output .= "<ul class=\"tabs primary\">\n". $primary . $dropdown . "</ul>\n";
}
if ($secondary = menu_secondary_local_tasks()) {
$output .= "<ul class=\"tabs secondary\">\n". $secondary ."</ul>\n";
}
return $output;
}
(NOTE: Untested code - potential typos)
As you are referring to code to put in a module, then the module should implement hook_theme_registry_alter(), which would allow the module to override the function theme_menu_local_tasks(). The module should store the value of the previous callback, so that it could still call it in the case the page it not one that it should change.
Implementing a hook in the module allows you to have the normal menu tabs, once the module has been disabled; altering the current theme would require you to change it back when you want the functionality anymore, and if you are using a theme made from another person you should change the theme all time you download a new version. If you are using more than one theme, then you should make the change to each used theme.
In general, a modification to a theme that is required from a module should be done inside a module.

Resources