hook_theme and tpl.php files: registering them with drupal, and passing variables

There is one way to let drupal know about a theme function or template. There are two ways to send variables to a template, but one of them has a lot of disadvantages.

We'll use two theme functions, with an identical template setup to illustrate these methods:

Creating Theme Functions and Routing Them to a Template

There's only one way, hook_theme()

<?php
/**
* Implementation of hook_theme().
* DRUPAL WONT SEE THIS HOOK UNTIL YOU CLEAR YOUR CACHE
*/
function exampleModule_theme() {
  return array(
   
// as in 'theme('verbose_method',...)
   
'verbose_method' => array(
     
// routes to file exampleModule/spanks-box-thing.tpl.php or [YOUR ACTIVE THEME DIRECTORY]/spanky-box-thing.tpl.php
     
'template' => 'spankys-box-thing',
     
// these variables must be called in the theme function, and will appear in the template as $title, $body, $link
     
'arguments' => array(
       
'title' => null,
       
'body' => null,
       
'link' => null,
      ),
    ),
   
'preprocess_method' => array(
     
'template' => 'spankys-box-thing',
     
'arguments' => array('node' => null),
    ),
  );
}
?>

The Verbose Function Method of sending variables to the tpl.php file

The verbose method is called such because it requires you to first define all the variables in hook_theme, and you have to set all those variables yourself when you call the theme function.

<?php
$output
= theme('verbose_method', $node->title, $node->teaser, l($node->title, 'node/'.$node->nid));
?>

The preprocess method of sending variables to the tpl.php file

Calling this theme function is decidedly less verbose.

<?php

$output
= theme('preprocess_method', $node);
return
$output;
?>

However, it requires a little extra code before it magically sends variables with nice names to the tpl.php file. Every theme function automatically looks for a preprocess function. You can preprocess in either the theme, or the module like in this example.

<?php
/**
* Note the pattern [ module_name ] _preprocess_ [ theme_hook ](&$vars)
*/
function exampleModule_preprocess_verbose_method(&$vars) {
// node is only available because we passed it when we called theme function and defined in the arguments array of hook_theme
 
$node = $vars['node'];
 
// $vars['title'] becomes $title in spanky-box.tpl.php
 
$vars['title'] = $node->title;
 
// and so on
 
$vars['body'] = $node->teaser;
// and so on
 
$vars['link'] = l($node->title, 'node/'.$node->nid);
 
// hint: nothing needs to be returned because of it being passed by reference (that's what the little &$ thing means in $vars)
}
?>

Discussion: Why preprocessing is superior

Generally speaking, I only use the preprocess method. Most of the time, I find myself dealing with an object, such as a $node, $user, $comment, $block, or $file. Often, I'm not exactly sure what data I'll need passed to the template when I first write it, so relying on the preprocess functions makes changes easier. Instead of having to change every instance of me having called the function, update the hook_theme function, I only have to alter a line in the preprocess function.

The preprocessing layer gives my brain a break, and doesn't require me to remember all sorts of nonsense like whether the 4th parameter of theme_gizmo is a widget, or a thingamajig. In addition, when dealing with say -- CCK nodes -- I don't have to remember $node->field_something_I_wish_named_better[0]['value'] every time I call the function.

Finally, the layer encourages better code. If I have to turn something into an item_list before it goes into the tpl.php file, I can freely take care of it in the preprocessing layer, instead of doing it before I call the theme function, or in the template file itself. All these arbitrary operations that used to go "where" now have a place. Sure the layer gets ugly at times, but at least the ugliness is contained, and I know where to look for it if I have to change it.

The only time I'll go for the verbose method is when I'm not working $objects, or other complex data types. But I find that to be a rare occurrence.

The template file

spankys-box-thing.tpl.php

<?php
print $title;
?>

<?php
print $body;
?>
<?php
print $link;
?>