Drupal theming: User configurable node templates

Oct082015

A reoccurring challenge in developing a Drupal site is allowing users to select a template for a node. Maybe it’s choosing between ‘news’ or ‘events’ styling or different ways to present a blog post, but users like to feel empowered to control the layout while using a single node type.

In this short post, I’ll introduce a fairly simple solution that I’ve used on several sites.

I use a taxonomy and add a field referencing it to the content type. Now that we have a field, we can customize to our heart’s content. Because I’m often adding this to multiple content types, I use a pattern where the taxonomy is called NODETYPE_template and the field is called field_NODETYPE_template.

In a perfect world, we’d use identical html generated from a single tpl and add a class to select custom css for each theme. That can work for custom colours, but less so for more radical layout differences or changes to image styles. Basically, if there’s custom processing, we’ll want multiple template files.

My solution has three parts:

  • Custom template suggestions in template.php,
  • Implement hook_node_view in a module or the theme to hold preprocessing commands; and
  • The final magic: tpl files of the style node–nodetype–template.tpl.php

This approach makes it easy to identify the template in charge of a specific rendering.

Let’s get into the code:

This function lives in template.php and implements hook_preprocess_node

function bv02_preprocess_node(&$vars) {
  // look for a field of the form "field_NODETYPE_template"
  $field_name = 'field_'.$vars['type'].'_template';
  if (!empty($vars['node']->{$field_name}[LANGUAGE_NONE][0]['tid'])) {
    // Load the taxonomy term and generate a simple version of the title
    $tid = $vars['node']->{$field_name}[LANGUAGE_NONE][0]['tid'];
    $template = taxonomy_term_load($tid);
    $simple_term_css = strtolower(drupal_clean_css_identifier($template->name));
    $simple_term = strtr($simple_term_css, '-', '_');

    // node--NODETYPE--VIEWMODE--TEMPLATENAME.tpl.php
    $vars['theme_hook_suggestions'][] 
      = 'node__' . $page_type . '__' . $vars['view_mode'] . '__' . $simple_term;
    // node--NODETYPE--VIEWMODE.tpl.php
    $vars['theme_hook_suggestions'][] 
      = 'node__' . $page_type . '__' . $vars['view_mode'];
    // node--NODETYPE--TEMPLATENAME.tpl.php
    $vars['theme_hook_suggestions'][] 
      = 'node__' . $page_type . '__' . $simple_term;

    // Add a class for the template
    $vars['classes_array'][] = 'template-'.$simple_term_css;
  }
}

This function lives in a module called bv02_pages which includes helpers and preprocessing for pages on the site.

function bv02_pages_node_view($node, $view_mode = 'full', $langcode = NULL) {
  // Only run this on regions and branches
  if (!in_array($node->type, array('article', 'blog'))) {
    return;
  }
  
  $content = &$node->content;
  
  hide($content['body']);
  
  $content['more_info'] = array(
    '#theme' => 'link',
    '#text' => t('More Info'),
    '#path' => $node_url = url('node/'.$node->nid),
    '#options' => array(
      'attributes' => array(
        'class' => array('more-button'),
      ),
      'html' => TRUE,
     ),
  );
}

I’m not including a tpl example because it’ll be specific to the task but I’ve used it for configuring the type of thumbnail used, the type of a post so that certain fields can be included or not, and more.

Good luck!

Skip to sharing