Theming the $links variable in Drupal nodes

This snippet of code gives a brief example of how to rewrite components of the $links variable to make them prettier :) Specifically, here I’m overwriting the link generated by the Forward module. You can see the result below: the little envelope icon labelled “Email”. Normally, this would just say “Forward this page”, which is a bit… well, it could be better. Obviously, it’s nice to be able to change these things to taste.


There are two ways to achieve this result: using theme code in template.php, or inside of a helper module. First, I’ll discuss the module approach.


The helper module method is what I had originally used. It’s a little neater, in that you code it once and forget about it, and it doesn’t clutter up template.php’s _phptemplate_variables function, which can easily become bloated with code.


In the module, I’ve added a function to implement Drupal’s hook_link_alter() function. Here’s the code to do it:

<?php
function mymodule_link_alter(&$node, &$links) {
  foreach (
$links as $module => $link) {   // iterate over the $links array
    //drupal_set_message(print_r($links)); // uncomment to display your $links array

    // check if this element is the forward module's link
   
if ($module == 'forward_links') {
     
$title = t('Email this page to a friend');    // change the title to suit
     
$path = path_to_theme() . '/images/email.png'// make an image path

      // now update the links array
      // set the title to some html of the image and choice of link text
     
$links[$module]['title'] = theme('image', $path, $title, $title) . ' Email';

     
// let's set some attributes on the link
     
$links[$module]['attributes'] = array(
       
'title' => $title,
       
'class' => 'forward-page',
       
'rel' => 'nofollow',
      );

     
// this must be set, so that l() interprets the image tag correctly
     
$links[$module]['html'] = TRUE;
    }
  }
}
?>


Ok so really, this ought to be done in the theme layer. Like I said, it’s perhaps not as compact and neat, but here’s the code. It’s mostly the same, but note a couple of additions and changes: firstly, we are not changing $links – this is a pre-rendered string by the time it gets to the template.php. We need to get to the original goodies! Hence, we use $vars[&#039;node&#039;]-&gt;links[module-name][field-name].


Secondly, note that because we have now altered the value of one of the original links’ values, does not mean that the node’s $links is correct. This is the bit that caught me out! We must now regenerate the $links variable using the theme_links() function, as per the last line of code below. This mimics what phptemplate.engine does in core.

<?php
function _phptemplate_variables($hook, $vars = array()) {
  switch (
$hook) {
    case
'node':
      foreach (
$vars['node']->links as $module => $link) {
        if (
$module == 'forward_links') {
         
$title = t('Email this page to a friend');
         
$path = path_to_theme() . '/images/email.png';
         
$vars['node']->links[$module]['title'] =
             
theme('image', $path, $title, $title) . ' Email';
         
$vars['node']->links[$module]['attributes'] =
              array(
'title' => $title, 'class' => 'forward-page', 'rel' => 'nofollow');
         
$vars['node']->links[$module]['html'] = TRUE;
        }
      }
     
$vars['links'] = theme('links', $vars['node']->links,
                                           array(
'class' => 'links inline'));
      break;
  }
}
?>


You can achieve this effect for anything that’s in the $links array. On this page (below), you can see the link I’ve described here, another for print-friendly pages and also a themed comment link.

Blog Tags: DrupalThemesModules

Comments

I’ve updated the article to include theming the links in the theme layer (natch). There was a little trick I missed which is why I hadn’t got it working until now.


Great idea!


Another example is adding the following in node.tpl.php
This example replaces the words “Printer-friendly version” with “printer.png”

<?php
$links
= str_replace('>Printer-friendly version<', ' title="Click to view a printer-friendly version of this document."><img src="images/printer.png"><',$links);
?>

Well… you could do that, but there’s a number of reasons why not to. Firstly, by using a snippet like the one above in the template.php, you are providing a solution to all your node types. Secondly, in the example above, you’re not using standard Drupal functions such as l() and t(), which you really ought to for reasons of coding standards, availability for translation and server security.

Just so you know…

As the print module maintainer, I would like to point out that there's better solutions in the case of the print module than either of the above. You can theme the $links link of the print module to your heart's content using the theme_print_format_link() function.

See more about that in #4 of http://drupal.org/node/190173.

Thanks for the tip, Joao – the technique I used above is really only meant as an indicator of a generic solution. A lot of modules, including forward (aobve) and taxonomy (core), do not have such theme functions. As such, this technique is probably the next most favourable.

Good news that the print module is becoming more configurable and accessible though!

hi,

is it possible to do this without making a module? somewhere in phptemplate for example.

It certainly is – I haven’t had enough free time to juggle the example above into theme-based code (that works for me…!) yet though.


The $links variable is available from within _phptemplate_variables, so you can alter this in template.php in the case: &#039;node&#039; bit of that. If you read this article that last bit will be clearer, if you don’t already know what I mean.


So, the code below should work in a similar fashion, although I’ve had mixed luck – it had otherwise been my intention to publish the full code for that method also.

<?php
 
function _phptemplate_variables($hook, $vars = array()) {
  switch (
$hook) {
    case
'node':
    foreach (
$vars['node']->links as $module => $link) {
      if (
$module == 'forward_links') {
       
// alter stuff here
     
}
    }
  }
}
?>

hi, I want to theme $links in comments

in _phptemplate_variables function, I add following code

case 'comment':
print_r($vars['comment']->links);
break;
nothing shows up, probably theres no such variable called $vars['comment']->links.

can you please show me how theme it in comment. I got stuck here for 2 days.

thank you so much for ur help.

does this work in drupal 6?

I don’t think there’s any issue with using this for D6, but you might want to check the function parameters on whichever one you use, to make sure they’re the same.

For D6 you should probably use YOURTHEME_preprocess_node instead of _phptemplate_variables though.

Thanks for this article, it worked for me

It is easy to do it for my website, but I found that if I use _preprocess_node(&$vars, $hook) then I can not get the node ID in the function.

Add new comment