What are the best practices for rendering different types of node displays?

The following post is an answer I wrote to a question submitted to Tree House Agency in preparation for Do It With Drupal (New Orleans 2008). Tree House has kindly given me permission to post this material on my own website.

Q: One node, varied displays?

BH asks:

What are the best practices for rendering different types of node displays?

Short Answer

Three methods immediately come to mind. These are:

  1. Different TPL files for each type of node

  2. Switching template files by path

  3. Using CSS to change display by node type

Additional cases may include:

  1. Switching by taxonomy term

  2. Switching by role type

  3. Switching by user id


Details

1. Different TPL files for each type of node

Drupal already has an excellent built in method for rendering different types of node displays.

Grab a copy of node.tpl.php from Drupal’s modules/node/ directory.

clip_image002[8]

Put it into your site theme folder. Then rename it according to whatever node type you would like to customize. (node-nodetype.tpl.php )

Notes:

The node type should be the machine readable content type.

There are many places to find the machine readable name. One place is at: /admin/content/types

clip_image004[8]

To theme all nodes of the “page” content type we create a node tpl file titled, “node-page.tpl.php” and theme it.

2. Switching template files by path

In a recent project, we needed to switch template files by path. In this case we needed to do it at the page level. It may also be done at the node type level.

Here an excerpt of the code we used in template.php (with inline comments):

```php 1: <?php

2: 

3: /**

4: * Override or insert variables into the page templates.

5: *

6: * @param $vars

7: * An array of variables to pass to the theme template.

8: * @param $hook

9: * The name of the template being rendered (“page” in this case.)

10: */

11: function am_liquid_preprocess_page(&$vars, $hook) {

12:

13: //we chose to do our template switching by path

14: //in other cases, Drupal system path might be used

15: $path = drupal_get_path_alias($_GET[‘q’]);

16:

17: //we use this to add different css classes depending on the page path

18: $pannel_classes = array();

19: $pannel_classes[] = ‘panel’;

20:

21: //The template switching occurs here, in a common switch case statement

22: switch ($path) {

23: case ‘redeem-code’:

24: $pannel_classes[] = ‘ w440 dark code ‘;

25: $vars[‘template_files’] = array (‘page-redeem-code’);

26: break;

27: case ‘user’:

28: $pannel_classes[] = ‘ w427 login ‘;

29: $vars[‘template_files’] = array (‘page-user’);

30: break;

31: case ‘user/register’:

32: $pannel_classes[] = ‘ w427 register ‘;

33: $vars[‘template_files’] = array (‘page-register’);

34: break;

35:

36: case ‘contact’:

37: $pannel_classes[] = ‘ w427 contact ‘;

38: //in this case and the default case, the default page tpl is used

39: break;

40:

41: default:

42: $pannel_classes[] = ‘ w427 ‘;

43: break;

44: }

45: //combine all the css classes.

46: $vars[‘pannel_classes’] = implode(‘ ‘, $pannel_classes);

47:

48: }

49: 

50: ?> ```

Notes:

The different panel classes allowed us to render the page wrapper with different background colors and at different widths.

The template file names within the “template_files” array do not include the “.tpl.php” extensions. When you name your files within the directory, you must include the extensions. For example:

1: $vars[‘template_files’] = array (‘page-redeem-code’);

Corresponds to the file:

page-redeem-code.tpl.php

clip_image008[8]

3. Using CSS to change display by node type

In keeping with the concept of theming from the outside in, CSS should be the first place to consider controlling your various node displays.

Color, borders, background images, fonts, and element sizes should almost always be done within CSS.

Drupal follows a fairly consistent XHTML, CSS Class & ID, XPath structures. This makes style changes to node, via CSS, an excellent option.

Within the default node.tpl.php file, each node is wrapped within a unique div.

1: <div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clear-block">

2: …. node XHTML goes here

3: </div>

Add the following code:

1:

To the end of the div class declarations:

1: <div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clear-block <?php print $type; ?>">

2: …. node XHTML goes here

3: </div>

#

This will provide you with a CSS class for each node type. You can then theme every element within the div according to the node type class of the wrapper div.

Tip:

Any number of CSS classes may be added to and made available for your node.tpl.php files.

Take a look inside the Zen theme on Drupal.org.

@see http://drupal.org/project/zen .

In the template.php file, the zen_preprocess_page and zen_preprocess_node build page and node classes according to a number of factors, including path, node type, and user.

1: <?php

2: // $Id: template.php,v 1.44 2008/09/15 09:59:02 johnalbin Exp $

3: 

4: 

5: /**

6: * Override or insert variables into the page templates.

7: *

8: * @param $vars

9: * An array of variables to pass to the theme template.

10: * @param $hook

11: * The name of the template being rendered (“page” in this case.)

12: */

13: function zen_preprocess_page(&$vars, $hook) {

14: // Add an optional title to the end of the breadcrumb.

15: if (theme_get_setting(‘zen_breadcrumb_title’) && $vars[‘breadcrumb’]) {

16: $vars[‘breadcrumb’] = substr($vars[‘breadcrumb’], 0, -6) . $vars[‘title’] . ‘</div>’;

17: }

18: 

19: // Add conditional stylesheets.

20: if (!module_exists(‘conditional_styles’)) {

21: $vars[‘styles’] .= $vars[‘conditional_styles’] = variable_get(‘conditional_styles_’ . $GLOBALS[‘theme’], ‘’);

22: }

23: 

24: // Classes for body element. Allows advanced theming based on context

25: // (home page, node of certain type, etc.)

26: $body_classes = array($vars[‘body_classes’]);

27: if (!$vars[‘is_front’]) {

28: // Add unique classes for each page and website section

29: $path = drupal_get_path_alias($_GET[‘q’]);

30: list($section, ) = explode(‘/’, $path, 2);

31: $body_classes[] = zen_id_safe(‘page-‘ . $path);

32: $body_classes[] = zen_id_safe(‘section-‘ . $section);

33: if (arg(0) == ‘node’) {

34: if (arg(1) == ‘add’) {

35: if ($section == ‘node’) {

36: array_pop($body_classes); // Remove ‘section-node’

37: }

38: $body_classes[] = ‘section-node-add’; // Add ‘section-node-add’

39: }

40: elseif (is_numeric(arg(1)) && (arg(2) == ‘edit’   arg(2) == ‘delete’)) {

41: if ($section == ‘node’) {

42: array_pop($body_classes); // Remove ‘section-node’

43: }

44: $body_classes[] = ‘section-node-‘ . arg(2); // Add ‘section-node-edit’ or ‘section-node-delete’

45: }

46: }

47: }

48: if (theme_get_setting(‘zen_wireframes’)) {

49: $body_classes[] = ‘with-wireframes’; // Optionally add the wireframes style.

50: }

51: $vars[‘body_classes’] = implode(‘ ‘, $body_classes); // Concatenate with spaces

52: }

53: 

54: /**

55: * Override or insert variables into the node templates.

56: *

57: * @param $vars

58: * An array of variables to pass to the theme template.

59: * @param $hook

60: * The name of the template being rendered (“node” in this case.)

61: */

62: function zen_preprocess_node(&$vars, $hook) {

63: // Special classes for nodes

64: $classes = array(‘node’);

65: if ($vars[‘sticky’]) {

66: $classes[] = ‘sticky’;

67: }

68: if (!$vars[‘status’]) {

69: $classes[] = ‘node-unpublished’;

70: $vars[‘unpublished’] = TRUE;

71: }

72: else {

73: $vars[‘unpublished’] = FALSE;

74: }

75: if ($vars[‘uid’] && $vars[‘uid’] == $GLOBALS[‘user’]->uid) {

76: $classes[] = ‘node-mine’; // Node is authored by current user.

77: }

78: if ($vars[‘teaser’]) {

79: $classes[] = ‘node-teaser’; // Node is displayed as teaser.

80: }

81: // Class for node type: “node-type-page”, “node-type-story”, “node-type-my-custom-type”, etc.

82: $classes[] = ‘node-type-‘ . $vars[‘type’];

83: $vars[‘classes’] = implode(‘ ‘, $classes); // Concatenate with spaces

84: }

** General Tips

  1. Read the comments at the top of the node.tpl.php for a list of variables available.

1: <?php

2: // $Id: node.tpl.php,v 1.4 2008/01/25 21:21:44 goba Exp $

3: 

4: /**

5: * @file node.tpl.php

6: *

7: * Theme implementation to display a node.

8: *

9: * Available variables:

10: * - $title: the (sanitized) title of the node.

11: * - $content: Node body or teaser depending on $teaser flag.

12: * - $picture: The authors picture of the node output from

13: * theme_user_picture().

14: * - $date: Formatted creation date (use $created to reformat with

15: * format_date()).

16: * - $links: Themed links like “Read more”, “Add new comment”, etc. output

17: * from theme_links().

18: * - $name: Themed username of node author output from theme_user().

19: * - $node_url: Direct url of the current node.

20: * - $terms: the themed list of taxonomy term links output from theme_links().

21: * - $submitted: themed submission information output from

22: * theme_node_submitted().

23: *

24: * Other variables:

25: * - $node: Full node object. Contains data that may not be safe.

26: * - $type: Node type, i.e. story, page, blog, etc.

27: * - $comment_count: Number of comments attached to the node.

28: * - $uid: User ID of the node author.

29: * - $created: Time the node was published formatted in Unix timestamp.

30: * - $zebra: Outputs either “even” or “odd”. Useful for zebra striping in

31: * teaser listings.

32: * - $id: Position of the node. Increments each time it’s output.

33: *

34: * Node status variables:

35: * - $teaser: Flag for the teaser state.

36: * - $page: Flag for the full page state.

37: * - $promote: Flag for front page promotion state.

38: * - $sticky: Flags for sticky post setting.

39: * - $status: Flag for published status.

40: * - $comment: State of comment settings for the node.

41: * - $readmore: Flags true if the teaser content of the node cannot hold the

42: * main body content.

43: * - $is_front: Flags true when presented in the front page.

44: * - $logged_in: Flags true when the current user is a logged-in member.

45: * - $is_admin: Flags true when the current user is an administrator.

46: *

47: * @see template_preprocess()

48: * @see template_preprocess_node()

49: */

50: ?>

51: <div id="node-<?php print $node->nid; ?>" class="node<?php if ($sticky) { print ' sticky'; } ?><?php if (!$status) { print ' node-unpublished'; } ?> clear-block">

52: 

53:

54: 

55:

56: <h2></h2>

57:

58: 

59: <div class="meta">

60:

61:

62:

63: 

64:

65: <div class="terms terms-inline"></div>

66:

67: </div>

68: 

69: <div class="content">

70:

71: </div>

72: 

73:

74: </div>

  1. You can also place this code within your node tpl to examine the variables:

1: <pre>

2: 

3:

4: 

5: </pre>

  1. Modifying node variables should be done within the template_preprocess_node placed in your template.php file. @ see http://api.drupal.org/api/function/template_preprocess_node/6

1: <?php

2: function template_preprocess_node(&$variables) {

3: $node = $variables[‘node’];

4: if (module_exists(‘taxonomy’)) {

5: $variables[‘taxonomy’] = taxonomy_link(‘taxonomy terms’, $node);

6: }

7: else {

8: $variables[‘taxonomy’] = array();

9: }

10: 

11: if ($variables[‘teaser’] && $node->teaser) {

12: $variables[‘content’] = $node->teaser;

13: }

14: elseif (isset($node->body)) {

15: $variables[‘content’] = $node->body;

16: }

17: else {

18: $variables[‘content’] = ‘’;

19: }

20: 

21: $variables[‘date’] = format_date($node->created);

22: $variables[‘links’] = !empty($node->links) ? theme(‘links’, $node->links, array(‘class’ => ‘links inline’)) : ‘’;

23: $variables[‘name’] = theme(‘username’, $node);

24: $variables[‘node_url’] = url(‘node/’. $node->nid);

25: $variables[‘terms’] = theme(‘links’, $variables[‘taxonomy’], array(‘class’ => ‘links inline’));

26: $variables[‘title’] = check_plain($node->title);

27: 

28: // Flatten the node object’s member fields.

29: $variables = array_merge((array)$node, $variables);

30: 

31: // Display info only on certain node types.

32: if (theme_get_setting(‘toggle_node_info_’. $node->type)) {

33: $variables[‘submitted’] = theme(‘node_submitted’, $node);

34: $variables[‘picture’] = theme_get_setting(‘toggle_node_user_picture’) ? theme(‘user_picture’, $node) : ‘’;

35: }

36: else {

37: $variables[‘submitted’] = ‘’;

38: $variables[‘picture’] = ‘’;

39: }

40: // Clean up name so there are no underscores.

41: $variables[‘template_files’][] = ‘node-‘. $node->type;

42: }

43: ?>

  1. Use the devel module and theme developer module when theming

  2. Use firefox firebug

  3. Go to /admin/build/modules every time you change a tpl file. This will rebuild your theme registry.

Share or Comment via Twitter