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:

  1. function _phptemplate_variables($hook, $vars = array())
  2. {
  3. switch ($hook)
  4. {
  5. case 'page':
  6.  
  7. //code block from the Drupal handbook
  8.  
  9. //the path module is required and must be activated
  10. if(module_exists('path'))
  11. {
  12. //gets the "clean" URL of the current page
  13. $alias = drupal_get_path_alias($_GET['q']);
  14.  
  15. $suggestions = array();
  16. $template_filename = 'page';
  17. foreach(explode('/', $alias) as $path_part)
  18. {
  19. $template_filename = $template_filename.'-'.$path_part;
  20. $suggestions[] = $template_filename;
  21. }
  22.  
  23. $vars['template_files'] = $suggestions;
  24. }
  25.  
  26. break;
  27.  
  28. case 'node':
  29.  
  30. //default template suggestions for all nodes
  31. $vars['template_files'] = array();
  32. $vars['template_files'][] = 'node';
  33.  
  34. //individual node being displayed
  35. if($vars['page'])
  36. {
  37. $vars['template_files'][] = 'node-page';
  38. $vars['template_files'][] = 'node-'.$vars['node']->type.'-page';
  39. $vars['template_files'][] = 'node-'.$vars['node']->nid.'-page';
  40. }
  41. //multiple nodes being displayed on one page in either teaser
  42. //or full view
  43. else
  44. {
  45. //template suggestions for nodes in general
  46. $vars['template_files'][] = 'node-'.$vars['node']->type;
  47. $vars['template_files'][] = 'node-'.$vars['node']->nid;
  48.  
  49. //template suggestions for nodes in teaser view
  50. //more granular control
  51. if($vars['teaser'])
  52. {
  53. $vars['template_files'][] = 'node-'.$vars['node']->type.'-teaser';
  54. $vars['template_files'][] = 'node-'.$vars['node']->nid.'-teaser';
  55. }
  56. }
  57.  
  58. break;
  59.  
  60. case 'block':
  61.  
  62. $vars['template_files'] = array('block', 'block-'.$vars['block']->delta);
  63.  
  64. if($vars['block']->subject != '')
  65. {
  66. //the "cleaned-up" block title to be used for suggestion file name
  67. $subject = str_replace(" ", "-", strtolower($vars['block']->subject));
  68.  
  69. $vars['template_files'][] = 'block-'.$subject;
  70. }
  71.  
  72. break;
  73. }
  74.  
  75. return $vars;
  76. }

For Drupal 6.x:

  1. function phptemplate_preprocess_page(&$vars)
  2. {
  3. //code block from the Drupal handbook
  4.  
  5. //the path module is required and must be activated
  6. if(module_exists('path'))
  7. {
  8. //gets the "clean" URL of the current page
  9. $alias = drupal_get_path_alias($_GET['q']);
  10.  
  11. $suggestions = array();
  12. $template_filename = 'page';
  13. foreach(explode('/', $alias) as $path_part)
  14. {
  15. $template_filename = $template_filename.'-'.$path_part;
  16. $suggestions[] = $template_filename;
  17. }
  18.  
  19. $vars['template_files'] = $suggestions;
  20. }
  21. }
  22.  
  23. function phptemplate_preprocess_node(&$vars)
  24. {
  25. //default template suggestions for all nodes
  26. $vars['template_files'] = array();
  27. $vars['template_files'][] = 'node';
  28.  
  29. //individual node being displayed
  30. if($vars['page'])
  31. {
  32. $vars['template_files'][] = 'node-page';
  33. $vars['template_files'][] = 'node-'.$vars['node']->type.'-page';
  34. $vars['template_files'][] = 'node-'.$vars['node']->nid.'-page';
  35. }
  36. //multiple nodes being displayed on one page in either teaser
  37. //or full view
  38. else
  39. {
  40. //template suggestions for nodes in general
  41. $vars['template_files'][] = 'node-'.$vars['node']->type;
  42. $vars['template_files'][] = 'node-'.$vars['node']->nid;
  43.  
  44. //template suggestions for nodes in teaser view
  45. //more granular control
  46. if($vars['teaser'])
  47. {
  48. $vars['template_files'][] = 'node-'.$vars['node']->type.'-teaser';
  49. $vars['template_files'][] = 'node-'.$vars['node']->nid.'-teaser';
  50. }
  51. }
  52. }
  53.  
  54. function phptemplate_preprocess_block(&$vars)
  55. {
  56. //the "cleaned-up" block title to be used for suggestion file name
  57. $subject = str_replace(" ", "-", strtolower($vars['block']->subject));
  58.  
  59. $vars['template_files'] = array('block', 'block-'.$vars['block']->delta, 'block-'.$subject);
  60. }

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:

  1. echo '<pre>';
  2. print_r($vars['template_files']);
  3. 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):

  1. Array
  2. {
  3. [0] = 'page'
  4. [1] = 'page-about_us'
  5. [2] = 'page-about_us-staff'
  6. }

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...

I visited this site and found it informative u also visit this site and surely u will find this visit productive itil certification

In developing countries, the number dedicated servers and seriousness of the problems faced are naturally greater. People in more remote or agrarian areas are sometimes unaware of the website hosting importance of education. However, many countries have an active Ministry of Education, and in many subjects, such as foreign language learning, the degree of education is actually much higher than in industrialized countries; for example, it is not at all uncommon for students in many developing dedicated server countries to be reasonably fluent in multiple foreign languages, whereas this is much more of a rarity in the supposedly "more educated" wireless internet service countries where much of the population is in fact monolingual.

Post new comment

The content of this field is kept private and will not be shown publicly.
Mollom CAPTCHA
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated.