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:
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 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));
?>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)
}
?>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.
<?php
print $title;
?><?php
print $body;
?>
<?php
print $link;
?>
Comments
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:
<?phpfunction 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