Community Documentation

Different node templates depending on URL aliases

Last updated August 26, 2009. Created by Crell on February 9, 2007.
Edited by bekasu, add1sun, Borek. Log in to edit this page.

Drupal 5 includes useful mechanism for providing different templates for different pages, blocks, nodes etc. For example, you can style nodes of type 'blog' simply by adding node-blog.tpl.php which will be preferred over standard node.tpl.php template. For page templates, there is even more flexibility, so you can for example create specific templates for specific nodes, see Using different page templates depending on the current path.

The list of possible "template suggestions" is also editable via the _phptemplate_variables() function. For instance, the code snippet below will create additional "suggestions" based on the the URL alias. That's much more powerful than the default method of using the internal Drupal path.

<?php
function _phptemplate_variables($hook, $vars = array()) {
  switch (
$hook) {
    case
'page':
   
     
// Add node template suggestions based on the aliased path.
      // For instance, if the current page has an alias of about/history/early,
      // we'll have templates of:
      // node_about_history_early.tpl.php
      // node_about_history.tpl.php
      // node_about.tpl.php
      // Whichever is found first is the one that will be used.
     
if (module_exists('path')) {
       
$alias = drupal_get_path_alias($_GET['q']);
        if (
$alias != $_GET['q']) {
         
$suggestions = array();
         
$template_filename = 'node';
          foreach (
explode('/', $alias) as $path_part) {
           
$template_filename = $template_filename . '_' . $path_part;
           
$suggestions[] = $template_filename;
          }
        }
       
$vars['template_files'] = $suggestions;
      }
      break;
  }
 
  return
$vars;
}
?>

Comments

As I understand it, the

As I understand it, the above code allows you to theme a node as a separate page. However, sometimes you want to be able to *just* theme the node itself, and not have to render a full page tpl.php like page.tpl.php.

Using the PHP code below, Drupal will look for these template files, split by page or no page view. This gives more fine grained control over your node tpl.php files.

Page view:

1) node-[nid]-page.tpl.php
   Node by itself on a page, specific NID
2) node-[type]-page.tpl.php
   Node by itself on a page, specific type
3) node-page.tpl.php
  Node by itself on a page, default

Listing/Teaser view:

4) node-[nid].tpl.php
   Node in list/teaser, specific NID
5) node-[type].tpl.php
   Node in list/teaser, specific type
6) node.tpl.php
   Node in list/teaser, default.

*UPDATE* Earl Miles has shown this can be done much simpler than what I had previously. Revised code:

<?php
function _phptemplate_variables($hook, $vars = array()) {
  switch (
$hook) {
    case
'node':
     
// Here is the way to switch to a different node-<something> template based on node properties.
     
if ($vars['page']) {
       
// This is LIFO (Last In First Out) so put them in reverse order, i.e
        // most important last.
       
$vars['template_files'] = array('node-page', 'node-'. $vars['node']->type .'-page', 'node-'. $vars['node']->nid .'-page');
      }
      else {
       
$vars['template_files'] = array('node-'. $vars['node']->nid);
      }
      break;
  }

  return
$vars;
}
?>

even more suggestions for node templates

I need to be able to:

- theme nodes by type
- theme nodes by original path
- theme nodes by type and original path
- theme nodes by URL alias
- theme nodes by type and URL alias

This order also represents the weight (LIFO).

This is my version of the code:

<?php
function _phptemplate_variables($hook, $vars = array()) {
  if (
$hook == 'node')
  {
   
// Additional node templates based on original path, path alias and type.
    // More specific paths have more weight. Path aliases have more weight
    // than original paths. Suggestions with node type have more weight than without.

   
$alias = $_GET['q'];
   
$suggestions = array();
   
$name_prefix = 'node';
   
$node_type = !empty($vars['node']->type) ? '-' . $vars['node']->type : '';
   
$add_path = '';

   
// generating additional node template names, based on original path
   
foreach (explode('/', $alias) as $path_part) {
     
$add_path .= !empty($path_part) ? '-' . $path_part : '';
     
$suggestions[] = $name_prefix . $add_path;
     
$suggestions[] = $name_prefix . $node_type . $add_path;
    }

   
// adding suggestions
   
$vars['template_files'] = $suggestions;

   
// using aliases?
   
if (module_exists('path')) {
     
$alias = drupal_get_path_alias($_GET['q']);

      if (
$alias != $_GET['q']) {
       
$suggestions = array();
       
$add_path = '';
       
// generating additional node  template names, based on alias path
       
foreach (explode('/', $alias) as $path_part) {
         
$add_path .= !empty($path_part) ? '-' . $path_part : '';
         
$suggestions[] = $name_prefix . $add_path;
         
$suggestions[] = $name_prefix . $node_type . $add_path;
        }
      }
     
// adding suggestions
     
$vars['template_files'] = array_merge($vars['template_files'], $suggestions);
    }
  }
  return
$vars;
}
?>

This way I am able to use the following node template name scheme:

node-[type].tpl.php (from drupal)

Adding with this script:

node-[path].tpl.php
node-[type]-[path].tpl.php
node-[url].tpl.php
node-[type]-[url].tpl.php

I am using underline (_) in node type names, never dashes (-) and I use different names for paths and node types. Otherwise it would be too confusing.

This way I have more granularity. I can make subthemes for node types and also decide to override this for other type-path/alias combinations.

Insert a

<?php
 
echo '<pre>';
 
print_r ($vars['template_files']);
  echo
'</pre>';
?>

before the final return statement to view the suggestions ("debug mode").

It's first confusing to get a 'node-node' suggestion. Logical but an uneccesary override of node.tpl.php, maybe this should be filtered out...

schnizZzla
____________
BerlinerStrassen.com
- Support Your Local Heroes!

Less suggestions - more control :)

Don't parse $_GET['q']! When You're calling node_view() from node-[path].tpl.php to insert another node You can get an infinite loop (the same template is used for path anchestors).

My example is for custom subtheme of Zen theme (see more...), but You can use it as listed above.
The difference in my case is a function name, $hook is already checked, all variables are preloaded.

My "name schemes":

  • node-[type].tpl.php - it's already implemented by phptemplate engine;
  • node-[nid].tpl.php - a template for single node;
  • node-[path].tpl.php - for node with [path] alias and nodes with aliases below it ([path]/*);
  • node-[path]-nofollow.tpl.php - for single node with [path] alias, anchestors are not included.

<?php
function zencustomsubtheme_preprocess_node(&$vars) {
 
// template name for current node id
 
$suggestions = array('node-'. $vars['nid']);
 
// additional node template names based on path alias
 
if (module_exists('path')) {
   
// we already can have a path alias
   
if (isset($vars['path'])) {
     
$alias = $vars['path'];
    }
    else {
     
// otherwise do standard check
     
$alias = drupal_get_path_alias('node/'. $vars['nid']);
    }
    if (
$alias != 'node/'. $vars['nid']) {
     
$add_path = '';
      foreach (
explode('/', $alias) as $path_part) {
       
$add_path .= !empty($path_part) ? $path_part : '';
       
$suggestions[] = 'node-'. $add_path;
      }
     
// adding the last one (higher priority) for this path only
      // node-some-long-path-nofollow.tpl.php (not for anchestors)
     
$suggestions[] = end($suggestions) .'-nofollow';
    }
  }
 
$vars['template_files'] = isset($vars['template_files']) ? array_merge($vars['template_files'], $suggestions) : $suggestions;
}
?>

6.x

Is anyone getting this to work on d6?
Well got this to suit my needs, I am so not a programmer but this modification works for me on d6.x. Anyone who want to improve it please do :)

<?php
function phptemplate_preprocess_page(&$vars) {
 
// template name for current node id
  //what do we need this for the standard one comes up anyways?
 
$suggestions = array('node-'. $vars['nid']);
 
// additional node template names based on path alias
 
if (module_exists('path')) {
   
// we already can have a path alias
   
if (isset($vars['node']->path)) {
     
$alias = ($vars['node']->path);
    }
    else {
     
// otherwise do standard check
     
$alias = drupal_get_path_alias('node/'. $vars['nid']);
    }
    if (
$alias != 'node/'. $vars['nid']) {
     
$add_path = '';
      foreach (
explode('/', $alias) as $path_part) {
       
$add_path .= !empty($path_part) ? $path_part : '';
       
//adding a pure path template name
       
$suggestions[] = $add_path;
      }
     
//what do we need this for?
      // adding the last one (higher priority) for this path only
      // node-some-long-path-nofollow.tpl.php (not for anchestors)
     
$suggestions[] = end($suggestions) .'-nofollow';
    }
  }
 
$vars['template_files'] = isset($vars['template_files']) ? array_merge($vars['template_files'], $suggestions) : $suggestions;
}
?>

For Drupal 6.x

<?php
function template_preprocess_node(&$vars) {

   
// Here is the way to switch to a different node-<something> template based on node properties.
   
if ($vars['page']) {
       
$vars['template_files'] = array('node-page', 'node-'. $vars['node']->type .'-page', 'node-'. $vars['node']->nid .'-page');
    } else {
       
$vars['template_files'] = array('node-'. $vars['node']->type, 'node-'. $vars['node']->nid);
    }

}
?>

What would I use if I just

What would I use if I just wanted to display one line of code in the page.tpl.php page? For example I just want to insert a div with special ID when the url path contains a specific word. (yepp) www.domain.com/yepp or any www.domain.com/yepp/page1

Thanks

Override Page.tpl

Hi,

please try to override the page.tpl.php using page-node.tpl.php/page-node-nodetype.tpl.php/page-node-edit.tpl.php but remember each of them will override the actual page.tpl.php so need to make a condition according to url alias
also take all the code snippets from page.tpl.php in to page-node.tpl.php then add your extra div element as you have mentioned!

in template.php of active theme

use function activethemename_preprocess_node(&$vars)

if(arg(1)=='page1' && arg(1)!=''){ //condition would be something like this
$vars['template_files'][] = "page-node";
}else $vars['template_files'][] = "page";

Issues with above php and path

Hello all! I used the above php code

<?php
function zencustomsubtheme_preprocess_node(&$vars) {
 
// template name for current node id
 
$suggestions = array('node-'. $vars['nid']);
 
// additional node template names based on path alias
 
if (module_exists('path')) {
   
// we already can have a path alias
   
if (isset($vars['path'])) {
     
$alias = $vars['path'];
    }
    else {
     
// otherwise do standard check
     
$alias = drupal_get_path_alias('node/'. $vars['nid']);
    }
    if (
$alias != 'node/'. $vars['nid']) {
     
$add_path = '';
      foreach (
explode('/', $alias) as $path_part) {
       
$add_path .= !empty($path_part) ? $path_part : '';
       
$suggestions[] = 'node-'. $add_path;
      }
     
// adding the last one (higher priority) for this path only
      // node-some-long-path-nofollow.tpl.php (not for anchestors)
     
$suggestions[] = end($suggestions) .'-nofollow';
    }
  }
 
$vars['template_files'] = isset($vars['template_files']) ? array_merge($vars['template_files'], $suggestions) : $suggestions;
}
?>

with the hope that I am able to use different theme pages for various nodes.

Here is what I did:

  1. Insert the code in page.tpl.php file, which I believe is my template.php file for my theme.
  2. Changed my template files that I want to override. For example, for the node/2 page I would like to use the template file node-2-page.tpl.php

When I load to my homepage, my page-front.tpl loads correctly, but when I click on node/2,node/3, node/4, nothing appears to load. I would like some guidance as to where I am falling short.

Fixed above question

Shortly after my post, I fixed my error my chance!

I have the files named node-2-page.tpl.php, etc.

I changed the file names to page-node-2.tpl.php. This fixed my solution and all of the pages can be dynamic!

Thanks for the code snippets above!

node template depend on taxonomy term

is this possible to have suggestions for node.tpl based on taxonomy term ? so when a custom content type is created and taggued whith a certain term, its more easy to apply a node.tpl to this content ...if someone can do that because i'm not a dev...only designer

thanks

Dev Server Ubuntu 12.04 LAMP PHP 5.3.10 Virtual Box
7 websites powered by drupal 6 - Hosted by OVH and Always Data

nobody click here