extending drupal templating
One of the most common questions on Drupal's theming forums is how to create an individual layout for a specific page or node. In this tutorial I'll show you how to do just that!
Let's start off by opening template.php in your theme's folder. If you do not have this file you're probably using a theme that is not powered by the phpTemplate templating engine, and as such, this tutorial will not be of much use to you.
Rather than walking you through every line of code (which is simple enough to be understood by anyone with basic PHP knowledge), I'll just provide the good stuff and explain it beneath:
Throw the following code into template.php, integrating with existing code when appropriate.
For Drupal 5.x:
{ switch ($hook) { case 'page': //code block from the Drupal handbook //the path module is required and must be activated if(module_exists('path')) { //gets the "clean" URL of the current page $alias = drupal_get_path_alias($_GET['q']); $template_filename = 'page'; { $template_filename = $template_filename.'-'.$path_part; $suggestions[] = $template_filename; } $vars['template_files'] = $suggestions; } break; case 'node': //default template suggestions for all nodes $vars['template_files'][] = 'node'; //individual node being displayed if($vars['page']) { $vars['template_files'][] = 'node-page'; $vars['template_files'][] = 'node-'.$vars['node']->type.'-page'; $vars['template_files'][] = 'node-'.$vars['node']->nid.'-page'; } //multiple nodes being displayed on one page in either teaser //or full view else { //template suggestions for nodes in general $vars['template_files'][] = 'node-'.$vars['node']->type; $vars['template_files'][] = 'node-'.$vars['node']->nid; //template suggestions for nodes in teaser view //more granular control if($vars['teaser']) { $vars['template_files'][] = 'node-'.$vars['node']->type.'-teaser'; $vars['template_files'][] = 'node-'.$vars['node']->nid.'-teaser'; } } break; case 'block': if($vars['block']->subject != '') { //the "cleaned-up" block title to be used for suggestion file name $vars['template_files'][] = 'block-'.$subject; } break; } return $vars; }
For Drupal 6.x:
function phptemplate_preprocess_page(&$vars) { //code block from the Drupal handbook //the path module is required and must be activated if(module_exists('path')) { //gets the "clean" URL of the current page $alias = drupal_get_path_alias($_GET['q']); $template_filename = 'page'; { $template_filename = $template_filename.'-'.$path_part; $suggestions[] = $template_filename; } $vars['template_files'] = $suggestions; } } function phptemplate_preprocess_node(&$vars) { //default template suggestions for all nodes $vars['template_files'][] = 'node'; //individual node being displayed if($vars['page']) { $vars['template_files'][] = 'node-page'; $vars['template_files'][] = 'node-'.$vars['node']->type.'-page'; $vars['template_files'][] = 'node-'.$vars['node']->nid.'-page'; } //multiple nodes being displayed on one page in either teaser //or full view else { //template suggestions for nodes in general $vars['template_files'][] = 'node-'.$vars['node']->type; $vars['template_files'][] = 'node-'.$vars['node']->nid; //template suggestions for nodes in teaser view //more granular control if($vars['teaser']) { $vars['template_files'][] = 'node-'.$vars['node']->type.'-teaser'; $vars['template_files'][] = 'node-'.$vars['node']->nid.'-teaser'; } } } function phptemplate_preprocess_block(&$vars) { //the "cleaned-up" block title to be used for suggestion file name }
Update: If you are using Drupal 6.x, you should clear the "theme registry" whenever you create new theme functions or templates by one of the following two methods:
- The clear button located at "Administer -> Site configuration -> Performance"
- Calling drupal_rebuild_theme_registry(). (hint: place this at the top of your template.php file while you're developing the site & remove from production)
In Drupal 5.x everything is handled by the single _phptemplate_variables() function, while in Drupal 6.x the same functionality is achieved by making separate functions for page, node and block content.
What the above code will do is make Drupal look for more template files than just the default node.tpl.php, block.tpl.php and page.tpl.php. We've added considerably more template suggestions, allowing for very granular templating.
The best way to see and understand what template files are being looked for is to print out the $vars['template_files'] array:
echo '<pre>'; echo '</pre>';
... either at the end of _phptemplate_variables() (for Drupal 5.x) or at the end of the phptemplate_preprocess_page() / phptemplate_preprocess_node() / phptemplate_preprocess_block() functions (for Drupal 6.x).
The output may look something like this (example for pages):
Array { [0] = 'page' [1] = 'page-about_us' [2] = 'page-about_us-staff' }
In this example, when the page mysite.com/about-us/staff is loaded, Drupal will look for the following template files: page-about_us-staff.tpl.php, page-about_us.tpl.php and page.tpl.php, using the first available one.
The same technique applies to nodes and to blocks.
When theming, remember to print out $vars['template_files'] to see what template files Drupal will look for!
Comments
Very helpful post! Thanks! The $vars['template_files'] array is so cool! I'm going to use that a lot!
Very Impresive.
I don't understant the first thing but I'll get there bit by bit.
Anyway, many thanks for the reply at Drupal forums.
I will be studying the tutorials and instructions and will see...
Many many thanks.
Fer
Thanks Hi, when doing this, do you even need the contemplates module anymore? Or does it still have advantages?
Contemplate is handy for a quick adjustment in layout, but for serious layout changes I think separate template files are the way to go. It's simply faster to develop in your favourite IDE, with code highlighting, formatting, and all the other useful stuff. Not to mention that it's faster to hit CTRL+S than drag the mouse to that "Submit" button, and when you want to continue making changes it's easier to ALT-TAB back to your IDE than to edit the template through the web interface. But, in the end it all comes down to personal preference - do whatever works better for you :).
I've never had to insert your 5x snippet into template.php for custom node.type.tpl.php files to work in Drupal 5x. Why do you have that?
Drupal has some default template suggestions, including the one you mentioned. I still specify the node-type.tpl.php suggestion to stay consistent and to always have it in the $vars['page_templates'] array for easy access.
thx,,.,
Well there's actually a way to store disk-based templates with contemplate. ;)
In most cases Drupa's template suggestions can solve problems. If you have some really specific requirements, than your solution could be fine. Anyway, really nice writing.
I personally used contemplate with my 2nd drupal theme, it made things much easier but I know its not the right way to do it. Hopefully on my next try...
Nicely written, insightful.
I personally used contemplate with my 2nd drupal theme, it made things much easier but I know its not the right way to do it. Hopefully on my next try...
When using this code , the different frontpage using page-front.tpl.php does not work.
That's correct - this code overrides the template suggestions, so if you'd like the original page-front.tpl.php to work you would need to add a condition to check for the front page using drupal_is_front_page(), and then add the page-front suggestion.
I like your blog,and also like the article,and thank you for provide me so much information :))
Post new comment