Warning message

Documentation is currently being migrated into the new system. Some pages might be temporarily missing, and some guides might appear empty. Thank you for your patience while we are improving Drupal.org documentation.

Working with template suggestions

Last updated on
August 31, 2016 - 14:15

Template suggestions are alternate templates based on existing .tpl.php files. These suggestions can be used when a specified condition is met and the suggested template exists. All layers from core, modules, theme engines and themes can provide the suggestions. You can think of the suggestions as naming hints telling the system to pick and choose based on the right circumstances. The idea is simple but it is a powerful feature providing another layer of customization.

Theme Developer module showing template suggestions for the possible "page" templates. The image shows Drupal 6 template suggestions.
devel showing Drupal 6 template suggestions

These naming suggestions are set from preprocess functions. There are plenty already provided by core. If you need to extend it further, add a preprocessor for the theming hook into your template.php file. The examples below add suggestions on the "node" and "page" theming hooks. It can be added to any hook implemented as a template.

Drupal 7

Theme debug mode

As of Drupal 7.33, Drupal core has a theme debug mode that can be enabled and disabled via the theme_debug variable. Theme debug mode can be used to see possible template suggestions and the locations of template files right in your HTML markup (as HTML comments). To enable it, add this line to your settings.php:

$conf['theme_debug'] = TRUE;

You can enable it with drush using:

drush vset theme_debug 1

And disable using

drush vset theme_debug 0

You'll then see output like this when you inspect or view source:

<!-- THEME DEBUG -->
<!-- CALL: theme('page') -->
<!-- FILE NAME SUGGESTIONS:
   * page--front.tpl.php
   * page--node.tpl.php
   x page.tpl.php
-->
<!-- BEGIN OUTPUT from 'modules/system/page.tpl.php' -->
…
<!-- END OUTPUT from 'modules/system/page.tpl.php' -->

A listing of all the suggestions for Drupal 7 core can be found in Drupal 7 Template Suggestions.

To use the examples below, paste the function definitions into a template.php file in your theme directory, ex: "sites/all/themes/drop/template.php". If a template.php file does not exist in your theme, you may create one. The prefix of "drop" should be the name of your theme.

// Add a single suggestion for nodes that have the "Promoted to front page" box checked.
function drop_preprocess_node(&$variables) {
  if ($variables['promote']) {
    // looks for node--promoted.tpl.php in your theme directory
    $variables['theme_hook_suggestions'] = 'node__promoted';
  }
}

// Add multiple suggestions for pages based on the logged in user's roles.
function drop_preprocess_page(&$variables) {
  global $user;
  
  if (!empty($user->roles)) {
    foreach ($user->roles as $role) {
      $filter = '![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s';
      $string_clean = preg_replace($filter, '-', drupal_strtolower($role));

      // looks for page--[role].tpl.php in your theme directory
      // ex: page--administrator.tpl.php
      $variables['theme_hook_suggestions'][] =  'page__' . $string_clean;
    }
  }
}

There are two ways to add these suggestions.

  1. The key of 'theme_hook_suggestion' accepts a single suggestion and it takes precedence. If the condition is met and the file exists, it will be used ignoring all others.
  2. The key of 'theme_hook_suggestions' (plural) can accept an array of suggestions. They are processed in FILO order (first in last out). Adding to the array should be done with a general condition first, progressively getting more specific so it cascades based on specificity.

A few notes:

  • When adding to 'theme_hook_suggestions', add to the array. Do not reset it since the variables are passed by reference. All the suggestions set before it in core and modules would be lost.
    // Do not do this:
    $variables['theme_hook_suggestions'] = array('hook__suggestion');
      
    // Instead do this:
    $variables['theme_hook_suggestions'][] = 'hook__suggestion';
    
  • Prefix the suggestion with the name of the hook it is associated with, such as "node" or "page". This keeps it clear and the files grouped together. It also minimizes any chance of Drupal registering the template with a different hook.
  • Use two hyphens to separate the hook name from the rest of the suggestion. This is consistent with template naming suggestions in core.
  • Use underscores ("_") instead of hyphens ("-") when adding to the array but use hyphens for your template.
    // Do not do this:
    $variables['theme_hook_suggestions'][] = 'pagemanager-item__' . $style;
    
    // Instead do this:
    $variables['theme_hook_suggestions'][] = 'pagemanager_item__' . $style;
    // to get to pagemanager-item--style1.tpl.php
    

Drupal 6

A listing of all the suggestions for core can be found in Drupal 6 Template Suggestions.

The prefix of "drop" should be the name of your theme.

function drop_preprocess_page(&$variables) {
  global $user;
  
  // Add a single suggestion based on the throttle module in core.
  if (module_invoke('throttle', 'status') && isset($user->roles[1])) {
    $variables['template_file'] = 'page-busy';
  }

  // Add multiple suggestions for pages based on the logged in user's roles.
  if (!empty($user->roles)) {
    foreach ($user->roles as $role) {
      $filter = '![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s';
      $string_clean = preg_replace($filter, '-', drupal_strtolower($role));
      $variables['template_files'][] =  'page-' . $string_clean;
    }
  }

}

Theming a page by arbitrary content types

You could improve above code to have the theme suggestion for all content types in your site.

function drop_preprocess_page(&$variables) {
  if ($variables['node']->type != "") {
    $variables['template_files'][] = "page-node-" . $variables['node']->type;
  }
}

Now just make your template in form page-node-your_content_type. If it's missing, the default page template will be used.

There are two ways to add these suggestions.

  1. The key of 'template_file' accepts a single suggestion and it takes precedence. If the condition is met and the file exists, it will be used ignoring all others.
  2. The key of 'template_files' (plural) can accept an array of suggestions. They are processed in FILO order (first in last out order). Adding to the array should be done with a general condition first, progressively getting more specific so it cascades based on specificity.

With the above example, Drupal will attempt to use a file named "page-busy.tpl.php" when the throttling threshold is met for anonymous users (anonymous role id typically set to 1). The others inform Drupal to look for templates based on the roles assigned to the current user, e.g., "page-authenticated-user.tpl.php". If none apply, the base template of "page.tpl.php" is used.

These are simply examples. You can set any context based on any data available to you.

A few notes:

  • When adding to 'template_files', add to the array. Do not reset it since the variables are passed by reference. All the suggestions set before it in core and modules would be lost.
      // Do not do this:
      $variables['template_files'] = array('hook-suggestion');
      
      // Instead do this:
      $variables['template_files'][] = 'hook-suggestion';
    
  • Prefix the suggestion with the name of the hook it is associated with. This keeps it clear and the files grouped together. It also minimizes any chance of Drupal registering the template with a different hook.
  • Use hyphens instead of underscores for consistency. The main template will never use underscores.
  • Suggestions work only when it is placed in the same directory as the base template. Templates can be placed in any sub-directory of the theme. They must be paired into the same location.
  • The theme registry does not have to be cleared for suggestions. It's only the base template that needs to be registered. Suggestions are discovered on the fly.