0

I needed to assign categories to post from frontend so I am making use of the solution suggested in this thread , in form of a plugin. It is working as expected. I just wanted to add a nonce field in order to make it a bit more secure. I seemed to have failed so far to get it working as I keep getting "Sorry, your nonce did not verify.".

Complete code is given below including the changes I made, which are on the lines 42 and 103. Here is also a link to pastebin thread , in case you will need to identify the lines. In both the lines I have tried to take the hint from this wordpress page .Kindly take a look and let me know why the nonce keeps failing to verify.

   <?php
    /*
    Plugin Name: WPSE Crowded Cats
    Plugin URI: https://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: https://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;

    if ( !isset($_POST['nonce_name']) || !wp_verify_nonce($_POST['nonce_name'],'nonce_action') )
          {
       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='submit' value='Submit' name='crowd-cats-submit'/>
                   <input type='hidden' value='".wp_nonce_field('nonce_action','nonce_name')."'/>
                   <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              
    ?>

Pretty new to php here, please be kind.

0

2 Answers 2

6

You are not inserting the nonce field in your form, so your script won't recieve the nonce field and this code:

 if ( !isset($_POST['nonce_name']))

Will be validated becasue $_POST['nonce_name'] is not set.

In your code, remove this line:

<input type='hidden' value='".wp_nonce_field('nonce_action','nonce_name')."'/>

And, where it said //TODO: set nonce, you need to include:

  $out .= wp_nonce_field( plugin_basename( __FILE__ ), 'nonce_name',true,false);

Note: set wp_nonce_field() 'echo' parameter to false to retrieve the nonce input field instead of printing it.

And then verify by:

if (!isset( $_POST['nonce_name'] ) || ! wp_verify_nonce( $_POST['nonce_name'], plugin_basename( __FILE__ ) ) )
        return;

So, your function get_form() should be:

    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'/>";

        $out .= wp_nonce_field( plugin_basename( __FILE__ ), 'nonce_name',true,false);

        $out .= "</form>";

        return $out;

    }

And your function process_request() should be:

    function process_request(){

        // check submission
        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;

    }
}
0
1

I think your problem is that you have <input type='hidden' value='".wp_nonce_field('nonce_action','nonce_name')."'/> in your code, but wp_nonce_field() generates the entire <input ...> for you. Have a look at your page's source; you probably will see something like

<input type='hidden' value='<input type="hidden" value="abcdef1234">' />

Change your $out to something like this:

$out .= "</ul>
    <input type='submit' value='Submit' name='crowd-cats-submit'/>
    " . wp_nonce_field( 'action_name', 'nonce_name' ) . "
    <input type='hidden' value='".esc_attr($tax)."' name='crowd-cats-tax'/>
    <input type='hidden' value='$post_id' name='crowd-cats-pid'/>";
2
  • I use firebug and I can see the value in the source, but for some reason the value eg.52f4D1ee4 remains stable on every submit. Also the categories do not get set.
    – gurung
    Sep 11, 2013 at 15:09
  • 1
    The nonce will only get generated every 12 (or is it 24) hours. So it makes sense that the nonce value would remain the same, unless you're checking it at day-long intervals.
    – Pat J
    Sep 11, 2013 at 18:41

Your Answer

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

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