Skip to main content

Theming Drupal 6 from the module layer

Ref: http://11heavens.com/theming-Drupal-6-from-the-module-layer

You start with creating a DOT info file for your module. The name of which would be in our case special_page.info.

;$Id$
name = Special Page
description = Provides a template file for my content type CONTENT_TYPE_NAME.
core = 6.x

Then you go about creating your DOT module file, ie: special_page.module.

<?php
// $Id$
/**
 * @file
 * Module that provides a special template for pages that show 
 * ONE node of content type CONTENT_TYPE_NAME.
 */

You probably should implement HOOK_help() in your module, but I will skip that, and cut the chase to what we really need.

At this point, you need to tell the theme system to use your template, and to use it only
in certain situations. Your 'situations' will differ from mine. In my
case, I wanted the theme system to use my template on a node page, hence
any page with path node/nid, yet only on pages that show the node in view 'mode', so I did not want the template to be used when the path is node/nid/edit
for example. There are many ways to skin the cat here. I decided to use
the fact that a $node object is passed to the page.tpl.php template
only when the page is a node page, as you will see in the following code
snippet. Here, I will make use of a preprocess function to pass on to
the theme system a suggestion about a new module-supplied template.

function special_page_preprocess_page(&$variables) {
 // If this is a node page (not a list of nodes page) and
 // the node is shown in 'view' mode rather than 'edit' or whatever.
 if (isset($variables['node']) && (arg(2) === NULL)) {
 // If the content type of that one node is 'CONTENT_TYPE_NAME'.
 if ($variables['node']->type == 'CONTENT_TYPE_NAME') {
  $variables['template_file'] = 'page-CONTENT_TYPE_NAME';
 }
 }
}

Then feel free to create such template file. As a reminder, no need
to add the tpl.php extension to the value you assign to
$variables['template_file']. Also, that name can be anything, I am just
following conventions here by prefixing with page, as in
page-SOMETHING.tpl.php. Make sure that the name you provide here matches
the name of your template file.

Then, you are faced with a small problem: the template file will need
to be placed in the theme folder in order to be picked up by Drupal's
theme system. But you don't want that. So what to do? Here comes a
situation where we can use the module hook HOOK_theme_registry_alter(). For the theme hook you want to provide special theming for (hook in theme parlance here), you will have to tell Drupal Hey, Drupal, please look in my module folder over here, you may find a template file you will need.

EDIT: As of Drupal 6.7, this last step should no longer be necessary. See this page in the Theming Guide on Drupal.org for details. I haven't had the chance to re-test my module without the following snippet.

function special_page_theme_registry_alter(&$theme_registry) {
 $theme_hook = 'page'; // my hook name
 // Get the path to this module
 $modulepath = drupal_get_path('module', 'special_page');
 // Add the module path on top in the array of paths
 array_unshift($theme_registry[$theme_hook]['theme paths'], $modulepath);
 // dsm($theme_registry[$theme_hook]['theme paths']);
}

And you are done.

A word on performance

What's more...

The hook function HOOK_theme_registry_alter() is called only when the
theme registry is rebuilt, that is, when you clear your Drupal cache.
(It is called for all modules that implement it of course.)

The hook is NOT called at every page refresh :-)

What a relief.

To test this, uncomment the dsm() call.