Voting API Field for CCK

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
webchick's picture

What?

A few days ago, I compiled a list of all the node review modules I could find at the time, and wrote up an article comparing them: http://www.lullabot.com/articles/a_review_of_node_review_modules. The amount of overlap in these modules is, quite frankly, stunning. Yet they all do slightly different things. Node Review handles multiple axes. Simple Vote merely stores the aggregate score for a node. User Review allows you to place a comment with your vote. Vote Up/Down handles a simple "yes/no" style of voting.

It occurred to me that if we took a step back, we might be able to develop "one voting module to rule them all." Rather than having to keep implementing these new voting modules because others "almost" do what we want but not quite.

I've looked briefly at customvote.module, which looks as though it endeavors to be that tool. But I'm thinking something slightly different: a voting API field for CCK.

Why?

  • I started down this track because I needed to implement Amazon-style reviews. So both a 1-5 "star" rating, as well as a "was this review helpful?" rating. None of the existing voting modules (that I could find anyway) did this. This meant implementing "yet another voting module" which greatly offended my sensibilities. ;)
  • In reviewing all the node review modules, I was struck by how they're basically all exactly the same except for a few differeces in implementation details:
    1. Is the review stored as a node, or only a rating?
    2. What "scale" are they rated from? 1-10? 1-5? Yes/No?
    3. Is a user allowed to comment along with their vote, or does the system store just a rating?
    4. Is a user allowed to vote on one aspect of the thing, or several?
    5. Is the voting widget a series of stars that you click on? Buttons? A drop-down?
    6. Are the voting results displayed as a series of stars? A number? An arrow?
    7. Is only the overall rating displayed, or is the user's rating also displayed? Can you see what all users voted?
  • An overwhelming amount of code in each of these modules is dedicated to customization; should the widget say "Share your opinion" or does it just say "Rating"? Should it output stars, numbers, or both?

If we could somehow extract these properties more generally, it would be extremely powerful.

How?

CCK seems the perfect tool for this:

  1. Whether fields are called "Rating" or "Review" or "Your opinion" or whatever is completely customizable.
  2. Reviews could be stored as nodes, with multiple voting fields attached (rating for X node, and was this review helpful?)
  3. CCK has built-in Views support, making it simple to create listings of votes ordered by author name, chronologically, by rating, etc.
  4. We can define different input widget types and theme functions to handle the input/output of votes.
  5. We can use the "multiple values" property to store votes on different axes.

Where?

I have some very preliminary code uploaded to my sandbox. Note that this doesn't come even close to working in its current state. I'm throwing this up here in case others can help provide architectural advice as I wrap my brain around CCK, Views, and Voting API, and contribute ideas and possibly patches so we can stop going down this road of 5,000 voting modules that all do almost-but-not-quite the same thing.

Thanks in advance for any feedback. :)

Comments

i'm in

moshe weitzman's picture

i was about to embark on a similar path. i looked at your code and it seems quite sane to me.

for my needs, i need multiple axes of voting. seems like you are proposing that those are multiple instances of this field type which makes total sense.

we need to keep in mind views_calc module and CCK calculated field widget so that we can get averages within a review (i.e. multiple axes) and across multiple nodes. this should all work fine.

in fact, i think those 2 modules give us most of what we need. i'm not even sure what we need votingapi for. thats probably becasue i don't votingapi very well

this post is now on the frontpage. lets get this going!

Why you want voting API

robertDouglass's picture

The Content Recommendation Engine is a really good reason why you want this data available to the Voting API. Once it's in there, the CRE goes and does whiz-bang analysis (actually called Slope-1), and comes up with recommendations of content and users based on how people are voting. The CRE is also an API for developers, for what it's worth. I'm sure there are other good reasons for Voting API integration, but that one alone is enough to convince me.

Seconded. We definately

Anonymous's picture

Seconded. We definately don't want to lose CRE integration ... we just got it!

But overall I love this idea. I'm now maintaining the "Voting" module (sigh YAVM - yet another voting module) as it needs some serious love at the moment. But looking forward, if it's core functionality could already be handled through CCK and I just needed to provide the whiz-bang flashy widget, that would save a lot of hassle all around.

A vote of support (eww, pun-ny) for this endeavor from me.

+1 for CRE comment but i

Scott Reynolds's picture

+1 for CRE comment but i think the big reason for VotingAPI is that it allows all types of voting. Pluraility voting, approval voting instant-runoff and the list goes on. VotingAPI, like CCk, is a lego brick that can be used to build high quality sites.

I think you're on to something, here...

Max Bell's picture

Orphaned modules are, clearly, a serious problem. Views and CCK have also begun to enjoy a degree of stability that doesn't exist outside core by fiat of sheer popularity, ergo any effort to extend them becomes, defacto, more praiseworthy than an individual module might be ordinarily.

You are correct in that such an addition to CCK would make the plethora of voting modules superfluous to any designer save those who do not mean to incorporate views as well.

And I've given a fair amount of thought to the installer/profile addition to Drupal in terms of creating profiles that allow the user to focus on solely the parts relevant to the design they wish to create. I mention this because where such profiles begin to incorporate modules from contrib, clearly it is paramount that any such profile minimize dependence on them, simply to avoid having it's overall functionality diminished when a key module is orphaned. I've been toying with various configurations of Drupal modules in recent weeks, as an example, and would estimate that there are possibly thirty or more that I would personally consider indispensible that don't even have anything to do with creating a specialized installation of Drupal.

So, if voting modules (which are must-have items even if unused simply because they add a potentially cool feature) can be done away with by extending CCK, what's not to love? Even if the result is another discreet module, it is defacto much less of a potential support issue because CCK is not in any great danger of becomming unsupported in the near and relevant future.

On the other hand... All of this made me wish that there were a little more consensus among Drupal's general development community, because what it made me appreciate is the fact that I would love for there to be an API between Views, CCK and Drupal for module extension and interoperability. While I appreciate that such a thing would be hypertrophied in scope and haven't seen such a thing discussed specifically thus far, I've also got to imagine that simply creating consensus for such a standard could take months or years. Imagine having a form as a front-end for creating cck widgets, like module builder, though, not something that produced a lot of redundant, spaghetti code but something that served as a front end for creating application frameworks based on an API so that seasoned developers could code about their business if need be or use it as a prototyper.

All of which runs the risk of my lapsing into a serious daydreaming session in which Drupal begins to take on the form and useability of hypercard, and I should be doing productive things and focusing on more tangible wants (like another soda).

Indeed, however; build this and my clients and users will use it, and I will applaud with wild enthusiasm because I'd like to see A LOT MORE people thinking this way.

+1

dado's picture

I am guilty of deploying one of the me-too voting modules (userreview). I agree a CCK field = voting field makes a lot of sense. It solves the problem of permitting multiple axes, comments attached to the vote. Ideally you could plug in different widgets. Not sure how you would be able to enforce 1 vote only per user per reviewable node.

I'll gladly deprecate userreview in favor of the votingapi field when userreview's functionality is present therein. Thanks!

For what it's worth...

webchick's picture

Userreview was among my favourites of node review modules I reviewed. :)

But glad to hear you're behind the idea. :) I'll keep people posted with progress.

I also like this idea. I

KarenS's picture

I also like this idea. I also thought userreview came the closest to what I wanted. The main change I made to my own copy of userreview was to implement star displays of ratings instead of the text ratings (I borrowed some of the css and images from medium vote). I especially like having views integration, which I think is absolutely necessary for any multi-purpose voting module.

Thanks webchick for taking this on!!

I need your help

Anonymous's picture

Hi, i actually have the same problem that you describe, the usersreview module is exactly what i need but is a most that the voting style be starred, could you send me your module (if it's possible of course) my email is damianrr@gmail.com

I like the way you think

Anonymous's picture

As NodeReview author, permit me to say "Oooo..." to this idea. My CCK-fu is minimal and I keep being told that it's not really stable yet (true/false?), which is why I'd not considered going that route. If the same functionality could be duplicated as just as field and configuration, though, I'm certainly game for it.

It would also have the advantage of easily offering fancy scoring controls without the need for extra code in each module. One reason NodeReview just uses a select box is that at the time, I just didn't want to bother with anything more complicated. :-)

Question: With a "rating field" type, how would you in CCK bind it to a text field? One of NodeReview's features is that each axis gets both a numeric (number, star, etc.) score and a comment, both of which are required. How would that be done with a votingapi CCK field type, exactly?

Dur

Crell's picture

And yes that is me in the post above. I didn't realize that g.d.o allowed anonymous posting. :-/

CCK is fairly stable...

webchick's picture

I wouldn't probably recommend total end users from implementing it on their sites, as occasionally the DB schema has changed and stuff like that, and there have been periods of time where it has required patches to work properly. But as long as you're not scared off from that kind of thing, it's an incredible site-building tool.

Question: With a "rating field" type, how would you in CCK bind it to a text field? One of NodeReview's features is that each axis gets both a numeric (number, star, etc.) score and a comment, both of which are required. How would that be done with a votingapi CCK field type, exactly?

You don't actually need to worry about this, really, imo. The rating is what you're concerned with (ex: Price: 1-5). The comment associated with a rating is just a text field.

Still a matched set

Crell's picture

Yes, it's just a text field. But it's a textfield that specifically backs up the numeric rating and vice versa.

I can't be sure until/unless I actually tried to write it, but it seems like I'd still need some way to associate the two. That would especially be the case for Views integration.

Another approach...

webchick's picture

This is something Moshe and I were talking about as we were batting ideas back and forth on IRC.

"Core" CCK already implements numeric and select fields, which is pretty much what Voting API would have to implement itself. So what about attaching Voting API-"ability" to existing CCK fields? So more like an admin/settings interface where you select from a list of fields and specify which are "rating" types, and their properties (percent, tags, etc.) as well as their given "target" (nodereference) field. Then some fancy hook_form_alter magic to pre-populate the target based on querystring argument and remove it from the form. Add in a few theme functions for displaying stars or arrows, and voila.

As I write this, sounds a bit hackish, but I might start here and then move onto the "end goal" a bit later when I understand this stuff a bit better. :)

I know this isn't the

desm0n's picture

I know this isn't the subject at hand so to speak but one thing they all have in common is attachment to a node and not to any taxonomy. This i find rather interesting.

If any of the reviews modules could be attached to taxonomy they would have far reaching appeal. For example you have a bunch of forums and one of them is entitled Movie Reviews. It would make sense to attach a review module to the nodes in that taxonomy only and not the entire forum set as is currently the standard.

I know when i set up my forums i looked at doing this on all the available modules, put in numerous requests when finding they didn't exist and promptly then gave up as it wasn't achievable.

Instead of a CCK module to do reviews i think a standalone reviews module that does attach to individual taxonomy would give the entire flexability you are looking for.

Love/Hate module does taxonomy, afaik.

webchick's picture

I needed a node review module for my purposes, so the article only covers the node review modules. :)

Voting API lets you specify the 'content type' you're reviewing; be that nodes, comments, taxonomy terms, etc. So the field would have those settings too.

Ah sorry i was in a bit of a

desm0n's picture

Ah sorry i was in a bit of a rush yesterday and half asleep when posting this :)

What i meant was to attach reviews to "terms" not taxonomy. The idea is quite simple but it appears the practice isn't so easy.

Say you have a reviews forum for say, oh i don't know, the latest Xbox games. You would attach a review module to the XBOX REVIEWS term within the forums but obviously not on any other forums that do not, generally, have reviews. This allows users to review their favourite game with all the bells and whistles a review module would bring, using exisitng node types in exisiting locations.

This gives far greater flexibility than using CCK as you can attach your review module to a CCK created content type anyway.

I'm a firm believer in trying to keep everything, whereever possible, in one place. The way the reviews modules currently work is that they either attach to ALL terms of one type of node or you end up creating a seperate node type, thus taking the user to another section of your site.

However with attachment to terms you can use exisiting infrastructure to achieve the same results without adding further sections.

In fact thinking on further it would be great to see the ability of CCK to attach itself to terms. Then you could extend that one term with extra review boxes etc quite like you do when you add taxonomy, but for only set terms.

So again using our example you would have say 5 forums that act as normal forums and 1 that is still a forum but when posting new content to it displays a set of CCK attached fields for reviewing in that forum.

Its early and i've only had one coffee but i hope you see where i'm going with this.

category module

chud's picture

check out the category module... it basically turns all terms and vocabs into nodes (plus a bunch more) which would allow you to associate reviews with a term (b/c it's a node)

Thanks chud i'll certainly

desm0n's picture

Thanks chud i'll certainly do that. The last time i checked category module it confused me into submission but i've come a long way since then. Sounds great, i'll play with that on my test system.

What I'd like to see

drumm's picture

I'd like to see form elements for the various complex form elements seen in voting, notable stars. These would only be form elements, and not tied to voting API. This is good since it would more clearly isolate JS and form issues from any given module.

Agreed

eaton's picture

I have a simple (very simple) radio-button based 1-n rating element that can be used by any voting module. What other pieces would be useful? jQuery-ified widgets? A slider? None of these would have to be tied to a given backend API, obviously.

Voting API Field for CCK

coupet's picture

Voting Option

  1. Ebay style voting - vote on author who published content
  2. Amazon style voting - vote on content published by author

Implementation of voting functionality to allow for voting on author's of nodes would be great!

Darly

Naming: Node Review Field

ChrisKennedy's picture

I don't see how this is a "Voting API field" per se. Based on the content of this thread it's actually a "node review" field. There are other uses of the Voting API for which this field would not work, such as the Advanced Poll module. I haven't used CCK much but it seems optimistic to think that a field could be created for all uses of VotingAPI.

Ideally...

webchick's picture

It actually does encapsulate all of the functionality of voting api, albeit with most of the stuff tucked in an "advanced options" fieldset or whatever so that it doesn't totally confuse people.

While it might start out simply for node reviews, I'd like to see this take on the whole gamut of what Voting API can do, therefore the name is accurate imo.

Totally Support!

Anonymous's picture

I totally support this effort!

If I can help in any way (though I'm a total Drupal noob), let me know...
Ian Cabell

I put together a possible CCK framework

KarenS's picture

I was thinking about how to make this work most efficiently in CCK and finally came up with something that I think has possibilities. I started with the code in webchick's sandbox and reworked the CCK part of the processing. I made no attempt to hook it into voting api or display any pretty widgets or anything, just tried to get a cck framework in place.

What I ended up with seems pretty flexible and hands a lot of the heavy lifting off to CCK. I define a multiple value cck field for the vote. Each individual user vote will create one value for that field. The way CCK is structured, a multiple value field resides in its own table, so this will create a single field table for the votes, with one record for each vote. We can define any number of columns for a field, so I set it up to flexibly include only as many columns as are needed, based on the field settings. It can accomodate multiple axis by giving each of them columns in the vote field. And you can indicate in your settings whether or not you want to allow the user to write a review, and add columns for that, if necessary. Each vote/axis combo also contains the key to the voting api record for that vote, so you can get the rest of the vote info by joining the field table to the voting api table.

As an example, if I create a field and say that I want 2 axis -- Value and Quality and I want them to have a place for the user to write a review, I end up with the following columns in my field: a field for the key for the voting api record for the value vote, a field for the review that goes with the value vote, a field for the key for the voting api record for the quality vote, and a field for the review that goes with the quality vote. Plus each record automatically gets a nid and vid column.

I then tweaked the regular widget and field code to create a way for the field to insert the voting form into the view, since we want the form there rather than on the edit page.

I think this method would eliminate the need to create separate nodes for each vote, since cck fields are views enabled (which I think was the main reason for making them nodes). It also eliminates the need for any code to manage a separate table, since it can be handled as a field table by CCK, so the module code can remain relatively simple and focus on creating widgets, formatting the output, and doing whatever work needs to be done to integrate it into voting api.

I now see there is no way to attach file to this message, so I have to figure out some place to put my file. I hate to put it in my sandbox since webchick already has a file with that name in her sandbox, and that would really confuse people, so I guess I'll just email it to webchick and she can decide what, if anything, she wants to do with it.

Just to let folks know...

webchick's picture

I've updated the code in my sandbox with Karen's stuff, since she knows CCK much better than I do, and thus I trust her instincts on architectural decisions related to CCK. :)

The VotingAPI integration is still missing, but I think the skeleton that's there is solid enough for someone to take a stab at it. Any takers, please feel free!

Performance? Reinvention?

ultraBoy's picture

Hi.

What about performance with CCK-voting-fields approach? I see that VotingAPI has the fastest structure (for it's features). Please remember, that performance is very important when you need to analyse and use actual votes (and that necessity is why we actually want votes, right?). I believe the developer of CRE will support me, that speed requirement are very strick for such task. Also, VotingAPI has (extensible) caching of voting results. Can it be implemented with CCK-aproach?

Your approach must (yes, must, if you want to use good algorythms to analyse voting data!) not be slower than VotingAPI.

I myself have my own CRE-like module implemented (it's at http://like-i-like.org I've done it before CRE), it's integrated with VotingAPI now. Not that I don't want to switch from VotingAPI, but I just suppose maybe we just need to add features to it (field names or whatever), instead of copying it's functionality. Please think about it.

The only thing this would do...

webchick's picture

Is handle storing numbers and stuff in voting api tables and read it back out. I don't really forsee any performance penalties, as it's not recreating what votingapi does, just encapsulating its behaviour into a field that can be applied on any node type.

I misunderstood you. I

ultraBoy's picture

I misunderstood you. I thought a CCK field has to store data into another table. I haven't even seen your code... Now, after calculated field available - it's obvious.
As I told, I'll try working on this voting field.

New Working Code

dfletcher's picture

I have gotten something basic working. It's a heavily modified version of what was in Webchick's sandbox. I have moved it to my own sandbox because much (70-80%) of the original code is gone; it's almost a new project.

This version uses VotingAPI for all storage purposes.

The output is only half-flexible currently: you can theme the output but not the input form (yes that's a biggie).

There is no "review/node rating" system in here yet- everything so far just deals with voting, not author-ranking.

It would be cool if you could specify if you want the results to display along-side the input form before voting, but it can't do that yet.

I'd also like to see some AJAXy functionality - "vote in place" where the form is replaced by the results in-page after voting.

forgot to mention

dfletcher's picture

This is only known to run in 5.x currently!

moved yet again

dfletcher's picture

Sorry for moving my code on the first day ;)

This project is now a real module:

http://drupal.org/project/votingapi_field

fapi themeing

moshe weitzman's picture

all forms are inherently themeable since fapi offers this built in. just prefix the form name with _ and you are off and running.

Integration

dfletcher's picture

There has been some amazing feedback in first couple weeks of development of VotingAPI Field. There are too many folks to thank for this feedback, so just go into #drupal and say thanks to them all ;-)

What has come to light is the need for close integration with other aspects of Drupal, some of which at first glance are very much unrelated to CCK. This may be obvious to some of the folks working on these integrations but to others it might not be so easy to see, so I'm writing down a few details here.

What I will concentrate on is a voting relationship between nodes. VotingAPI Field users will be able to attach other nodes directly using the CCK Nodereference module, or may attach nodes by writing some PHP code to specify the relationship. When a vote is placed on the node with the voting field, a vote is also placed on all relationships of that node. These relationships can very easily represent a one-to-many aggregate relationship, among others.

We've all seen the Amazon style comment voting. A comment represents one vote and the parent article holds the aggregation of those votes. Problem is, comments in Drupal are not nodes. Therefore votingapi would have to go far outside the scope of being a CCK widget and start interacting with the comment system in a unique way. Thanks to the work of rDouglass and others, comments are going to become nodes for this very reason. Then what can happen is the Drupal administrator tells votingapi_field that comments are attached to their parent via a small bit of PHP glue code. This comment integration could be provided as a standard add on module with VotingAPI Field once the new comment system is in place, so no code needs to be written for this common case of attaching comments to parent nodes.

A similar situation arises for users. It would be neat to allow voting on users. Again, the user system has very little to do with CCK. Unless someone steps up and figures out a way to make users into real nodes, VogingAPI Field would have to write lots of custom code. The usernode module seems to have some promise, but it does not allow administrators to choose what type of node is created so it might be very limited. Another module, "usernodes" (gah!) might do this, but since neither one is updated for 5 I cannot determine currently if either would work.

In short, VotingAPI Field wants everything to be a node :-)

Working Node References

dfletcher's picture

Node references are now working in latest CVS. You can reference another node via the standard CCK node reference module or by writing a PHP hook.

User integration

KarenS's picture

There are two possiblities for user integration. One is usernode. All you do is install usernode and it will automatically create a single node for each user that has only two fields, the nid of the usernode and the uid of the user. You don't actually do anything with that node (you don't add fields to it or anything else) it just creates a table you can use that has exactly one unique node for each user, so you can use that table in joins and in Views to display user info or link to users. If you want to create a user profile that is a node, you then install the nodeprofile module along with usernode, which allows you to link any CCK content type in as the profile node. The usernode creates the link to the user and the nodeprofile node can then have CCK fields attached to it.

The other possibility is the CCK userreference field which allows you to link one or more users to a node. That field could use some work, but patches are more than welcome if you see ways to improve it. You could create a CCK content type for your user info that would store the vote, then use userreference to link that node to the actual user it represents.

I've used both these methods in a various projects and both work fairly well. Also, using either one of these methods you will have fields that work in Views, so you can use Views for lists and results.

Thanks!

dfletcher's picture

Thank you so much KarenS, I will try both approaches to see what works well with VotingAPI Field.

Also, I haven't spoken with you since I started this - thanks for the original code from webchick's sandbox ... I used that as a base for the new project :-)

fivestar?

greggles's picture

http://drupal.org/project/fivestar

I believe that fivestar has many of these ideas since it enables cck votingapi widget.

Any thoughts from Karens or Webchick about differences between the code you started and the current fivestar module?

--
Knaddison Family | mmm Beta Burritos

Clicking a vote before submitting a content

halohaloplace's picture

Hello all. I have a question:

For example I created a Content Type called Product Review. Then I will allow my authenticated users to submit a product to review using the fields I have set up for Product Review content. I want to make it possible for the submitting member to vote while they are still filling up the review form; and then when they submit the form, the vote will be submitted as well. When they are done, I want other visitors to use the voting system that the author-member previously used (add their vote in there). This is somewhat possible with Fivestar, however we need to create a node first, which complicates when I have to let my reviewers create their own nodes.

Like this:

----Within the form of content type---
Product Title -- Product A (editable by authors only)
Product Quality Rating (uses voting system) -- author can vote right away, and when this form is submitted, visitors can also use this system to vote
---save/submit---

Is this possible?

user rating other user

Energyblazar's picture

Hello, i am new to this web development stuff and have just moved from joomla to drupal a few days back.

I am trying to do something like this

I am trying to create a simple rating system wherein user can rate other users.

To rate or vote other user the user must

1) Be an authenticated user

2) Be part of the group.

Here is an example for better understanding.

In my site i have these users who are authenticated, TIM, JIMMY, SAM, TOM, NICKKY, EMMA, PHIL, ALEXA.

TIM has created a group called ABCD [ i am using organic groups and have provided access to authenticated users to create groups ]

SAM, EMMA and PHIL have joined the group.

So now SAM can vote rate these users EMMA PHIL and TIM, while he cannot rate others i.e. JIMMY, TOM, NICKKY, ALEXA who are not part of this group ABCD.

So is the same for others they can only rate members who are part of their group, which they may have created or joined.

Any suggestions as to how can i achieve this.... ?????

Thanks in advance....

Try Drupal Answers

mikeytown2's picture

Give Drupal Answers a shot but looking at this, I think you will need something like organic groups.

Thanks

Energyblazar's picture

Thank you mikey i already got the organic group modules with it i have latest 5star module and am search for a way to use 5starextra module (which enables one to add the 5star in the user profile) in D7.....and had completely forgotten about drupal answers....thanks for reminding me... :)

Voting Systems

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: