With help from experts on this site, I have been able to put together a plugin that allows to choose and submit categories from the front-end. Further, in order to make it a bit more secure I have tried to include nonces and a honey pot in the form.
Although I am pretty sure that my nonce and honeypot are working fine, I am also not sure if I am checking things in the right order. You can see that I have tried to check for the honeypot first and then the main submit and then the nonce. Is it in the right order ? If not, what order should they be in? I believe if I do not check things in right order, I may get unexpected results. Entire plugin code is given below.
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(!empty($_POST['pot-net']))
return; //end process if field is not found empty.
if ( ! isset($_POST['crowd-cat-radio']) || ! is_array($_POST['crowd-cat-radio']) )
return;
if (!isset( $_POST['nonce_name'] ) || ! wp_verify_nonce( $_POST['nonce_name'], plugin_basename( __FILE__ ) ) ) {
print 'Sorry, your nonce did not verify.';
exit;
} else { // continue to process form data
// 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='text' name='pot-net' style='visibility:hidden' value=''/>
<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'/>";
$out .= wp_nonce_field( plugin_basename( __FILE__ ), 'nonce_name',true,false);
$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
?>
If you will need me to put this on pastebin and point out the specifically concerned lines of code, please let me know.