Add a span wrapper inside primary and secondary menu links in Drupal 6

Average: 5 (3 votes)
By Benjamin Melançon
on 29 Aug
1 comment

Key words and phrases

span wrapper for primary links make tab-style links for main navigation menu

Tags

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;
}
?>

 

Thanks!

It was the easiest-to-follow effective tutorial I've read! now I just have to implement...

Posted by André (not verified) on Tue, 2008-11-04 14:51
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> <blockquote> <h1> <h2> <h3> <h4> <h5> <h6> <small> <pre> <strike> <sub> <sup> <kbd> <s>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Copy the characters (respecting upper/lower case) from the image.