Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Basic idea is for any post on the site, I'd like users to be able to assign a category for it by selecting from a set of checkboxes on the frontend. This would be a kind of crowd-sourced categorization of content.

Any ideas on the best way to approach this?

share|improve this question

2 Answers 2

up vote 5 down vote accepted

I wanted to provide you with a few ideas but once I started I couldn't stop myself and wrote this little plugin with an obscure name to get you started.

<?php 
/*
Plugin Name: WPSE Crowded Cats
Plugin URI: http://wordpress.stackexchange.com/questions/43419/how-do-i-create-a-way-for-users-to-assign-categories-to-a-post-from-the-frontend
Description: Allow visitors to change categories of posts. Ready to use with custom taxonomies and post types. 
Version: 0.1
Author: WPSE
Author URI: http://wordpress.stackexchange.com/users/2110/maugly
License: GPL2
*/


add_action('plugins_loaded','wpse_init_crowd_cats_class');
function wpse_init_crowd_cats_class(){
    new WPSECrowdCatsClass();
}


class WPSECrowdCatsClass { 

    function __construct() {

        // APPEND THE FORM AUTOMATICALLY TO EVERY POST
        add_filter( 'the_content', array( $this,'append_form' ) );

        // TEMPLATE ACTION TAG TO BE USED IN THEME
        // Usage: do_action('wpse_crowd_cats_form');
        // Usage: do_action('wpse_crowd_cats_form', $post_id, $taxonomy );
        add_action( 'wpse_crowd_cats_form', array( $this,'wpse_crowd_cats_form' ), 10, 2 );

        // FORM PROCESSING
        add_action( 'template_redirect', array( $this,'process_request' ) );

    }

    function process_request(){

        // check submission
        if ( ! isset($_POST['crowd-cat-radio']) || ! is_array($_POST['crowd-cat-radio']) )
            return;

        //TODO: check nonce

        // sanitize and check the input
        $suggested_terms = array_map( 'absint', $_POST['crowd-cat-radio'] );
        $post_id = absint( $_POST['crowd-cats-pid'] );
        $tax = $_POST['crowd-cats-tax'];
        if ( ! taxonomy_exists($tax) )
            return;

        // Allow only existing terms. Not sure if this is needed.
        $args = array( 'hide_empty' => false );
        $args = apply_filters( 'mcc_allowed_terms_args', $args, $post_id, $tax );
        $args['fields'] = 'ids';
        $allowed_terms = get_terms( $tax, $args );
        foreach ( $suggested_terms as $key => $term_id )
            if ( ! in_array( $term_id, $allowed_terms ) )
                unset( $suggested_terms[$key] );

        // Add terms to taxonomy
        $affected_terms = wp_set_object_terms( $post_id, $suggested_terms, $tax, false );
        update_term_cache($affected_terms);
        return $affected_terms;

    }


    function get_form( $post_id=null, $tax='category' ) {

        if ( is_null($post_id) || ! taxonomy_exists($tax) )
            return false;

        $args = array( 'hide_empty' => false );
        $args = apply_filters( 'mcc_get_terms_args', $args, $post_id, $tax );
        $all_terms = get_terms( $tax, $args );

        if ( ! $all_terms )
            return false;

        $post_terms = wp_get_object_terms( $post_id, $tax, array( 'fields' => 'ids' ) );

        $permalink = get_permalink( $post_id );

        $out = "<form id='crowd-cats' action='$permalink' method='POST' >
            <ul >";

        foreach ( $all_terms as $t ) :

            $checked = in_array( $t->term_id, $post_terms) ? 'checked' : '';
            $out .= "<li>
                        <input type='checkbox' id='crowd-cat-$t->term_id' name='crowd-cat-radio[]' value='$t->term_id' $checked /> 
                        <label for='crowd-cat-$t->term_id' >".esc_attr($t->name)."</label>
                     </li>";

        endforeach;

        $out .= "</ul>
                <input type='submit' value='Submit' name='crowd-cats-submit'/>
                <input type='hidden' value='".esc_attr($tax)."' name='crowd-cats-tax'/>
                <input type='hidden' value='$post_id' name='crowd-cats-pid'/>";

        //TODO: set nonce

        $out .= "</form>";

        return $out;

    }



    function append_form($content){

        global $post;

        if ( 'post' != $post->post_type )
            return $content;

        $form = $this->get_form( $post->ID );

        if ( ! $form )
            return $content;

        return "$content \n $form";
    }


    function wpse_crowd_cats_form( $post_id=null, $taxonomy='category' ) {

        if ( is_null($post_id) ) {
            global $post;
            $post_id = $post->ID;
        }

        echo $this->get_form( $post_id, $taxonomy );
    }


} // end of class               
?>
share|improve this answer
1  
I really need to get back to work now but I will revisit this answer later and provide with more explanation where needed. I did a basic test and it seems to work. Ask here in comments if you have any questions. –  Michal Mau Feb 24 '12 at 23:12
    
Thanks! This is great work. I think there is a lot of potential behind something like this. I'll tinker as well. –  Travis Clark Mar 1 '12 at 22:18
    
@Travis I'm glad I could help :) In chat toscho suggested some more improvements to security using nonces and hidden "honey pot" fields. I haven't found a time to add these changes yet. I will let you know here in comments if I do so. –  Michal Mau Mar 1 '12 at 22:33
    
@TravisClark Also note that if you've found this answer useful and actually answering your question then you can mark it as accepted. It's not like I want to push my rep :) but we already have a zillion question marked as unanswered here on WPSE :/ –  Michal Mau Mar 1 '12 at 22:37

The approach I would use would be update post and using in_array to see if the category has already been added.

global $post; //define global of post
$category_array = $post->post_category;

//check if the new category or item is in the array already:

foreach($_POST['category_checkbox'] as $value){
if(!in_array($value,$category_array)){//not in array yet, add it
$new_category = get_cat_ID( $value ) ;//turn the name into category ID
array_push($category_array,$new_category);
}
}
//update the post
wp_update_post( array($post->ID,$category_array) );
share|improve this answer
1  
afaik there's nothing like $post->post_category in the global $post object. It would be nice if you could edit your answer to avoid potential confusion. –  Michal Mau Feb 25 '12 at 11:41
    
No confusion. Quick reference, mate: rlmseo.com/blog/wordpress-post-variable-quick-reference –  Neil Davidson Mar 4 '12 at 0:09
    
Thanks for your answer @Neil. But apparently there IS some confusion already. Have you actually tried using it? The source you cited is either really outdated or just plain wrong :) I should have been more precise in my comment - $post->post_category can exist in $post object but it's like a useless ghost of the past - it will always be 0 (zero) from WP 2.1 onwards - see Codex - get_post(). Please edit your answer accordingly. –  Michal Mau Mar 4 '12 at 12:38
2  
While post_category field will be filled under some rare circumstances (like result of oldish wp_get_single_post() function call) it's not there in most cases in modern WP and should not be relied on. –  Rarst Mar 4 '12 at 12:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.