4

I want to have multiple axis comment reviews for nodes.
Example - rate a restaurant by the following criteria: food, drinks, atmosphere, location.

I want to order the nodes in a view according to the average vote.

Questions:

  1. How can I setup the views relationship and fields to order nodes by total rating?
  2. Should I create a separate vote tag in fivestar settings for each axis?
  3. Is this possible out of the box with fivestar for D7?

UPDATE

To illustrate better the problem, here are the screenshots and exact numbers I'm getting.

Views settings
Views output
Calculations from reviews


UPDATE 2

Thanks to everyone who posted here.

I'm still not able to aggregate the votes correctly but I think it's due to some settings in views.

I will award the bounty and post the code/solution I used as soon as I solve it completely. I think Ayesh and junedkazi gave the correct answer saying almost the same thing. Will confirm when I solve it completely.


FINAL UPDATE

The votes are not aggregated on the nodes properly. Custom module is calculating the "overall" value for each comment and that works as it should. But when the fivestar/votingapi calculates the votes for parent node on node view page and on views listing page, it does not work. It takes into consideration only the last review, and not the rest.

Just in case, here's the calculating code I'm using in a custom module:

/**
 * Implements hook_comment_presave().
 */
function MYMODULE_comment_presave($comment) {
  // Keep these as separate variables so the code doesn't have to be
  // updated if the number of axis has been changed from admin.
  $axis_count = 0;
  $rating_sum = 0;
  // Go through all elements and check if this is a rating field.
  // Avoid hardcoding the field names (except the overall field).
  foreach ($comment as $element_id => $element) {
    if (is_array($element) && isset($element[LANGUAGE_NONE][0]['rating'])) {
      $rating_sum += $element[LANGUAGE_NONE][0]['rating'];
      $axis_count++;
    }
  }
  // Trim out eventual weird decimals
  $overall = number_format($rating_sum / $axis_count, 0);
  // Save the value in the overall field
  $comment->field_overall[LANGUAGE_NONE][0]['rating'] = $overall;
}

Please if anyone has any ideas I'd be really thankful. Even though the bounty expired, I will award it for a working solution (I don't care about the points).

2

Fivestar Widget

I believe the Fivestar widget stores values as a percent average rather than as a vote average. In otherwords the Fivestar widget is storing a value between 0-100 rather than 0-5.

When you have a Fivestar widget collecting 0 to 5 stars, each star is worth 20. This is why when you have an average of '2 stars', your seeing a value of 40. (2*20=40)

To extend this:

  • A node with 1, 2 star vote will be stored as 40
  • A node with 2, 2 star votes will be stored as 40
  • A node with 1, 2 star vote and 1, 3 star vote will be stored as 50

This can easily be fixed by dividing the displayed output by 20.

From there, I believe your view may already be setup properly.

I'll rework my answer if this isn't relevant here.

  • Thanks for the answer. I'll check if that's really the case and post back here. Would be great if it is working out of the box! Do you know if I should create separate vote tags for every axis though? – Aram Boyajyan Sep 21 '12 at 15:58
  • I updated the answer with more screenshots and it still makes no sense. Furthermore I did everything on a clean install. Do you have any other ideas? – Aram Boyajyan Sep 23 '12 at 17:55
2

I had a similar use case but instead of using comments I created a separate node type called as review.

I created multiple axis using the fivestar settings. Also an average vote axis to store the average.

enter image description here

After this I created each axis on the node type which is "Stars (rated while viewing)" and making sure the exposed check box is checked off on the display settings.

After this I re-used the same fields on the review type (in your case it will be the comment) and set the widget type as "Stars (rated while editing)" and select the proper parent reference.

Also I had field permissions module installed and with proper permissions to hide the avg vote axis from normal user on the review content type. You can do it with hook_form_alter as well.

Then I added this small piece of code to calculate the avg vote based on all the other axis. In your case it will be hook_comment_presave.

In this case I am assuming you have the entity api module bcoz I am using entity_metadata_wrapper function.

function hook_node_presave($node) {
  if ($node->type == 'review') {
    // get all fivestar fields
    $fields = field_read_fields(array('type' => 'fivestar'));
    // load the wrapper with node information
    $wrapper = entity_metadata_wrapper('node', $node);
    // to hold each axis vote
    $total = array();
    foreach ($fields as $field_name => $field) {
      // make sure your field belongs to the same bundle and is not deleted
      // and is not the avg vote field
      if (($fivestar_field = field_read_instance('node', $field_name, $node->type)) && (!$fivestar_field['deleted']) && ($fivestar_field['field_name'] != 'field_average_rating')) {
        // Get the axis value
        $value = $wrapper->$field_name->value();
        // place the value in the total array
        $total[] = $value;
      }
    }
    $node->field_average_rating[LANGUAGE_NONE][0]['rating'] = array_sum($total)/count($fields);
  }
}
1

How can I setup the views relationship and fields to order nodes by total rating?

You need to add a relationship to vote results and define the tag. (see #2).

Should I create a separate vote tag in fivestar settings for each axis?

YES!

Is this possible out of the box with fivestar for D7?

Not out-of-the-box, if you want to have an automagically calculated overall field. even though there are discussions about Computed Field module, I had to invest time on a custom module (that uses hook_comment_presave to calculate overall voting).

The main concept behind multi-axis voting is, tags. First, you need to add multiple tags in Voting API settings page. It defaults to "vote" but you will need food, drinks, atmosphere, location and probably an overall. Note that overall calculations could be a little tough unless you make a module to do so.

First, add 4 fields to the comment form under 4 different tags (or 5, if you want an overall one. if you want to calculate overall from other 4 fields, lets do so later).

Each field can be used (rated) on editing (while leaving the comment). Rating target, parent node. But individual vote values are still stored in the comment field. So when you display the comment, you will see individual comment's rating data.

Then, the tricky part. You need to add 4 (or 5, for overall) fields to the node as well. Choose this under each tag you created earlier. Now you will be able to see aggregated results in normal node View. For Views, you need to define the tag.So without an extra overall tag, you will only be able to sort nodes by best food restaurants by votes, likewise.

You can however have a hidden overall field in comment form and then calculate the overall value from other 4 axises on a hook_comment_presave. I'm assuming you will be able to do it yourself. I have a working module if you want to inspire. (it's for a client though).

  • Thanks for the answer :) So basically the view will order the nodes according to the overall field which is calculated through a custom module. Did I understand correctly? – Aram Boyajyan Sep 23 '12 at 19:41
  • Yes. The "overall"value is actually yet another axis but it's hidden from the user. When the user submits the review/ratings, it will calculate value for the "overall" axis and let Fivestar continue. Fivestar will set votes to the parent node under "overall" tag so you can sort bu overall rating. – AyeshK Sep 23 '12 at 19:48
  • I think it's clear now; I'll try and then come back. Thanks again. – Aram Boyajyan Sep 23 '12 at 19:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.