Custom Voting API Calculation
The Voting API is really nice when used in conjunction with a module like Fivestar. It takes all of the complexity out of setting up a voting/rating system. On occasion, however, you need it to do some things that aren’t built in. Using the VotingAPI’s API, I’ll show you how to trigger a function (send an email, write a message to the screen, etc.) when a piece of content receives a fifth vote of four stars or greater. That is, a node may have four votes of five stars, and two votes of two stars. As soon as the next greater-than-four vote goes in, we want to do something about it. In our case, the client wants to receive an email when a node is popular, and has had five four-star-or-greater votes.
That’s enough explaining. Let’s get started! First of all, please do not rely on the examples here as they are outdated! Search for “votingapi” in the Drupal APIfor the latest docs.
The code is pretty straightforward (if you understand SQL and PHP arrays). The main point of confusion for me while writing this function was the line that actually writes to the $results variable.
1 |
$results[$info['tag']][$info['value_type']]['count_over_4_stars'] = $info['count_over_4_stars']; |
I was trying to use $cache instead of $results as I’d seen this documented a few different ways… even the example in the documentation seems to have it wrong!
I’ve included some screenshots below to show you what the VotingAPI cache table looks like after adding our custom calculation. The thumbnails are tiny, just below the code.
If you are unsure how to use this code, or where to put it? Perhaps you need to look at Creating a Custom Module.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
/** * @file * A custom module for handling fivestar votes using the VotingAPI */ /** * Create/Set a new cached vote calculation * * @param $results * An array containing the current vote results for this content id * @param $content_type * The content type (probably node) * @param $content_id * The content id * @see <a href="http://drupalcontrib.org/api/function/hook_votingapi_results_alter">http://drupalcontrib.org/api/function/hook_votingapi_results_alter</a> */ function fivestarcounter_votingapi_results_alter(&$results, $content_type, $content_id) { // Stars 1:20%, 2:40$, 3:60%, 4:80%, 5:100% $sql = "SELECT v.value_type, v.tag, "; $sql .= "COUNT(v.value) as count_over_4_stars "; $sql .= "FROM {votingapi_vote} v "; $sql .= "WHERE v.content_type = '%s' AND v.content_id = %d AND v.value_type = 'percent' AND v.value >= 80 "; $sql .= "GROUP BY v.tag"; $myResults = db_query($sql, $content_type, $content_id); while ($info = db_fetch_array($myResults)) { $results[$info['tag']][$info['value_type']]['count_over_4_stars'] = $info['count_over_4_stars']; // we already have the count data, so lets just use it (rather than run another api hook/call later) // this will NOT run if there are no results (no votes of 80% or better) // could add logic to handle the no-votes situation; not necessary for this application fivestarcounter_handle_count($content_id, $info['count_over_4_stars']); } return TRUE; } /** * Handles the custom vote count * * @param $content_id * The content id * @param $count * The custom count value */ function fivestarcounter_handle_count($content_id, $count) { if ($count == 5) { // Normally you'd display text using the t() function, but this is just for testing. drupal_set_message('this has received exactly 5 awesome votes!'); $to = "<a href="mailto:youremail@mysite.com">youremail@mysite.com</a>"; $params['count'] = $count; $params['content_id'] = $content_id; // consider using the user's language (as seen in many drupal_mail examples) drupal_mail('fivestarcounter', 'target_vote_count_hit', $to, language_default(), $params); } else { // Normally you'd display text using the t() function, but this is just for testing. drupal_set_message("this has received {$count} awesome vote(s), which is not exactly 5 awesome votes!"); } } /** * Implementation of hook_mail(). */ function fivestarcounter_mail($key, &$message, $params) { $site_name = variable_get('site_name', "Default site name"); $language = $message['language']; $variables = array('!content_id'=>$params['content_id'], '!site_name'=>$site_name); switch ($key) { case 'target_vote_count_hit': $message_subject = "!site_name: Vote target hit on content_id #!content_id."; $message_body = "The vote target has been hit on content_id #!content_id."; $message['subject'] = t($message_subject, $variables, $language->language); $message['body'][] = t($message_body, $variables, $language->language); break; } } |