I've had a lot of people asking about the directory I'm working on here: http://couleeregiononline.com/directory . I plan on doing a tutorial but first I need to finish version 3 of user profiles along with all the other stuff I have to do. So it's going to be a while. In the mean time, here's a few pointers to help those who can't wait:
Hopefully that will help a bit until I can get the tutorial written.
Michelle
Oct 31, 2007 - This tutorial works but I've since found a more elegant way of doing it, so I recommend Rate and Review 2.
Purpose: This tutorial will show you one way of allowing users to rate and review a node all in the same form. This isn't the only way of doing it. If you are looking for a more drop in solution, see http://drupal.org/project/userreview . I went this route because I wanted to use fivestar and I already have CCK and views installed so all I needed was prepopulate.
Skill level: This tutorial is not aimed at beginners. You need to be comfortable with creating content types and theming them.
Support: Please use the support forum if you have questions and I will try to answer if I am able.
Modules needed: CCK, Views, Fivestar (as well as dependencies for those modules)
Note: In order for this to work, you need to make the following change to fivestar_field.inc:
Change
$items[$delta]['target'] = drupal eval($item['target']);
to
$items[$delta]['target'] = eval($item['target']);
The reason for this is that the $node object is not in scope in the evaluated PHP when using drupal_eval but it is with just eval. Hacking a module is uncool, so suggestions to get around that fix are welcome.
If you have a site specific module, add this form_alter code:
<?php
function YOURMODULENAME_form_alter($form_id, &$form) {
switch ($form_id) {
// Only do this for the review type's form
case ('review_node_form'):
//If we are adding a review, we need to grab the parent node ID from the URL
if (arg(1) == "add") {
// Get the parent node's id from the url
$pnid = $_GET['pnid'];
// Set the parentnid field's value
$form['field_parentnid'][0]['value']['#value'] = $pnid;
} else {
// Otherwise, grab the existing parent node ID to redirect to
$pnid = $form['field_parentnid'][0]['value']['#default_value'];
}
// Hide the field
$form['field_parentnid'][0]['value']['#access'] = FALSE;
// On submission, redirect to the parent node
$form['#redirect'] = "node/$pnid";
// This is in case we add more forms later
break;
}
}
?>If you don't already have one and don't know how to make a module, just use the one in the zip.
<?php
$current_rating = votingapi_get_voting_result('node', $nid, 'percent', 'vote', 'average');
$numstars = 5; // Change this to how many stars you want
print theme('fivestar_static', $current_rating->value, $numstars);
?><?php
print l("Add a review","node/add/review",NULL,"pnid=" . $node->nid,NULL,NULL,TRUE);
?><?php
// Retrieve the view
$view = views_get_view('reviews_of_node');
// Build the view into the $reviews variable with paging on and nodes per page set to 20
$reviews = views_build_view('embed', $view, array(strval($node->nid)), true, 20);
// Get the number of reviews
global $pager_total_items;
$numreviews = $pager_total_items[0];
// Print the reviews
print "Number of reviews: $numreviews";
print $reviews
?>Enjoy!
| Attachment | Size |
|---|---|
| rateandreview.zip | 817 bytes |
Aug 26, 2008: A recent user of this tutorial wrote some updates here.
Note: This tutorial was written before fivestar gained the ability to use comments for rating. It's still useful if you want your reviews to be nodes.
This is a revised version of Rate and review in one step using the node relativity module. (Thanks to greggles for pointing this module out.)
Purpose: This tutorial will show you one way of allowing users to rate and review a node all in the same form. This isn't the only way of doing it. If you are looking for a more drop in solution, see http://drupal.org/project/userreview .
Skill level: This tutorial is not aimed at beginners. You need to be comfortable with creating content types and theming them.
Support: Please use the support forum if you have questions and I will try to answer if I am able.
Modules needed: CCK, Views, Fivestar, and Node Relativity (as well as dependencies for those modules)
Fivestar uses drupal_eval() to determine the target node for the voting widget. Unfortunately, the $node object is not in scope in drupal_eval() and we need to pull the target from the $node object. The fix is to make the following change to fivestar_field.inc:
Change
$items[$delta]['target'] = drupal eval($item['target']);
to
$items[$delta]['target'] = eval($item['target']);
Hacking a module is uncool, so suggestions to get around that fix are welcome.
<?php
$current_rating = votingapi_get_voting_result('node', $nid, 'percent', 'vote', 'average');
$numstars = 5; // Change this to how many stars you want
print theme('fivestar_static', $current_rating->value, $numstars);
?><?php
print l("node/add/review/parent/$node->nid",NULL,NULL,NULL,FALSE,TRUE);
?><?php
// Retrieve the view
$view = views_get_view('reviews_of_node');
// Build the view into the $reviews variable with paging on and nodes per page set to 20
$reviews = views_build_view('embed', $view, array(strval($node->nid)), true, 20);
// Get the number of reviews
global $pager_total_items;
$numreviews = $pager_total_items[0];
// Print the reviews
print "Number of reviews: $numreviews";
print $reviews
?>When submitting the review, it goes to the review view page. It makes more sense to go back to the node being reviewed. If you have already have a site specific module, add this form_alter code:
<?php
function YOURMODULENAME_form_alter($form_id, &$form) {
switch ($form_id) {
// Only do this for the review type's form
case ('review_node_form'):
// On submission, redirect to the parent node
$pnid = arg(4);
$form['#redirect'] = "node/$pnid";
// This is in case we add more forms later
break;
}
}
?>Enjoy!
| Attachment | Size |
|---|---|
| rateandreview.zip | 745 bytes |
| rate-review-screen-1.jpg | 63.17 KB |
| rate-review-screen-2.jpg | 75.38 KB |
| rate-review-screen-3.jpg | 63.21 KB |
It's likely to be some months before I get to writing this tutorial so I decided to throw up some tidbits. These are offered as is. Please don't ask for support. I'm already behind in supporting forums & profiles and just can't add to that. Don't expect to be able to just drop this in and have it work but, if you have some idea of what you're doing, this may be helpful.
For the top level directory page, I have a vocabulary, Directory Categories, with two levels of terms. The top level is a broad category and the second level narrows it down. I used the panels_by_term view style found when you have both the views bonus pack and the panels module. This is with panels 1 as this was done before panels 2 was around. This is the export of the view, called directory_browse:
<?php
$view = new stdClass();
$view->name = 'directory_browse';
$view->description = 'Browsable directory';
$view->access = array (
);
$view->view_args_php = '// Always use 8 as the augment since that\'s the directory\'s taxonomy
if (!$args[0]) {
$args[0] = 8;
}';
$view->page = TRUE;
$view->page_title = 'Browse Directory';
$view->page_header = '';
$view->page_header_format = '1';
$view->page_footer = '';
$view->page_footer_format = '1';
$view->page_empty = '';
$view->page_empty_format = '1';
$view->page_type = 'panels_threecol_term';
$view->url = 'directory/browse';
$view->use_pager = FALSE;
$view->nodes_per_page = '0';
$view->menu = TRUE;
$view->menu_title = 'Browse directory';
$view->menu_tab = TRUE;
$view->menu_tab_weight = '0';
$view->menu_tab_default = TRUE;
$view->menu_tab_default_parent = NULL;
$view->menu_tab_default_parent_type = 'normal';
$view->menu_parent_tab_weight = '1';
$view->menu_parent_title = 'Directory';
$view->sort = array (
array (
'tablename' => 'node',
'field' => 'sticky',
'sortorder' => 'DESC',
'options' => '',
),
array (
'tablename' => 'node',
'field' => 'title',
'sortorder' => 'ASC',
'options' => '',
),
);
$view->argument = array (
array (
'type' => 'vocid',
'argdefault' => '1',
'title' => '%1',
'options' => '',
'wildcard' => '',
'wildcard_substitution' => '',
),
array (
'type' => 'taxid',
'argdefault' => '6',
'title' => '%1 - %2',
'options' => '9',
'wildcard' => '',
'wildcard_substitution' => '',
),
);
$view->field = array (
array (
'tablename' => 'node',
'field' => 'title',
'label' => '',
'handler' => 'views_handler_field_nodelink',
'options' => 'link',
),
);
$view->filter = array (
);
$view->exposed_filter = array (
);
$view->requires = array(node);
$views[$view->name] = $view;
?>Note the argument code is hardcoded with my vocab ID.
To make the page look how it does takes some heavy theming. You can put this in your template.php:
<?php
// BEGIN Override the browse directory view (panels by term) theming
function phptemplate_views_bonus_panels_byterm_summary_directory_browse($view) {
drupal_add_css(drupal_get_path('module', 'views_bonus') .'/views_bonus.css');
// argument 0 must be a vocabulary ID
$vid = $view->args[0];
// Get the taxonomy tree from the argument to the view
$tree = taxonomy_get_tree($vid);
// group terms with their parent
foreach ($tree as $term) {
$cnt = taxonomy_term_count_nodes($term->tid);
if ($term->depth == 0) {
// Top level category. Add the "all" to the URL to show all subterms when the link is clicked
$txt = array($prefix. l($term->name . " ($cnt)", "taxonomy/term/$term->tid/all"));
$parent_tid = $term->tid;
$groups[$parent_tid]['header'] = $txt;
} else {
// This bit is a pseudo tagadelic for the terms. It takes the number of nodes for a term and divides
// it by 5 and then uses just the whole number part. If a term has at least one node, it gets a 1. If
// a term has more than 25 nodes, it stays at 5. These numbers are then used to add an extra class of
// "sizedterm-N" where N is 0-5 that can be styled in CSS to make the terms look different based on
// the number of nodes in the term.
$sizeclass = floor($cnt/5);
if ($sizeclass == 0 && $cnt > 0) {
$sizeclass = 1;
}
if ($sizeclass > 5) {
$sizeclass = 5;
}
$txt = array('<span class="sizedterm-' . $sizeclass . '">' . l($term->name . " ($cnt)", "taxonomy/term/$term->tid") . '</span>');
$groups[$parent_tid]['rows'][] = $txt;
}
}
// Spread the across 2 columns
$content = array();
$i=0;
foreach ($groups as $group) {
if ($i % 2) {
$section = 'left';
} else {
$section = 'right';
}
// Create a comma separated list of subterms
$subterms = array();
foreach ($group['rows'] as $subterm) {
array_push($subterms, $subterm[0]);
}
$subterms = implode(", ", $subterms);
$content[$section] .= '<div style="display:block;"><h3>' . $group['header'][0] . "</h3>" . $subterms . "</div>";
$i++;
}
return panels_print_layout('twocol', $content);
}
// END Override the browse directory view (panels by term) theming
?>I think this is all the CSS for it but there may be more spread out in my .css file:
.view-summary-directory-browse h3 {
background: #356AA0 url(images/bluegradient-medium.jpg) repeat-x;
color: White;
padding : .25em;
margin-bottom: .25em;
}
.view-summary-directory-browse h3 a {
color: White;
}
.sizedterm-0 {
font-size: .9em;
}
.sizedterm-1 {
font-weight:bold;
font-size: 1.1em;
}
.sizedterm-2 {
font-weight:bold;
font-size: 1.2em;
}
.sizedterm-3 {
font-weight:bold;
font-size: 1.3em;
}
.sizedterm-4 {
font-weight:bold;
font-size: 1.4em;
}
.sizedterm-5 {
font-weight:bold;
font-size: 1.5em;
}
I'll try to throw more tidbits out as time permits. Hopefully that will help someone.
Michelle