Theming 101 – The theme_links Function

This article is an in-depth look at the theme_links function. Two notable uses of theme_links are theming a site's primary navigation links and, as of Drupal 5, the link list appearing in a node (nodelinks) i.e., Read More, Comments.

Changing these lists is a common theming requirement. After reading this article you'll be able to quickly determine if theme_links can handle your changes or if a new formatting function is required. You may also find the theme_links function appropriate for other uses in your theme or module.

A Quick Aside on Link Lists

Before CSS a block of text or a table was used for a link list. For example:

<p>
  <a href="link1">Link 1</a> <a href="link2">Link 2</a> <a href="link3">Link 3</a>
</p>

<table>
  <tr>
    <td><a href="link1">Link 1</a></td>
    <td><a href="link2">Link 2</a></td>
    <td><a href="link3">Link 3</a></td>
  </tr>
</table>

With CSS, the current common practice is to use an unordered list:

<ul>
  <li><a href="link1">Link 1</a></li>
  <li><a href="link2">Link 2</a></li>
  <li><a href="link3">Link 3</a></li>
</ul>

CSS display:inline is used when the list is horizontal.

theme_links produces the link list using the current common practice of an unordered list.

Introduction to theme_links

theme_links takes an associative array of link information, and an optional array of tag attributes, and renders them into an unordered list (ul) of links. While doing so, it adds CSS class information to assist the formatting of the list.

Documentation for theme_links is found at api.drupal.org. For example, the Drupal 5 theme_links documentation URL is: http://api.drupal.org/api/5/function/theme_links. This article discusses the Drupal 5 version of theme_links.

theme_links is defined as follows:

<?php

   theme_links
($links, $attributes = array('class' => 'links'))

?>

Per the Drupal calling standard, it's called as follows:

<?php

  $rendered_HTML
= theme('link', $links);
 
$rendered_HTML = theme('link', $links, $attributes);

?>

$links Parameter Format

The first input parameter, shown as $links in the definition above, is an array containing the raw data for each link in the list. The array key is used as the li class name (i.e., <li class="key">). The corresponding array value holds a second associative array containing the raw data for the link.

The following information can be specified for each link's anchor tag: title, href, query, fragment, attributes, html

If these names seems familiar it's because theme_links uses the "l" function (For more information: Creating Links (aka Anchor tags) - The "l" Function). It's good to have an understanding of the l function when working with theme_links, since the link data from the input array is handed directly to this function.

Basic Link List Example:

<?php

$linklist
= array(
 
'item1' => array( 'title' => '1st Item', 'href' => 'one' ),
 
'item2' => array( 'title' => '2nd Item', 'href' => 'two' ),
 
'item3' => array( 'title' => '3rd Item'),
             array(
'title' => '4th Item', 'href' => 'four' ),
 
'item5' => '',
 
'item6' => array( 'title' => '6th Item', 'href' => 'six' )
);

print
theme('links', $linklist);

?>

This will produce, depending on your exact server configuration, something like:

<ul class="links">
  <li class="first item1"><a href="/one" class="item1">1st Item</a></li>
  <li class="item2"><a href="/two" class="item2">2nd Item</a></li>
  <li class="item3"><span class="item3">3rd Item</span></li>
  <li class="0"><a href="/four" class="0">4th Item</a></li>
  <li class="item5"></li>
  <li class="last item6"><a href="/six" class="item6">6th Item</a></li>
</ul>

$attributes Parameter Format

The second input parameter provides a list of attributes for the ul tag. If nothing is specified, it has a default value of array('class' => 'links'). You can observe this in the example above (<ul class="links">). Attributes are specified as key/value pairs where the key is the attribute name and the value is the attribute value.

<ul> Attributes Example:

<?php

$linklist
= array(
 
'item1' => array( 'title' => '1st Item', 'href' => 'one' ),
 
'item2' => array( 'title' => '2nd Item', 'href' => 'two' ),
 
'item3' => array( 'title' => '3rd Item'),
             array(
'title' => '4th Item', 'href' => 'four' ),
 
'item5' => '',
 
'item6' => array( 'title' => '6th Item', 'href' => 'six' )
);
$attributelist = array('class' => 'linklist', 'id' => 'list1');

print
theme('links', $linklist, $attributelist);

?>

This will produce, depending on your exact server configuration, something like:

<ul class="linklist" id="list1">
  <li class="first item1"><a href="/one" class="item1">1st Item</a></li>
  <li class="item2"><a href="/two" class="item2">2nd Item</a></li>
  <li class="item3"><span class="item3">3rd Item</span></li>
  <li class="0"><a href="/four" class="0">4th Item</a></li>
  <li class="item5"></li>
  <li class="last item6"><a href="/six" class="item6">6th Item</a></li>
</ul>

Notice how array('class' => 'linklist', 'id' => 'list1') produced <ul class="linklist" id="list1">.

Full Link Specification Example

For the sake of completeness here is a very contrived example of what a link entry looks like with everything specified:

<?php

$links
= array(
 
'digg' => array(
   
'title' => '<img src="images/diggit.gif" alt="Digg It" />',
   
'href'  => 'http://digg.com/submit',
   
'query' => 'phase=2&url=http://mysite.example.com',
   
'attributes' => array('target' => '_blank'),
   
'fragment' => 'sillyexample',
   
'html' => TRUE
 
)
);

?>

Usage Notes

"first" and "last" class names

theme_links automatically adds the class names "first" and "last" to the first and last li tags, respectively:

<li class="first item1"><a href="/one" class="item1">1st Item</a></li>
<li class="last item6"><a href="/six" class="item6">6th Item</a></li>
Anchor (a) tags are created with the l function

The a tag is created using the l function. All of the l function parameters can be used except for absolute. See Creating Links (aka Anchor tags) - The "l" Function and api.drupal.org for more information on the l function.

No href produces a text-only li item

As shown with example item3, an entry with no href is allowed and will produce a text-only li item:

<?php

'item3' => array( 'title' => '3rd Item' )

?>

This produces title text wrapped in a span tag:

<li class="item3"><span class="item3">3rd Item</span></li>

The array key of the link list is used as a class name for both the li and span tags. Not shown in the example, additional attributes can be specified for the span tag by adding an attributes entry to the link data array.

Empty li items are possible

As shown with example item5, an "empty" entry can be made:

<?php

'item5' => ''

?>

This produces:

<li class="item5"></li>

This might be useful if you're doing CSS image replacement.

Key-less arrays possible but not recommended

As shown with example item4, an entry can be made without a key even though a keyed array is explicitly called for:

<?php
linklist
= array(
   ...
  array(
'title' => '4th Item', 'href' => 'four' ),
   ...
);
?>

This produces:

<li class="0"><a href="/four" class="0">4th Item</a></li>

This output contains an illegal class name because class names are not allowed to start with a digit (1). Always specify a key, even though omitting the key doesn't cause an error.

li and a tag receive key name as class name

The array key of the link list is used as a class name for both the li and a tags. While additional attributes can be defined for the a tag, the array key is the one and only class name you can apply to the li tag.

<?php

'item1' => array( 'title' => '1st Item', 'href' => 'one' ),
'item2' => array( 'title' => '2nd Item', 'href' => 'two' ),

?>
<li class="first item1"><a href="/one" class="item1">1st Item</a></li>
<li class="item2"><a href="/two" class="item2">2nd Item</a></li>
Drupal default for class="links"

If no attributes are specified, class="links" is applied to the ul tag. Drupal provides the following CSS in system.css:

ul.links {
  margin: 0;
  padding: 0;
}
ul.links.inline {
  display: inline;
}
ul.links li {
  display: inline;
  list-style-type: none;
  padding: 0 0.5em;
}

If you want the ul tag created without any attributes to avoid the Drupal system.css formatting, specify an empty array for the attributes parameter:

<?php

$rendered_html
= theme('links', $links, array());

?>

 


1 - Class Naming

http://www.w3.org/TR/CSS21/syndata.html

4.1.3 Characters and case

In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-z0-9] and ISO 10646 characters U+00A1 and higher, plus the hyphen (-) and the underscore (_); they cannot start with a digit, or a hyphen followed by a digit.

Comments

A thorny question that may have a simple answer but it has eluded me. I'm theming a Drupal 4.7 site built with organic groups. The base site has always had tracking turned on. But for the new groups the number of reads is low.

So for the group CSS I used display:none on the list item number to remove the link. Except that in some nodes there are more links in the list. So I used display:none on more links - not realizing immediately that Read More and Add Comment were going to disappear.

Currently I have turned off "view post access" for the whole site. But I would like to have it back for the main site.

Any thoughts?

Hey Angus,

Tangentially related (and handling these kinds of issues is one of the directions I'm heading with the series, if my energy holds up, so this is sort of preview!).

In 4.7 $links is generated as follows: 'links' => $node->links ? theme('links', $node->links) : '' (themes/engines/phptemplate/phptemplate.engine - function phptemplate_node) In other words, $node->links contains an array in the $links Parameter Format I described above.

You should be able to do something like this (warning, I haven't tested this code):
<?php

if (array_key_exists('evil_link_key_name', $node->links)) {
unset($node->links['evil_link_key_name']);
$links = theme('links', $node->links);
}

?>

If you have multiple node types and therefore multiple .tpl.php files it's a good candidate for the _phptemplate_variables function in template.php (Take Control of Your PHPTemplate Variables).

Link you mentioned in your comment is broken (http://www.group42.ca/take_control_of_your_phptemplate_variables = Page not found)

Did you mean http://www.group42.ca/take_control_your_phptemplate_variables ?

Yes, you're correct. It should be http://www.group42.ca/take_control_your_phptemplate_variables

Thanks for pointing that out.

I needed to know how to put images in links for advforum. Thanks!

Michelle

If I'm correctly understanding what you want to do, the easiest way is via CSS.