background image
HomeRecent PostsDrupalSearchTagsRSSContactAboutAccount
Eric.London's picture

The Fivestar module offers a great way to allow users to rate your content. Enabling this functionality for a node type was straight forward. My next goal was to show the fivestar widget in a view for each node row. Unfortunately, the row styling for my view was "Fields", so the fivestar widget would not appear. Apparently, the fivestar widget is only available for the teaser & full node display options.

No worries, you can always override the themable output of a view. Using the "Theme information" section on the view edit screen, I decided to create a new template file in my theme directory for "Row style output". For example:

views-view-fields--MY-VIEW-NAME.tpl.php

I then copied the contents of default view template into this file.

<?php
// $Id: views-view-fields.tpl.php,v 1.6 2008/09/24 22:48:21 merlinofchaos Exp $
/**
* @file views-view-fields.tpl.php
* Default simple view template to all the fields as a row.
*
* - $view: The view in use.
* - $fields: an array of $field objects. Each one contains:
*   - $field->content: The output of the field.
*   - $field->raw: The raw data for the field, if it exists. This is NOT output safe.
*   - $field->class: The safe class id to use.
*   - $field->handler: The Views field handler object controlling this field. Do not use
*     var_export to dump this object, as it can't handle the recursion.
*   - $field->inline: Whether or not the field should be inline.
*   - $field->inline_html: either div or span based on the above flag.
*   - $field->separator: an optional separator that may appear before a field.
* - $row: The raw result object from the query, with all data it fetched.
*
* @ingroup views_templates
*/
?>

<?php foreach ($fields as $id => $field): ?>
  <?php if (!empty($field->separator)): ?>
    <?php print $field->separator; ?>
  <?php endif; ?>

  <<?php print $field->inline_html;?> class="views-field-<?php print $field->class; ?>">
    <?php if ($field->label): ?>
      <label class="views-label-<?php print $field->class; ?>">
        <?php print $field->label; ?>:
      </label>
    <?php endif; ?>
      <?php
     
// $field->element_type is either SPAN or DIV depending upon whether or not
      // the field is a 'block' element type or 'inline' element type.
     
?>

      <<?php print $field->element_type; ?> class="field-content"><?php print $field->content; ?></<?php print $field->element_type; ?>>
  </<?php print $field->inline_html;?>>
<?php endforeach; ?>

By examining the hook_nodeapi() function of the Fivestar module, I decided to use the fivestar_widget_form() function to embed the widget in my view. This function accepts one argument, the $node object. Inside the first php tag in my new template file, I added the following code to load the node object:

<?php
$node
= node_load($row->nid);
?>

Last, I determined a good insertion point for the fivestar widget in this template file, and added the following code:

<?php
if (function_exists('fivestar_widget_form')) print fivestar_widget_form($node);
?>

If done correctly the Fivestar widget should now be embedded in the view for each node row.

I recently created a block view that I wanted to include only on pages of a certain node type. I decided to create a PHP function that returns true or false based based on the page URL and then call the function via the "Page specific visibility settings", on the block edit screen.

This function returns true or false based on the what type of node the page URL is. I added this function to my template.php file, but you could add it to a module if desired.

<?php
function _MYTHEME_MYBLOCK_visibility() {
 
// look up the system path from the page URL
 
$path = drupal_lookup_path('source', $_REQUEST['q']);

 
// check if the page is a node
 
if (substr($path,0,5)=='node/') {
   
// load node
   
$node = node_load(substr($path,5));
       
   
// check if node exists
   
if (!$node) return false;
       
   
// check node type
   
if ($node->type == 'MYNODETYPE') return true;
       
  } else {
    return
false;   
  }
}
?>

Then I added a PHP snippet in the "Page specific visibility settings" on the block edit screen:

<?php
if (function_exists('_MYTHEME_MYBLOCK_visibility')) return _MYTHEME_MYBLOCK_visibility();
return
false;
?>

Now, the block only shows on pages of "MYNODETYPE".

Eric.London's picture

Hardcoding something in your module or theme can be just as bad as hacking the core. If the Drupal admin interface allows you the change and configure something, your modules and themes must be scalable enough to account for these changes. This code snippet (example) shows you how you can lookup the CCK field labels, so you'll never have to hard code a label in your theme/module again.

<?php
// create a container for the field labels
$fieldLabels = array();

// load node
$node = node_load('MYCCKNODEID');

// loop through node properties
foreach ($node as $k => $v) {
 
// ensure this property is a field
 
if (substr($k,0,6) == 'field_') {
   
// use the CCK function to get the field data for this field
   
$fieldData = content_fields($k, $node->type);

   
// add the label to the array
   
$fieldLabels[$k] = $fieldData['widget']['label'];
  }
}

// for debug, you could now show all the fields with their labels:
echo "<pre>";
print_r($fieldLabels);
echo
"</pre>";
?>

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;

  }

}
?>

This problem comes up a lot in my Drupal module development: How do I generate the html for an individual CCK field? After much examination of the CCK, Views, and Node modules, I came up with this code snippet:

<?php
// load the node object
$node = node_load(MYNODEID);

// at this point the node object contains preprocessed data. build the content
$node = node_build_content($node);

// loop through content
foreach ($node->content as $k => $v) {
 
// specify a delimiter
 
$delimiter = "\n";

 
// ensure field items exist
 
if (is_array($v['field']['items'])) {
   
// create a container for the items html
   
$content = array();

   
// loop through items
   
foreach($v['field']['items'] as $i) {
     
// theme item
     
$content[] = theme($i['#theme'], $i);
    }

   
// roll up items html using delimiter
   
$content = implode($delimiter, $content);
  } else {
   
// NOTE: drupal_render includes divs, field labels, etc, which you may not want
   
$content = drupal_render($k);
  }

 
// NOTE: at this point, the data will be stored in $content, and you can now do whatever you want with it.
  // The date module gave me some headaches with this code snippet, BTW

}
?>

Syndicate content