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

10.10.2008

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

Comments

buy wow gold cheap wow power

Thanks for the post. Helped

Thanks for the post. Helped me much

Promoters who’ve been in the

Promoters who’ve been in the concert business for years realize that you can’t over promoter a show. It’s impossible. And they know that even huge acts won’t draw a crowd if posters are all that’s getting the word out. And full-time promoters, who pay thousands of dollars to bring artists, MUST draw a crowd or they don’t eat.

Online High School Diploma and High school online

It would be a real chance for

It would be a real chance for us to show leadership to the open source community. My guess is that others will follow our lead, which will result in hosting companies finally getting off their lazy, fat, grotesquely slothful asses and upgrading their freaking PHP version (its not that hard! for gods sake!).
online bachelor degree

an effect can become a cause,

an effect can become a cause, reinforcing the original cause and producing the same effect in an intensified form, and so on indefinitely. A man may take to drink because he feels himself to be a failure, and then fail all the more completely because he drinks.
online masters degree

My friends, PHP is dying.

My friends, PHP is dying. Every day, the best programmers are moving to, faster, better constructed, more powerful languages such as python and ruby. The developers of PHP have been aware of this for some time. That's why they released PHP 5*.
online doctorate degree

reply

Attaching couple of patch files which need reviewing, tracker now runs through the theme API in the supplied patch.
marirea sanilor

I think you are right here,

I think you are right here, I'll keep looking though...
lose stomach fat fast

How to pass the whole page

What if I want to theme a page this way? When I chage theme('page', $mypage) to theme('preprocess_method', $mypage) I get nothing?

Thanks

You never directly call

You never directly call "hook_preprocess_tfunction". When theme('page') gets called, it automatically searches for preprocessor functions

function [theme_name]_preprocess_page(&$vars)

or

function [module_name]_preprocess_page(&$vars)

Within these functions you can add or alter data in $vars. For example:

<?php
function blueprint_preprocess_page(&$vars) {
 
// overwrites site name
 
$vars['site_name'] = 'Best Website Ever';
// adds a new variable that will be available as $goober in page.tpl.php
$vars['goober'] ="bob says, yer mom!";
}
?>

If you wish to radically alter the page template based on path you could do it merely by creating a new page.tpl.php.

For example, lets say you had a special path for lightboxes sitename.com/lightbox.
You could add a new page.tpl.php file called page-lightbox.tpl.php.

I thought that's what you

I thought that's what you were doing in your example with preprocess_method.

My goal is to have the module select the template. The page is being saved to a file, not sent to the browser. Ideally the user will select which template to use when the page is saved. My trouble seems to be that I can get the module to use the right template but none of the content is sent to it.

  //Create a full url, the themed page.
  $htmlview  = $base_url .'/'. $dest;
  menu_set_active_item('node/'. $form_state['values']['nid']);
  $test = menu_execute_active_handler();
  $page_html = theme('page', $test );

Then $page_html gets saved to a file.

This on its own will use the default page template. Somehow I need to pass something to _preprocess_page that I can use to tell it which template to use. I thought I was following your example but couldn't get it to work.

Anyway, thanks for looking at this.

I did it like this

  $page_html = theme('htmlsave');

and then

function htmlsave_theme() {
  return array (
    'htmlsave' => array(
      'path' => drupal_get_path('module', 'htmlsave') .'/tpl',
      'template' => variable_get('htmlsave_template', 'htmlsave-fullpage'),
      'arguments' => array(),
    ),
  );
}

And then I reused almost the full theme_preprocess_page to get all my variables in the template.

Thanks for the post. Helped

Thanks for the post. Helped me much

_phptemplate_callback drupal 6 replacement

The reason I'm using such a wierd title is that this is exactly the tutorial I was looking for (plain simple and addresses my need to simply call a tpl from a page).
It's very easy to fall deep into preprocess land and get confused if your not careful.
The next person which is familiar with _phptemplate_callback tpl invocation might find this helpful.
Thanks for this post and others which have been an important part of my themeing education :)
Lior

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>
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.