background image
HomeRecent PostsDrupalSearchTagsRSSContactAboutAccount

Revise the structure, layout, and visibility of your node fields

Eric.London'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.

Groups

This approach also fails if you sort your fields by groups. It gets even messier when you have some fields grouped and some un-grouped...