Using different template (tpl.php) files for a specific content type in Drupal 7

Use case

In one of our sites, we post email communications that were sent out as all-campus announcements on our website.

The problem is, our basic web template does not look like an email template.

So I thought, “I wonder if I could just load a separate set of tpl.php files based on the content type.” Spoiler alert: I could.

I wanted a solution that didn’t require hacking my original theme. I wanted to leave the current theme untouched and simply provide new html.tpl.php and page.tpl.php for this specific content type (presidential_email).

Start with Features

This step is technically optional. If you don’t have a local or dev environment then you don’t need to package your content type in a feature. But for those of us who have to push code through dev -> stg -> prod, features is the best route so you don’t have to rebuild the content type on each environment.

Create your content type in your local environment. Add fields to your liking. Now export that content type using Features.

I typically use the “Generate Feature” functionality under Advanced Options, but you can do whatever you want. Generate Feature allows me to write the code directly where I want to. In this case, it was sites/all/modules/custom.

Fire up your code editor and add your hooks

Go to your sites/all/modules/custom directory and you should see a folder in the path you specified with your content type exported into a Features module.

Add your hooks to your modulename.module file to really get cookin’!

hook_theme

In your hook_theme implementation, you want to specify the new tpl files you want to use. In my case, I want this module to override html.tpl.php and page.tpl.php for the presidential_email content type.

/**
 * Implements hook_theme().
 */
function presidential_email_theme($existing, $type, $theme, $path) {
    $theme = array();
    $theme['html__presidential_email'] = array(
        'render element' => 'content',
        'base hook' => 'node',
        'template' => 'html--presidential-email',
        'path' => drupal_get_path('module', 'presidential_email') . '/templates',
    );
    $theme['page__presidential_email'] = array(
        'render element' => 'content',
        'base hook' => 'node',
        'template' => 'page--presidential-email',
        'path' => drupal_get_path('module', 'presidential_email') . '/templates',
    );
    return $theme;
}

Create your templates folder and files
In your created module folder, add a templates folder. The above functions are telling Drupal to look in yourmodule/templates for html–presidential-email.tpl.php and page–presidential-email.tpl.php.

hook_css_alter

Depending on your use case, this could be optional. In my case, I didn’t want ANY of the typical CSS to be loaded because I wanted to use inline styles created by the MailChimp template. To achieve this, my hook_css_alter looked something like this:

/**
 * Implements hook_css_alter().
 */
function presidential_email_css_alter(&$css) {
    $node = menu_get_object();
    if ($node && $node->type == 'presidential_email' ) {
        foreach ($css as $k => $v) {
            if (!strpos($k, "navbar")) {
                unset($css[$k]);
            }
        }
    }
}

Essentially, this code checks to see if the current node is a ‘presidential_email’ and then loops through all the CSS files, unsetting them all unless it’s necessary for the navbar (I still want it to look presentable while logged in).

hook_preprocess_html and hook_preprocess_page

Last but certainly not least, this method only works if you have auto-generated template suggestions based on node type. For instance, consider my template_preprocess_html and template_preprocess_page functions (replace template with your theme name).

You could also put these in your .module file changing ‘template’ in the function name to your module name.

/**
 * Implements template_preprocess_html().
 */
function template_preprocess_html(&$vars) {
    $node = menu_get_object();
    if ($node && $node->nid) {
        $vars['theme_hook_suggestions'][] = 'html__' . $node->type;
    }
}

/**
 * Implements template_preprocess_page().
 */
function template_preprocess_page(&$variables) {
    if (isset($variables['node']->type)) {
        $nodetype = $variables['node']->type;
        $variables['theme_hook_suggestions'][] = 'page__' . $nodetype;
    }
}

I wrote these at different times in my Drupal career but they do the trick. A content type of “presidential_email” will now produce template suggestions for html–presidential-email.tpl.php and page–presidential-email.tpl.php.

With this in place, the module will now load templates in the module’s template folder when the presidential_email content type is being displayed. Worked well for my simple use case!

What do you think?