4

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?

2 Answers 2

6

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               
?>
4
  • 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, 2012 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. Mar 1, 2012 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, 2012 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, 2012 at 22:37
-2

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) );
4
  • 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, 2012 at 11:41
  • No confusion. Quick reference, mate: rlmseo.com/blog/wordpress-post-variable-quick-reference Mar 4, 2012 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, 2012 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, 2012 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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