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;
}
}
?>





















Comments
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 2845It seems the problem was caused by passing the
#pre_renderand#content_extra_fieldselements of the$newNode->contentarray intodrupal_render. Testing for those at the beginning of theforeachloop and NOT passing them todrupal_rendergot 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
foreachloop), I unset its element from the$newNode->contentarray. Then all the remaining fields can be rendered by throwing the entire (now smaller)$newNode->contentinto drupal_render (after theforeachloop is done).That way if new fields are added to the content type later, they'll at least show up in
$node->content.