background image
Eric's picture

When creating your theme, you may need absolute control over your node fields, and creating a node specific template file (CONTENTTYPE.tpl.php) does not give you enough flexibility. This code snippet defines a preprocess_node hook to modify the $content variable, so the field html has already been modified before it reaches your theme.

<?php
function MYMODULE_preprocess_node(&$variables) {
 
// test for your node type that you'd like to modify
 
if ($variables['type']=='MYNODETYPE') {
   
// prepare your node object so the fields can be rendered individually
   
$newNode = node_build_content(node_load($variables['nid']));

   
// define a variable to hold your rendered content
   
$newContent = "";

   
// example: define a list of fields to show in an item list
   
$itemListFields = array('field_itemlist_1','field_itemlist_2','field_itemlist_3');
   
$itemListFieldsData = array();

   
// loop through the node content
   
foreach ($newNode->content as $k => $v) {
     
// example: to prevent a field from being shown,
      // simply render the field and don't capture the output
     
if ($k == 'MYFIELDTOHIDE') {
       
drupal_render($v);
      } elseif (
in_array($k, $itemListFields)) {
       
// example: group some fields in an item list
       
$itemListFieldsData[] = drupal_render($v);
      } elseif (
$k == 'MYOTHERFIELD') {
       
// example: surround a field in a div
       
$newContent .= "<div id='MYHTMLID'>" . drupal_render($v) . "</div>";
      } else {
       
// render the remaining fields and capture the output
       
$newContent .= drupal_render($v);
      }

    }

   
// example: generate the output for the item list
   
if (count($itemListFieldsData)) $newContent .= theme('item_list', $itemListFieldsData);

   
// replace the content variable
   
if (strlen($newContent)) $variables['content'] = $newContent;

  }

}
?>

Thanks! Addition to avoid WSOD

Extremely helpful post, thanks very much for sharing!

I was getting the following error when I first tried your code:

PHP Fatal error: Unsupported operand types in /drupal6/includes/common.inc on line 2845

It seems the problem was caused by passing the #pre_render and #content_extra_fields elements of the $newNode->content array into drupal_render. Testing for those at the beginning of the foreach loop and NOT passing them to drupal_render got things working.

This led me to a slight variation on your approach: I specify only the specific fields that need to be rendered individually. After each field is rendered (inside the foreach loop), I unset its element from the $newNode->content array. Then all the remaining fields can be rendered by throwing the entire (now smaller) $newNode->content into drupal_render (after the foreach loop is done).

That way if new fields are added to the content type later, they'll at least show up in $node->content.