Creating a review system with multi-axis average rating
Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites
This handbook is about how to setup fivestar 7.x-2.0 to use for a review system.
The code examples were initially posted in the issue queue of computed_field, but this should be a more appropriate place.
The code below contains an implementation of fivestar that is used as a review system. It contains some code for your custom module. Replace 'MYMODULE' with the name of your module.
Use case:
Your users rate multiple things (axis) and you also want to show an average rating or other calculated/derived ratings.
This is very typical for a customer-review, where things like 'speed', 'quality' and such are rated and we would like to show an average rating per review.
Summary:
Create an extra fivestar-axis named 'average' on your review, hide it for users and calculate/save it upon saving the review.
Long example with a review content-type.
Working example:
Create 4 voting tags/axis on /admin/config/content/fivestar.
- vote_axis_one
- vote_axis_two
- vote_axis_three
- votes_average
Create a "review" content-type with 4 voting fields:
to vote on:
- field_review_vote_axis_one
- field_review_vote_axis_two
- field_review_vote_axis_three
calculated:
- field_review_votes_average.
set your voting targets as you normally do (with a node_reference field).
We hide the average field and calculate it when the review is saved or updated.
/**
* Implements hook_form_alter().
*
* Hide average fivestar field from review edit/create form.
*/
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'review_node_form') {
// Hide average field, this field is calculated upon node_presave.
$form['field_review_votes_average']['#access'] = FALSE;
}
}
/**
* Implements hook_node_presave().
*
* Calculates average vote rating.
*/
function MYMODULE_node_presave($node) {
if ($node->type == 'review') {
// Get values from 3 axis.
$vote_axis_one = entity_metadata_wrapper('node', $node)->field_review_vote_axis_one->value();
$vote_axis_two = entity_metadata_wrapper('node', $node)->field_review_vote_axis_two->value();
$vote_axis_three = entity_metadata_wrapper('node', $node)->field_review_vote_axis_three->value();
// Calculate and set average axe.
$votes_average = ($vote_axis_one + $vote_axis_two + $vote_axis_three) / 3;
// @info: Can't use entity_metadata_wrapper, because '->set' not supported on this field.
//entity_metadata_wrapper('node', $node)->field_review_votes_average->set($votes_average);
$node->field_review_votes_average['und'][0]['rating'] = $votes_average;
}
}
Long example with a comment instead of a seperate review content-type.
Like above but:
- Instead of adding the fields to the 'review' contenttype you add as comment fields. At "admin/structure/types/manage/YOUR-CONTENT-TYPE/comment/fields"
- As voting target you choose "Parent Node".
- Use the comment form id to hide the field. Thats in the form_alter function. It is probably something like "comment_node_YOUR-CONTENT-TYPE_form".
- Instead of hook_node_presave use hook_comment_presave. Instead of $node you use $comment and it should work.
In this example the content-type name is "YOUR-CONTENT-TYPE":
/**
* Implements hook_form_alter().
*
* Hide average fivestar field from review edit/create form.
*/
function MYMODULE_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'comment_node_YOUR-CONTENT-TYPE_form') {
// Hide average field, this field is calculated upon node_presave.
$form['field_votes_average']['#access'] = FALSE;
}
}
/**
* Implements hook_comment_presave().
*
* Calculates average vote rating.
*/
function MYMODULE_comment_presave($comment) {
$parent_node = node_load($comment->nid);
if ($parent_node->type == 'YOUR-CONTENT-TYPE') {
// Get values from 3 axis.
$vote_axis_one = entity_metadata_wrapper('comment', $comment)->field_vote_axis_one->value();
$vote_axis_two = entity_metadata_wrapper('comment', $comment)->field_vote_axis_two->value();
$vote_axis_three = entity_metadata_wrapper('comment', $comment)->field_vote_axis_three->value();
// Calculate and set average axe.
$votes_average = ($vote_axis_one + $vote_axis_two + $vote_axis_three) / 3;
// @info: Can't use entity_metadata_wrapper, because '->set' not supported on this field.
//entity_metadata_wrapper('node', $node)->field_review_votes_average->set($votes_average);
$comment->field_votes_average['und'][0]['rating'] = $votes_average;
}
}
BTW: this code uses entity api (function entity_metadata_wrapper) & fivestar.
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion