Skip to content Skip to navigation

Using Templates in a Custom Drupal Module

In Drupal development land, the theme is what controls the final HTML, CSS, and Javascript that get delivered to the browser.

Sometimes, however, in developing a custom module, you want to provide a suggestion for an HTML framework, and not rely on the theme's default implementation of a given block of HTML.

You may ask yourself:

Can I use .tpl.php files in a Drupal module?

(And you may ask yourself, "How do I work this?", and you may ask yourself, "Where is that large automobile?")

Enter hook_theme_registry_alter()

Drupal's API includes a nifty function named hook_theme_registry_alter(). This hook allows you to - wait for it - alter the theme registry. The theme registry "maintains cached data on the available theming hooks and how to handle them". By altering the theme registry, you can tell Drupal to look elsewhere for theme templates (e.g., *.tpl.php files).

See What's in the Theme Registry

  1. Install and enable the Devel module
  2. Call dpm($theme_registry) in your custom module:

    function mymodule_theme_registry_alter(&$theme_registry) {
      dpm($theme_registry);
    }
                   
  3. Clear your theme-registry cache: drush cc theme-registry

  4. Reload the page, and you then get a nice Krumo display of the entire $theme_registry array.

    Screenshot of a Krumo output of the $theme_registry variable

  5. In this case, we want to override the search page "no results" language (which has been the subject of contentious debate) with a custom template.
    Screenshot of the default Drupal search page for no results found
  6. $theme_registry['search_results'] looks like this:

    Array
    (
        [variables] => Array
            (
                [results] =>
                [module] =>
            )

        [file] => search.pages.inc
        [template] => modules/search/search-results
        [type] => module
        [theme path] => modules/search
        [includes] => Array
            (
                [0] => modules/search/search.pages.inc
            )

        [preprocess functions] => Array
            (
                [0] => template_preprocess
                [1] => template_preprocess_search_results
                [2] => contextual_preprocess
            )

        [process functions] => Array
            (
                [0] => template_process
                [1] => rdf_process
            )

    )

    Screenshot of a Krumo output of just the $theme_registry['search_results'] array

Alter the Theme Registry

We're going to override that setting in the theme registry, and tell the theme system to look in our custom module (named "mymodule") for a template:

function mymodule_theme_registry_alter(&$theme_registry) {
  // tell the theme system to look in the "templates" subdirectory within our module directory
  $theme_registry['search_results']['theme paths'] = array(0 => drupal_get_path('module', 'mymodule') . '/templates');
  $theme_registry['search_results']['theme path'] = drupal_get_path('module', 'mymodule') . '/templates';
  $theme_registry['search_results']['path'] = drupal_get_path('module', 'mymodule') . '/templates';
  // tell the theme system to use 'search-results.tpl.php' as the template file. Note that you do not include 'tpl.php'
  $theme_registry['search_results']['template'] = 'search-results';
}

Our search-results.tpl.php file looks like this:

<?php
$content = '<ul>';
$content .= '<li>' . t('Check if your spelling is correct.') . '</li>';
$content .= '<li>' . t('Simplify your search by using fewer words.') . '</li>';
$content .= '<li>' . t('Remove quotes around phrases to match each word individually: %stanfordquote will match less than %stanfordnoquote.', array('%stanfordquote' => '"stanford university"', '%stanfordnoquote' => 'stanford university')) . '</li>';
$content .= '<li>' . t('Consider loosening your query with <em>OR</em>: <em>stanford university</em> will match less than <em>stanford OR university</em>.') . '</li>';
$content .= '</ul>';
?>
<?php if ($search_results): ?>
  <h2><?php print t('Search results');?></h2>
  <ol class="search-results <?php print $module; ?>-results">
    <?php print $search_results; ?>
  </ol>
  <?php print $pager; ?>
<?php else : ?>
  <h2><?php print t('Your search did not yield any results');?></h2>
  <?php print $content; ?>
<?php endif; ?>

The Results

Now our $theme_registry['search_results'] looks like this:

Array
(
    [variables] => Array
        (
            [results] =>
            [module] =>
        )

    [file] => search.pages.inc
    [template] => search-results
    [type] => module
    [theme path] => sites/all/modules/mymodule/templates
    [includes] => Array
        (
            [0] => modules/search/search.pages.inc
        )

    [preprocess functions] => Array
        (
            [0] => template_preprocess
            [1] => template_preprocess_search_results
            [2] => contextual_preprocess
        )

    [process functions] => Array
        (
            [0] => template_process
            [1] => rdf_process
        )

    [theme paths] => Array
        (
            [0] => sites/all/modules/mymodule/templates
        )

    [path] => sites/all/modules/mymodule/templates
)

Screenshot of a Krumo output of just the $theme_registry['search_results'] array, after it has been altered

And our search results page looks like this:

Screenshot of the modified Drupal search page for no results found

Note that "bike shed" has been replaced by "stanford university"

See Also

Categories: 

Comments

Check out the the View Mode Templates module: https://drupal.org/project/view_mode_templates

Makes creating template very easy.

Thanks for the tip, Mark!

Love the humor in an otherwise usually dry content landia.
What kind of soap is used to wash a purple monkey in a dishwasher?

I'd recommend a color-fast dishwasher detergent, lest you end up with a lavender monkey.

And you may tell yourself, "This is not my beautiful house."
And you may tell yourself, "This is not my beautiful wife."

After struggling to override the ds_search module's search-results this gave me enough information to make it work

This tutorial outlines the specifics for using hook_theme_registry_alter() to modify an existing registry entry, but are these instructions the same for new additions to the registry?

To clarify...

This tutorial explains how to tell the registry to look for the search-results template in your own custom module. Within Drupal, there is a fairly good chance that the search results will already exist within the registry; just as 'page', 'html' and 'block' would. This code will update the registry accordingly.

However, if there is a registry entry needed, that does not exist already in the $theme_registry array, will these instructions work the exact same way for the addition of new registry items, or will additional information be required?

Hey Tim,
If you would like to use this function to add new templates you can use the following within this function (not I didn't write this and I cant recall where I got it from)
{code}
// Find all .tpl.php files in this module's folder recursively.
$template_file_objects = drupal_find_theme_templates($theme_registry, '.tpl.php', PATH TO MODULE HERE);
// Iterate through all found template file objects.
foreach ($template_file_objects as $key => $template_file_object) {
// If the template has not already been overridden by a theme.
if (!isset($theme_registry[$key]['theme path']) || !preg_match('#/themes/#', $theme_registry[$key]['theme path'])) {
// Alter the theme path and template elements.
$theme_registry[$key]['theme path'] = PATH TO MODULE HERE;
$theme_registry[$key] = array_merge($theme_registry[$key], $template_file_object);
$theme_registry[$key]['type'] = 'module';
}
}
{code}