You are here

plus1.module in Plus 1 6

Same filename and directory in other branches
  1. 6.2 plus1.module
  2. 7 plus1.module

A simple +1 voting widget module.

File

plus1.module
View source
<?php

/**
* @file
* A simple +1 voting widget module.
*/

/**
* Implementation of hook_perm().
*/
function plus1_perm() {
  return array(
    'rate content',
    'administer the voting widget',
  );
}

/**
* Implementation of hook_menu().
*/
function plus1_menu() {
  $items['plus1/vote/%'] = array(
    'title' => t('Vote'),
    'page callback' => 'plus1_vote',
    'page arguments' => array(
      2,
    ),
    'access arguments' => array(
      'rate content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/plus1'] = array(
    'title' => t('Plus 1'),
    'description' => t('Allows readers to vote on content.'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'plus1_settings',
    ),
    'access arguments' => array(
      'administer the voting widget',
    ),
  );
  return $items;
}

/**
* Menu callback to configure module settings.
*/
function plus1_settings() {
  $form['plus1_nodetypes_fieldset'] = array(
    '#type' => 'fieldset',
    '#title' => t('Content type settings'),
    '#description' => t('Select all node types to which a +1 voting widget can be added.'),
  );
  $form['plus1_nodetypes_fieldset']['plus1_nodetypes'] = array(
    '#type' => 'checkboxes',
    '#options' => node_get_types('names'),
    '#default_value' => variable_get('plus1_nodetypes', array(
      'story',
    )),
  );
  $form['plus1_display'] = array(
    '#type' => 'fieldset',
    '#title' => t('Display settings'),
    '#description' => t('You may select none, one or both options.'),
  );
  $form['plus1_display']['plus1_in_teaser'] = array(
    '#type' => 'checkbox',
    '#title' => t('Add a +1 voting widget to the node in teaser view.'),
    '#default_value' => variable_get('plus1_in_teaser', 0),
  );
  $form['plus1_display']['plus1_in_full_view'] = array(
    '#type' => 'checkbox',
    '#title' => t('Add a +1 voting widget to the node in full view.'),
    '#default_value' => variable_get('plus1_in_full_view', 1),
  );
  $form['array_filter'] = array(
    '#type' => 'hidden',
  );
  return system_settings_form($form);
}

/**
* Called by jQuery.
* This submits the vote request and returns JSON to be parsed by jQuery.
*/
function plus1_vote($nid) {
  global $user;

  // Authors may not vote on their own posts.
  $is_author = db_result(db_query('SELECT uid FROM {node} WHERE nid = %d AND uid = %d', $nid, $user->uid));

  // Before processing the vote we check that the user is logged in.
  // We have a node ID, and the user is not the author of the node.
  if ($user->uid && $nid > 0 && !$is_author) {
    $vote = plus1_get_vote($nid, $user->uid);
    if (!$vote) {
      $values = array(
        'uid' => $user->uid,
        'nid' => $nid,
        'vote' => 1,
      );
      plus1_vote_save($values);
      $score = plus1_get_score($nid);

      // This print statement will return results to jQuery's request.
      // drupal_json has replaced drupal_to_js in Drupal 6 (it adds a header).
      print drupal_json(array(
        'score' => $score,
        'voted' => t('<small>You voted</small>'),
      ));
    }
  }

  // Out we go, we're not returning anything
  exit;
}

/**
* Return the number of votes for a given node ID/user ID pair.
*
* @param $nid
* A node ID.
* @param $uid
* A user ID.
* @return Integer
* Number of votes the user has cast on this node.
*/
function plus1_get_vote($nid, $uid) {
  return (int) db_result(db_query('SELECT vote FROM {plus1_vote} WHERE nid = %d AND uid = %d', $nid, $uid));
}

/**
* Return the total score of a node.
*
* @param $nid
* A node ID.
* @return Integer
* The score.
*/
function plus1_get_score($nid) {
  return (int) db_result(db_query('SELECT SUM(vote) FROM {plus1_vote} WHERE nid = %d', $nid));
}

/**
* Save the vote.
*
* @param $values
* An array of the values to save to the database.
*/
function plus1_vote_save($values) {
  db_query('DELETE FROM {plus1_vote} WHERE uid = %d AND nid = %d', $values['uid'], $values['nid']);
  db_query('INSERT INTO {plus1_vote} (uid, nid, vote, created) VALUES (%d, %d, %d, %d)', $values['uid'], $values['nid'], $values['vote'], time());
}

/**
* Create voting widget to display on the webpage.
*/
function plus1_jquery_widget($nid, $teaser) {

  // Load the JavaScript and CSS files.
  drupal_add_js(drupal_get_path('module', 'plus1') . '/jquery.plus1.js');
  drupal_add_css(drupal_get_path('module', 'plus1') . '/plus1.css');
  $score = plus1_get_score($nid);
  global $user;

  // If user is not logged-in.
  if ($user->uid == 0) {
    $logged_in = FALSE;
  }
  else {
    $logged_in = TRUE;
    $is_author = db_result(db_query('SELECT uid FROM {node} WHERE nid = %d AND uid = %d', $nid, $user->uid));
    $voted = plus1_get_vote($nid, $user->uid);
  }
  return theme('plus1_widget', $nid, $score, $logged_in, $is_author, $voted, $teaser);
}

/**
* Theme for the voting widget.
*/
function theme_plus1_widget($nid, $score, $logged_in, $is_author, $voted, $teaser) {
  $output = '<div class="plus1-widget">';
  if (!$logged_in || user_access('rate content')) {
    $output .= '<div class="plus1-msg">';
    if (!$logged_in) {
      $output .= '<small>' . l(t('Log in<br />to vote'), 'user', array(
        'html' => TRUE,
      )) . '</small>';
    }
    else {
      if ($is_author) {

        // User is author so he's not allowed to vote.
        $output .= '<small>' . t('Your<br />content') . '</small>';
      }
      else {
        if ($voted) {

          // User already voted.
          $output .= '<small>' . t('You voted') . '</small>';
        }
        else {

          // User is eligible to vote.
          // The class plus1-link is what we will search for in our jQuery later.
          // But we could have used the selector ".plus1-vote a".
          // Beware : l() and url() have different signatures in Drupal 6.
          $output .= '<div class="plus1-vote"' . l(t('Vote'), "plus1/vote/{$nid}", array(
            'attributes' => array(
              'class' => 'plus1-link',
            ),
          )) . '</div>';
        }
      }
    }
    $output .= '</div>';
  }
  $output .= '<div class="plus1-score">';
  $output .= $score;
  $output .= '</div>';
  $output .= '</div>';
  return $output;
}

/**
* Implementation of hook_theme().
*/
function plus1_theme() {
  return array(
    'plus1_widget' => array(
      'arguments' => array(
        'nid',
        'score',
        'is_author',
        'voted',
      ),
    ),
  );
}

/**
* Implementation of hook_nodeapi().
*/
function plus1_nodeapi(&$node, $op, $teaser, $page) {
  switch ($op) {
    case 'view':

      // Only show the voting widget in allowed content types.
      if (in_array($node->type, variable_get('plus1_nodetypes', array(
        'story',
      )))) {

        // Show the widget.
        if ($teaser && variable_get('plus1_in_teaser', 0) || !$teaser && variable_get('plus1_in_full_view', 1)) {
          $node->content['plus1_widget'] = array(
            '#value' => plus1_jquery_widget($node->nid, $teaser),
            '#weight' => 100,
          );
        }
      }
      break;
    case 'delete':
      db_query('DELETE FROM {plus1_vote} WHERE nid = %d', $node->nid);
      break;
  }
}

Functions

Namesort descending Description
plus1_get_score Return the total score of a node.
plus1_get_vote Return the number of votes for a given node ID/user ID pair.
plus1_jquery_widget Create voting widget to display on the webpage.
plus1_menu Implementation of hook_menu().
plus1_nodeapi Implementation of hook_nodeapi().
plus1_perm Implementation of hook_perm().
plus1_settings Menu callback to configure module settings.
plus1_theme Implementation of hook_theme().
plus1_vote Called by jQuery. This submits the vote request and returns JSON to be parsed by jQuery.
plus1_vote_save Save the vote.
theme_plus1_widget Theme for the voting widget.