Skip to:
Content
Pages
Categories
Search
Top
Bottom

Rate anything: new plugin in development, soliciting architecture advice


  • Dwenaus
    Participant

    @dwenaus

    Hi fellow developers. On a project I’m working on I need the ability to rate photos. and then do lots of things with the highest rated each day, week, etc. In my previous BuddyPress Group Forum Rating plugin I stored the data in the BBpress posts meta database table, which was fine, but not good if I wanted to rate other things.

    For this new plugin I was thinking of making a sort of rating API where people could rate any type of object and the data would all be stored centrally. That would be helpful for generating a site-wide ‘karma’ score for each user based on the ratings they have received for myriad things such as forum posts, groups, photos, videos, activity updates, blog posts, blog comments, you name it.

    So to do this I was thinking of creating a new database table. (maybe two for meta info). But I recently read that the author of EventPress used custom post types to store registration data. This is intriguing, but i’m not sure it’s the most flexible approach.

    Any thoughts on this would be appreciated.

Viewing 24 replies - 1 through 24 (of 24 total)

  • Boone Gorges
    Keymaster

    @boonebgorges

    You’ll probably have to write less code if you use custom post types. Also, using custom post types will make it easier for other developers to extend and customize the plugin. Using WP’s meta_query or tax_query will make it pretty straightforward to store and retrieve the data.

    Your general idea about a ratings API is really smart. BP’s activity API might be a sort of model: BP provides bp_activity_add(), and components like groups have their own wrapper functions. Or a central ratings class that other plugins could extend. The details don’t matter that much.

    Also, make sure you provide some flexible markup functions, so that it’s not only easy to retrieve the ratings themselves, but so there’s also a nice way for people to display them on arbitrary content types.

    Looking forward to seeing what you come up with!


    nanchante
    Participant

    @nanchante

    +1 Sounds great.


    Dwenaus
    Participant

    @dwenaus

    Boone, thanks for the feedback.

    I’m still a bit hesitant to use custom post types. Maybe the query powers are good enough but in some cases where I want to get meta information about all ratings, won’t I run into problems when my data is separated into the posts table and the posts_meta table. I’ll have to do some complex joins and what not. But if I make a custom DB table, I can just use GROUP BY or DISTINCT to get what i need quite quickly. I’m thinking of stuff like Highest Rated XYZ or Most Rated ABC. These things won’t fit so well into the custom post type/custom taxonomy mould. Any more thoughts on this?

    @djpaul – I see in your (totally awesome) achievements plugin, that you use a few custom db tables. Do you have any thing to add regarding your choices. I’m thinking this ‘Rate everything’ is more akin to that plugin.

    Also, I’m thinking this plugin will be a bit more like Facebook ‘Like’ than an actual star Rating. but we’ll see what comes out in the end.

    Hello!

    Achievements is being re-written to use post types; I think it’s up to one post type and two custom taxonomies so far. I think you can and should use a custom post type for this. Don’t underestimate the power of the post types and taxonomies APIs, but remember you can also make your own direct SQL query to the posts table if you really need to. I assume you’ve figured out what fields you’re going to store in the database, and where?


    ARHistoryHub
    Participant

    @arhistoryhub

    I echo nanchate – +1!


    Boone Gorges
    Keymaster

    @boonebgorges

    Derek – You’re right that the queries will be a bit more complex than if you stored your data in a single table, but here’s the thing: You won’t have to write those queries, since they’re all already part of the custom post type API. Or at least, as Paul says, if there are really complex things that can’t be handled by the API, there are adequate filters in place for you to modify the query. But I’d be very curious to hear what the queries might be that the API wouldn’t handle; it seems to me that the meta_query introduced in 3.1 is enough to handle just about anything, without your having to worry about the difference between the posts and the postmeta table.

    Another big advantage of post types is that it’ll automatically use any caching solution that the installation has. So, even if the queries are, strictly speaking, more complex than they’d be in a custom table, this can be mostly mitigated by good caching.


    Dwenaus
    Participant

    @dwenaus

    @djpaul oh boy – I was hoping you wouldn’t say that! ;) Can you tell me why you are re-writing it, and if you’ve started any difficulties you’ve encountered.

    Here is my initial db scheme with examples (initially visualized as a mysql table)
    rating_id – auto-generated
    object_id – id of object being rated. ie. post_id, group_id, bp_album image id, forum_post_id
    object_type – type of thing beind rated. ie. group, blog post, album image, forum post
    rater_user_id – the user_id of the person doing the rating (need to be logged in)
    owner_user_id – the user id of the person who ‘owns’ the object being rated
    rate_type – either ‘like’, ‘vote’ or ‘rate’.
    rate_value – value of rating/like/vote. Like can only be ‘like’, vote is 1 or -1, rate can be range from 1 to 5.
    date_rated

    maybe I’m being too flexible with the different rate types and I should just stick to one type, such as Facebook style ‘Like’. but then that leaves out a lot of functionality for amazon and app store style ratings. it would be nice if these were consolidated in one area, but maybe too ambitious.

    Looking again at custom post types/taxonomies I can see how the custom post type will be an individual rating, and the owner of that custom post type will be the rater. I can add a custom field for the user id of the object owner. It looks like the object_type would be a custom taxonomy, and the id of the object rated would be another custom field. The value of the rating could either be a custom field or maybe a taxonomy.

    Should I be connecting up the object being rated or the object owner using custom taxonomies? if yes, then I’m having trouble visualizing that.

    thanks!


    Dwenaus
    Participant

    @dwenaus

    @djpaul and @boonebgorges, I hear you about the caching. that is one big bonus. I can make big ugly queries and know that they’ll be cached. If I ‘roll by own’ then I’ll have to build caching myself (but it’s not that hard).

    I looked at the meta_query functions, and they seem quite sufficient for most queries, they only thing they are missing are the powerful mysql abilities such as GROUP BY, COUNT, DISTINCT, and mysql’s cryptic but powerful date range functions. Much of this can be done in php with more flexibility, but sometimes it’s nice to do a single query and get exactly what you want.

    The most common need for this plugin, is to display the combined vote/rating/likes of a content object. I can pretty easily figure out how to do that with MySQL, but how to do it quickly with custom post types/taxonomies?

    For example, i’m looking at a list of images, and I want to see the ratings of each image. I can’t really store it in my new rating custom post type, do I store it in some site option? seems kinda odd, or do I create a new custom post type – one for each object type – seems kinda odd, or do I use taxonomies. Or do I store it in the meta table of that individual object such as post_meta, group_meta. etc. this will not scale well because some objects have no meta table (such as images).

    any insights into these things would be greatly appreciated.


    Boone Gorges
    Keymaster

    @boonebgorges

    `this will not scale well because some objects have no meta table (such as images)`

    How are the images being stored? If they are uploaded through the Media uploader, then they are just a post type of their own, right?

    I guess that, if I knew that each rate-able content type would have a meta table, that I would store individual ratings in a post type, and store aggregate/average ratings in meta (updated each time a new rating is posted). That’s how I do it on the (admittedly imperfect) BP Group Reviews plugin. But if that won’t work, it wouldn’t be too complicated to have a second post type for average ratings. I don’t think this would introduce too much inefficiency, since there would be far fewer posts of this type (a max of one for each item) than individual ratings.

    No matter where you store it, I would recommend storing the aggregate/average scores separately instead of calculating them on each page load (whether in PHP or MySQL). (Or maybe you’re not suggesting this? :) )


    Dwenaus
    Participant

    @dwenaus

    Boone, The images i’m talking about are from the BP Albums+ plugin (which soon will be upgraded to the gigantic BP Media plugin) which as no meta table for album photos.

    If all you wanted was Average ratings across all objects, then another custom post type would be fine. but what i really want is total or average ratings for each single item (post, group, bp album image, forum post).

    maybe a hybrid approach would work. For those objects that have a meta table, use that (groups, posts, users, etc.). And for those objects that don’t (bp album images) maybe create a ‘shadow’ custom post for each item.

    yes, you are right, I should not be calculating this on the fly, although I it would be so much simpler if mysql did it on the fly using COUNT!


    stwc
    Participant

    @stwc

    Bookmark post.


    Dwenaus
    Participant

    @dwenaus

    i’m going down the road of custom post types and taxonomies with reservations. i’m coding it now, and while it’s strange, it will work.

    My one concern is this: ratings on various posts, groups, photos are not really content, rather it is meta content, so storing each rating as a custom post seems a bit weird. It is going to bloat the posts table, which will affect people backing up.

    Yes it will be good for caching for plugins that cache the posts, but that is about the only benefit I can see. The actual coding of the plugin is MORE complex because of using custom post types and taxonomies. For example, things like dates inserted as a custom field will work, but not as elegantly as in mysql.

    Food for thought.


    imjscn
    Participant

    @imjscn

    How about save this custom post’s contents as an array so that it will be just one colum in parent post’s meta?

    I’m wondering why you want to store meta in the posts table as opposed to, say, the posts meta table? :)


    Boone Gorges
    Keymaster

    @boonebgorges

    `storing each rating as a custom post seems a bit weird. It is going to bloat the posts table, which will affect people backing up. `

    This might be interpreted as a strength of the approach. Some backup solutions don’t account for custom tables. The custom post type approach guarantees that the rating data will be included in regular WP backups.

    Why do you need to store dates in a custom field? Why not use post_date and post_modified?

    That said, I know what you mean: it can seem funny to use what might seem like an arcane API to do something that could be accomplished with a simple call to the database. But using the API is doing a lot of hidden work: caching (as already discussed), security (proper query escaping, etc), compatibility with different database setups, post revisions, not to mention allowing you to use The Loop when displaying. So while it might be a bit more work on simple save/get methods, in exchange you are getting a lot of more advanced work done for you.


    Dwenaus
    Participant

    @dwenaus

    storing meta data in an array is good for simplicity, but it fails when I want to do any type of query on that data.

    Boone, Good points about the date I can use those. And what you say about the back up makes sense too – it goes both ways, it will bloat the table AND it will definitely get backed up.

    Thanks for listing the hidden things that you get when you use the custom post type api. When dealing with custom *content* I think they are all very relevant (such as you wiki plugin). However when dealing with meta content such as Ratings and Likes, it breaks down a bit.
    – Yes caching is nice, but I can deal with that using the wp’s nice caching functions, I will loose out on other fancy caching methods, but its good enough.
    – I believe I will already get proper query escaping because I’ll be using the $wpdb class and prepare the query accordingly.
    – different database setups – very good point, no argument here
    – post revisions, I have no need for this, in fact I have no need for title, content or excerpt which causing wp_insert_post to fail, so I need to artificially create a title just to be able to post. this makes me think I’m abusing the system rather than using it.
    – I have no need to loop through this rating meta data.

    While it is almost always a good idea to use the built in APIs for all the reasons you outline and more, sometimes it is not. I think there are some rarer cases when using the API is a hindrance. It’s kind of like someone using wordpress to build a gigantic e-commerce store – sure you can do it – but maybe you should have started with magento instead. I feel that my plugin is in the middle and could go either way.

    This exchange has been quite fruitful, thank you for the great discussion.


    Boone Gorges
    Keymaster

    @boonebgorges

    It’s been useful for me too – thanks for bringing it up in this public forum. Please continue to share your reflections as you actually build the plugin. And let’s talk about the possibility of merging the BP Group Reviews plugin into what you’re doing – I don’t know if it’ll be possible given the way you’re structuring things, but there might be room for collaboration there.


    Dwenaus
    Participant

    @dwenaus

    I think the plugin will be called Rate Vote Like Anything. And I’m building it with those three systems in mind:
    Rate: you can rate things 1 to 5 (or whatever scale)
    Vote: you can vote thumbs up or down (1 or -1)
    Like: you can like something

    So it probably will work to replace other voting systems. I’m going to take your advice and do my best to include an API so that others can use the plugin for any type of content. I’m going to replace my other BuddyPress Rate Forum Posts plugin. Tens of twenties of people (!) have asked me to extend my other plugin to rate blog posts and comments, so this new system will do it.

    And as far as group rating is concerned, I’ve already built the star rating aspect for another site. you can see it in action here http://www.fashionsalade.com/2011/02/street-people/my-icons/rebeca/ (you need to login via facebook first).

    The major benefit of this new plugin is that it will have shared ‘karma’ from all the items you create. Some people will want this, others might not. But it’s a cool feature that I really like. Site admins can also decide which items will be karmable (i think i just made a word up).

    I’m also not making it BP dependant, Although I’m guessing it will mainly be used on BP sites, as wordpress already has things like GD post ratings – but that plugin is a beast.

    After suffering most of yesterday while stretching custom post types to do my bidding, I’ve decided to create new tables today. and now i’m at peace :D However it was a great exercise to do, and I got to dig into wordpress core much more than I normally do, which is always fruitful. Thanks so much for your encouragement.


    imjscn
    Participant

    @imjscn

    what’s the posibility for this— a custom post type has its own activity stream, rate its activity comments and calculate the statics within this type’s scope?


    Dwenaus
    Participant

    @dwenaus

    Update: I took the approach of using my own db tables. and so far very smooth sailing. Once I got the hang of setting up db tables and handled db schema updates, everything is crystal clear and easy to work with. I’m glad I took both routes. and for any future custom content I will definitely use custom post types and taxonomies, but for this kind of specialized functionality that is not really content, custom db tables is much cleaner in my opinion. (Perhaps a hybrid approach is sometimes the best approach, it all depends.)

    @imjscn the plugin will probably only handle activity comments as a whole. You will be able to like, rate or vote on them (or all three at the same time!). I’ll add hooks and filters in the plugin so you could probably limit rating for activity comments on your special custom post type.


    imjscn
    Participant

    @imjscn

    That’s great!
    like/rate/vote ? Sounds gonna be another beast like GD? Hope not :-)


    Selu Vega
    Participant

    @bluelf

    If you need some spanish translation, you can count on me.


    Dwenaus
    Participant

    @dwenaus

    @imjscn it won’t be a beast, it will be … poetry :)

    and in case anyone else is reading this thread in the future regarding the in-depth discussion about using db tables or not, I wanted to mention one thing I learned.

    You can insert or update the wordpress database – existing tables or your own – using nice built in class functions. for example:

    `
    $wpdb->mytable = $wpdb->base_prefix . ‘mytable’;
    $values = array(
    ‘col1’ => $myval1,
    ‘col2’ => $myval2,
    );
    $wpdb->insert($wpdb->mytable, $values);
    `
    doing things this way, you gain all the security features of the wordpress database class, and don’t have to work about preparing or escaping the query. it’s done for you. $wpdb->update also exists. more here: https://codex.wordpress.org/Function_Reference/wpdb_Class


    imjscn
    Participant

    @imjscn

    @boonebgorges , following your above advice, I created my BP avatar plugin for all post types and saved data in post meta. But I don’t know if the object is cached or not, could you please take a look at following codes? I also have doubt on the efficiency of the global $obj. — Since it’s not in a loop, so, everytime when call an item, it means to make a new instance of the calss. Please give advice when you have a little time, thanks!

    Class My_Obj{
    var...
    function populate(){
    $obj = get_post_custom( $post->ID);

    if( !empty( $obj[0] ) ){
    $this->obj_id = $obj[0];
    $this->height= $obj[0];
    $this->width = $obj[0];
    }
    }
    // other stuffs...
    }

    function obj(){
    global $post, $obj;
    $id = get_the_ID();
    $obj= new My_Obj( $id );
    }

Viewing 24 replies - 1 through 24 (of 24 total)
  • The topic ‘Rate anything: new plugin in development, soliciting architecture advice’ is closed to new replies.
Skip to toolbar