Add a span wrapper inside primary and secondary menu links in Drupal 6
Key words and phrases
span wrapper for primary links make tab-style links for main navigation menuTags
Description
This document takes us through the steps of figuring out how some output is produced (without an Integrated Development Environment with debugger) so that we can modify it. Skip straight to Agaric's answer in the resolution at the bottom if that's all you want!
theme_menu_item_link() has no effect on primary / secondary navigation links (at least when printed through the theme, and not as blocks). Which was unexpected.
However, in a Zen subtheme (called examplezen here) the following code produced all kinds of interesting output for node menus and
<?php
/**
* Generate the HTML representing a given menu item ID.
*
* An implementation of theme_menu_item_link()
*
* @param $link
* array The menu item to render.
* @return
* string The rendered menu item.
*/
function examplezen_menu_item_link($link) {
if (empty($link['options'])) {
$link['options'] = array();
}
$test = '<pre>'. var_export($link,TRUE) .'</pre>';
// 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['options']['html'] = TRUE;
}
if (empty($link['type'])) {
$true = TRUE;
}
return $test . l($link['title'], $link['href'], $link['options']);
}
?>Here's some of that exciting test code, from admin_menu:
array (
'load_functions' => '',
'to_arg_functions' => '',
'access_callback' => 'user_access',
'access_arguments' => 'a:1:{i:0;s:22:"administer permissions";}',
'page_callback' => 'user_admin_access',
'page_arguments' => 'a:0:{}',
'title' => 'Access rules',
'title_callback' => 't',
'title_arguments' => '',
'type' => '6',
'description' => 'List and create rules to disallow usernames, e-mail addresses, and IP addresses.',
'menu_name' => 'admin_menu',
'mlid' => '201',
'plid' => '199',
'link_path' => 'admin/user/rules',
'router_path' => 'admin/user/rules',
'link_title' => 'Access rules',
'options' =>
array (
'alter' => true,
),
'module' => 'admin_menu',
'hidden' => '0',
'external' => '0',
'has_children' => '1',
'expanded' => '0',
'weight' => '0',
'depth' => '2',
'customized' => '0',
'p1' => '199',
'p2' => '201',
'p3' => '0',
'p4' => '0',
'p5' => '0',
'p6' => '0',
'p7' => '0',
'p8' => '0',
'p9' => '0',
'updated' => '0',
'in_active_trail' => false,
'href' => 'admin/user/rules',
'access' => true,
'localized_options' =>
array (
'alter' => true,
'alias' => true,
),
)</pre><a href="/admin/user/rules">Access rules</a>And from the navigation menu:
<li class="leaf first"><pre>array (
'load_functions' =>
array (
1 => 'user_uid_optional_load',
),
'to_arg_functions' => 'a:1:{i:1;s:24:"user_uid_optional_to_arg";}',
'access_callback' => 'user_view_access',
'access_arguments' => 'a:1:{i:0;i:1;}',
'page_callback' => 'user_view',
'page_arguments' => 'a:1:{i:0;i:1;}',
'title' => 'My account',
'title_callback' => 'user_page_title',
'title_arguments' => 'a:1:{i:0;i:1;}',
'type' => '6',
'description' => '',
'menu_name' => 'navigation',
'mlid' => '21',
'plid' => '0',
'link_path' => 'user/%',
'router_path' => 'user/%',
'link_title' => 'My account',
'options' =>
array (
),
'module' => 'system',
'hidden' => '0',
'external' => '0',
'has_children' => '0',
'expanded' => '0',
'weight' => '0',
'depth' => '1',
'customized' => '0',
'p1' => '21',
'p2' => '0',
'p3' => '0',
'p4' => '0',
'p5' => '0',
'p6' => '0',
'p7' => '0',
'p8' => '0',
'p9' => '0',
'updated' => '0',
'in_active_trail' => false,
'href' => 'user/1',
'access' => true,
'localized_options' =>
array (
),
)</pre><a href="/user/1">My account</a></li>But nothing for the primary links:
<div id="primary">
<ul class="links"><li class="menu-115 first"><a href="/" title="Example front page.">Home</a></li>
<li class="menu-117 last"><a href="/forum" title="Participate in discussions about Example.">Community Forums</a></li>
</ul> </div> <!-- /#primary -->There's a menu_primary_links() function:
<?php
function menu_primary_links() {
return menu_navigation_links(variable_get('menu_primary_links_source', 'primary-links'));
}
?>But there is no theming in the function it calls, menu_navigation_links.
So this all must be a level above theme_links which gets handed the menu array (somehow) and in this big huge function below throws the HTML around it, here, where we have put in some test code:
<?php
function examplezen_links($links, $attributes = array('class' => 'links')) {
$output = '';
$test .= '<pre>'. var_export($links,TRUE) .'</pre>';
if (count($links) > 0) {
$output = '<ul'. drupal_attributes($attributes) .'>';
$num_links = count($links);
$i = 1;
foreach ($links as $key => $link) {
$class = $key;
// Add first, last and active classes to the list of links to help out themers.
if ($i == 1) {
$class .= ' first';
}
if ($i == $num_links) {
$class .= ' last';
}
if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
$class .= ' active';
}
$output .= '<li'. drupal_attributes(array('class' => $class)) .'>';
if (isset($link['href'])) {
// Pass in $link as $options, they share the same keys.
$output .= l($link['title'], $link['href'], $link);
}
else if (!empty($link['title'])) {
// Some links are actually not links, but we wrap these in <span> for adding title and class attributes
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
$span_attributes = '';
if (isset($link['attributes'])) {
$span_attributes = drupal_attributes($link['attributes']);
}
$output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
}
$i++;
$output .= "</li>\n";
}
$output .= '</ul>';
}
return $test . $output;
}
?>The output, with test code output preceding it, looks like this:
<div id="primary">
<pre>array (
'menu-115' =>
array (
'attributes' =>
array (
'title' => 'Example front page.',
),
'href' => '<front>',
'title' => 'Home',
),
'menu-117' =>
array (
'attributes' =>
array (
'title' => 'Participate in discussions about Example.',
),
'href' => 'forum',
'title' => 'Community Forums',
),
)</pre><ul class="links"><li class="menu-115 first"><a href="/" title="Example front page.">Home</a></li>
<li class="menu-117 last"><a href="/forum" title="Participate in discussions about Example.">Community Forums</a></li>
</ul> </div> <!-- /#primary -->Resolution
All I want to do is throw spans around the links. Ah well. Here is the function below, modified to do exactly that.
It will do it to all sets of links passed through theme('links', $links) but so far on Agaric's example site, at least, that means only the primary links.
<?php
function examplezen_links($links, $attributes = array('class' => 'links')) {
$output = '';
if (count($links) > 0) {
$output = '<ul'. drupal_attributes($attributes) .'>';
$num_links = count($links);
$i = 1;
foreach ($links as $key => $link) {
$class = $key;
// Add first, last and active classes to the list of links to help out themers.
if ($i == 1) {
$class .= ' first';
}
if ($i == $num_links) {
$class .= ' last';
}
if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
$class .= ' active';
}
$output .= '<li'. drupal_attributes(array('class' => $class)) .'>';
if (isset($link['href'])) {
$link['title'] = '<span class="link">' . check_plain($link['title']) . '</span>';
$link['html'] = TRUE;
// Pass in $link as $options, they share the same keys.
$output .= l($link['title'], $link['href'], $link);
}
else if (!empty($link['title'])) {
// Some links are actually not links, but we wrap these in <span> for adding title and class attributes
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
$span_attributes = '';
if (isset($link['attributes'])) {
$span_attributes = drupal_attributes($link['attributes']);
}
$output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
}
$i++;
$output .= "</li>\n";
}
$output .= '</ul>';
}
return $output;
}
?>
It was the easiest-to-follow effective tutorial I've read! now I just have to implement...