Community Documentation

How to use template (.tpl.php) files in your own module

Last updated March 28, 2012. Created by xenophyle on February 15, 2010.
Edited by alexweber. Log in to edit this page.

Some modules may need to override the default template files -- page, node, etc. -- provided by Drupal. It can be tricky figuring out how to do this, so this page will present approaches for Drupal 5, 6, and 7.

Why would you want to override a template file in a module rather than in the theme?
There are a number of reasons a module would need to have control of how a piece of content is presented. A module may provide a new content type with a custom node template. In the case of the Print module, it is necessary to exclude the header, footer, and sidebars and then add some other elements.

The Drupal 6 and 7 approaches are similar: telling the theme system to look in the module directory for templates as well as the theme directory. In both cases it may be necessary to limit when the custom template is used. I.e., if a module has its own page.tpl.php, it probably should not be used for every page on the site.

This can be done by naming the custom template in such a way that it will only be used in certain cases. (See Drupal 6 template suggestions and Drupal 7 template suggestions.)

For finer control it can also be done using a preprocess function.

Drupal 7

The Drupal 7 approach is adapted from Adding a module path to the Drupal 7 theme registry.

First create a template file in your module directory.

The next step is to tell the theme system to look there.

// Create a variable to store the path to this module
define('MY_MODULE_PATH', drupal_get_path('module', 'my_module'));

function my_module_theme_registry_alter(&$theme_registry) {
  $theme_registry_copy = $theme_registry;
  _theme_process_registry($theme_registry_copy, 'phptemplate', 'theme_engine', 'my_custom_theme', MY_MODULE_PATH);
  $theme_registry += array_diff_key($theme_registry_copy, $theme_registry);

  // A list of templates the module will provide templates for
  $hooks = array('page');
  foreach ($hooks as $h) {
    // Add the key 'theme paths' if it doesn't exist in this theme's registry
    if (!isset($theme_registry[$h]['theme paths'])) {
      $theme_registry[$h]['theme paths'] = array();
    }

    //Shift this module's directory to the top of the theme path list
    if(is_array($theme_registry[$h]['theme paths'])) {
      $first_element = array_shift($theme_registry[$h]['theme paths']);
      if ($first_element) {
        array_unshift($theme_registry[$h]['theme paths'], $first_element, MY_MODULE_PATH);
      } else {
        array_unshift($theme_registry[$h]['theme paths'], MY_MODULE_PATH);
      }
    }
  }
}

Drupal 6

The Drupal 6 technique comes from Theming Drupal 6 from the Module Layer.

First create a template file in your module directory.

Then tell the theme system to look there.

// Create a variable to store the path to this module
define('MY_MODULE_PATH', drupal_get_path('module', 'my_module'));

function special_page_theme_registry_alter(&$theme_registry) {
  // A list of templates the module will provide templates for
  $hooks = array('page');

  foreach ($hooks as $h) {
    // Add the module path on top in the array of paths
    array_unshift($theme_registry[$h]['theme paths'], MY_MODULE_PATH);
  }
}

Drupal 5

For Drupal 5 I will describe a workaround inspired by the Print module.

Overview of the solution

1. Set up the variables that will be used in the page template.
2. Create a new page template, mypage.tpl.php, inside your module.
3. Include the page template.

Details of the solution

1. Since this is a workaround and not part of the theme system, your template will not have access to the regular theme variables. You will have to set the variables that you want the new template to have access to:

function _mymodule_print_vars_setup() {
    $print['language'] = $GLOBALS['locale'];
    $print['title'] = 'Page XYZ';
    $print['head'] = drupal_get_html_head();
    $print['favicon'] = theme_get_setting("toggle_favicon") ? "<link rel=\"shortcut icon\" href=\"". theme_get_setting("favicon") ."\" type=\"image/x-icon\"/>\n" : "";

    $css_files = array(drupal_get_path('module','mymodule').'/stylesheet1.css', drupal_get_path('module','mymodule').'/stylesheet2.css');
    foreach ($css_files as $css_file)
        $print["css"] .= "<style type=\"text/css\" media=\"all\">@import \"". base_path() . $css_file['file'] ."\";</style>\n";

    $print["content"] = _mymodule_page_content();

    return $print;
}

}

2. Create a template file, which will be very similar to the theme's page.tpl.php, except the variables you will use will be from the $print array you created in step 1.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $print['language'] ?>" lang="<?php print $print['language'] ?>" >
  <head>
    <title><?php print $print['title'] ?></title>
    <?php print $print['head'] ?>
    <?php print $print["favicon"] ?>
    <?php print $print['css'] ?>
  </head>
  <body>
    <div id="wrapper">
        <div id="main-content">
    <?php print $print['content']; ?>
        </div>
        <div id="right-bar">
          <?php print theme('blocks', 'right_bar'); ?>
        </div>
      </div>
    </div>
  </body>
</html>

You can access your main theme's regions using theme_blocks, as shown for the right bar.

3. Then create a function that will be the callback to one of the items in your modules hook_menu implementation:

function mymodule_special_page() {
    $print = _mymodule_print_vars_setup();
    include_once(drupal_get_path('module','mymodule').'/mypage.tpl.php');
}

For a more complete example of this method, study the Print module.

Comments

Awesome

Just I was looking for... Thaks :)

What about search templates?

I can get this to work as advertised in Drupal 7 for page templates, but no luck for search_result.tpl.php or search_results.tpl.php.

I've added 'search_result' and 'search_results' to the hooks array and confirmed that theme_paths was added to each, but the search templates in my module are not being used, it defaults back to the templates in modules/search. Any suggestions?

Try

Put your tpl.php inside your theme's folder.

Did you ever resolve this?

Did you ever resolve this? I'm having the same issue not being able to replace the search tpl files.

Page status

No known problems

Log in to edit this page

About this page

Drupal version
Drupal 5.x, Drupal 6.x, Drupal 7.x
Audience
Programmers

Develop for Drupal

Drupal’s online documentation is © 2000-2013 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License. Comments on documentation pages are used to improve content and then deleted.