I am working through the jQuery chapter of the book and have installed the sample module that provides a post rating example. I can follow most of the code and the module installs without error. The install code correctly builds a custom table in the database.

There are 6 files:
plusone.info
plusone.module
plusone.css
plussone.js
plussone.info
plussone_widget.tpl,php

All are located in ../sites/all/modules/plusone .

The problem is that when the module is installed there is no sign of any link or setting to enable the voting button. There are three areas where I am very much in the dark:

  • The use of MENU_SUGGESTED_ITEM in the plusone_menu function. From documentation it appears that the administrator needs to do something to enable the menu. But what ? (Changing the menu item to NORMAL_MENU_ITEM causes no menu option to show).
  • The menu item page callback - plusone_vote - gives a page not found.
  • My Drupal templating knowledge isn't good but:
    • Is the template file correctly located - or should it be in ../sites/all/themes ?
    • Is the template file correctly named ? Should it have a double underscore ? And where does 'widget' come from ?

Here is the module code - plusone.module

<?php
// $Id$

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

/**
 * Implements hook_permission().
 */
function plusone_permission() {

  $perms = array(
    'rate content' => array(
      'title' => t('rate content'),
    ),
  );
  return $perms;
}

/**
 * Implementation of hook_menu().
 */
function plusone_menu() {

  $items['plusone/vote'] = array(
    'title' => 'Vote',
    'page callback' => 'plusone_vote',
    'access arguments' => array('rate content'),
    'type' => MENU_NORMAL_ITEM,
  );
  
  return $items;
}


/**
 * Called by jQuery, or by browser if JavaScript is disabled.
 * Submits the vote request. If called by jQuery, returns JSON.
 * If called by the browser, returns page with updated vote total.
 */
function plusone_vote() {

  global $user;
  $nid = (int)$nid;
  
  // Authors may not vote on their own posts. We check the node table
  // to see if this user is the author of the post.
  $is_author = db_query('SELECT uid from {node} where nid = :nid AND uid = :uid', array(":nid" => (int)$nid, ":uid" => (int)$user->uid))->fetchField();
  
  if ($nid > 0 && !$is_author) { 
    // get current vote count for this user;
    $vote_count = plusone_get_vote($nid, $user->uid);
    echo "Vote count is: $vote_count<br/>";
    if (!$vote_count) { 
      echo "Yep was existing votes<br/>";
      // Delete existing vote count for this user.
      db_delete('plusone_votes')
       ->condition('uid', $user->uid)
       ->condition('nid', $nid)
       ->execute();
      db_insert('plusone_votes')
        ->fields(array(
          'uid' => $user->uid,
          'nid' => $nid,
          'vote_count' => $vote_count + 1,
        ))
        ->execute();
      watchdog("plusone", 'Vote by @user on node @nid.', array('@user' => $user->name, '@nid' => $nid));
    }  
  } 
  $total_votes = plusone_get_total($nid);
  // Check to see if jQuery made the call.  The AJAX call used
  // the POST method and passed in the key/value pair js = 1.
  if (!empty($_POST['js'])) { 
    // jQuery made the call
    // This will return results to jQuery's request
    drupal_json(array(
     'total_votes' => $total_votes,
     'voted' => t('You Voted')
    )
   );
   exit();
  }
  
  // It was a non-JavaScript call. Redisplay the entire page
  // with the updated vote total by redirecting to node/$nid
  // (or any URL alias that has been set for node/$nid).
  $path = drupal_get_path_alias('node/'. $nid);
  drupal_goto($path);

}

/**
 * Return the number of votes for a given node ID/user ID pair
 */
function plusone_get_vote($nid, $uid) { 
   $vote_count = db_query('SELECT vote_count FROM {plusone_votes} WHERE
        nid = :nid AND uid = :uid', array(':nid' => $nid, ':uid' => $uid))->fetchField();
   return $vote_count;
}


/**
 * Return the total vote cont for a node.
 */
 function plusone_get_total($nid) { 
    $total_count = (int)db_query('SELECT SUM(vote_count) from {plusone_votes} where nid = :nid', array(':nid' => $nid))->fetchField();
    return ($total_count);
 }
 
/**
 * Load the values required to make the widget work
 * And output the widget on hook_node_load
 */ 
function plusone_node_view($node, $view_mode) {

  global $user;
  
  $total = plusone_get_total($node->nid);  
  $is_author = db_query('SELECT uid from {node} where nid = :nid AND uid = :uid', array(":nid" => $node->nid, ":uid" => $user->uid))->fetchField();  

  if ($is_author) { 
    $is_author = TRUE;
  } else { 
    $is_author = FALSE;
  }

  $voted = plusone_get_vote($node->nid, $user->uid);

  if ($view_mode == 'full') {
      $node->content['plusone_vote'] = array(
        '#markup' => theme('plusone_widget', array('nid' =>(int)$node->nid, 'total' =>(int)$total, 'is_author' => $is_author, 'voted' => $voted)),
        '#markup' => "Test",
        '#weight' => 100,
      );      
  }   
}



The code download for this book is freely available from the Apress site. Here is a dropbox link to the Chapter 18 Javascript example that I can't get to work.

I realise that it may be a bit of a cheek asking for help to fix code from a book, but I've had no joy from the Apress site. I understand the book is a widely accepted Drupal 7 resource and it is possible that someone has got this module to work. Also there aren't a great number of use cases for Drupal + jQuery and I'd really like to get to play with this one if I can.

Any thoughts or tips much appreciated.

Comments

Jaypan’s picture

What does your name have to do with the topic at hand? I'm not sure why you would put it in the title.

peterk900’s picture

That's the book's author ! Maybe wrong but I thought his book was perhaps more well known than it is. I mentioned title and author because I hoped that someone might remember having looked at this particular demo code and perhaps have found any mistake I might be making. Sorry for any confusion here.

peterk900’s picture

I've found the menu link - it needs to be enabled and is in the Navigation, rather than the main menu as I'd thought.

The problem line is this $nid = (int)$nid; in the snippet below:

function plusone_vote() {

  global $user;
  $nid = (int)$nid;
  .........


(full code for .module, which includes this function, is in original post)

The error message is:

Notice: Undefined variable: nid in plusone_vote() (line 46 of /home/sites/fffffffffffffffl.co.uk/public_html/drn1/sites/all/modules/plusone/plusone.module).

The problem is that it cannot find the nid. The write up doesn't make it clear how this thing is supposed to work but I guess that you need to be on the node that you want to rate and therefore the module should get the nid from the url. Any thoughts ?

PS Devel shows nid is available when on an article page