MMK
MMK

Reputation: 605

why is my ajax function not working as expected?

so my class looks like this:

class Myclass{

    private $nonce;

    public function __construct(){
        if( get_current_screen()->id == 'nav-menus' ){
            $this->nonce = 'my-plugin-nonce';
        }
        add_action( 'wp_ajax_run_action', array( $this, 'run' ) );

        wp_localize_script(
            'my-script',
            'my_script',
            array( 'nonce' => wp_create_nonce( $this->nonce ), 
                 'ajaxurl' => admin_url('admin-ajax.php'),
            )
        );
    }

    public function run(){
        if( ! wp_verify_nonce( $_POST['nonce'], $this->nonce ) )
            return false;

        wp_send_json_success();
    }

}
new Myclass;

And here is the javascript code:

$.ajax({
    type: 'POST',
    dataType: 'json',
    url: my_script.ajaxurl,
    data: {
         'action': 'run_action',
         'nonce' : my_script.nonce,
    },
    complete: function( object ) {
        console.log( object.responseJSON )
    }
});

The problem is that when i try to call the run_action action from within my javascript ajax function it does not return true as it should.

Note that i have properly localized my script and any data contained in the object is being rendered correctly.

Why is that happening ?

Upvotes: 0

Views: 457

Answers (2)

Mikk3lRo
Mikk3lRo

Reputation: 3496

Localization of the script must be done on the pages you are including the script on (ie. on the nav-menus.php admin page in this case) - you do not include the code that actually enqueues your javascript, but the code you did post suggests to me that you are actually attempting to localize the script in the ajax-call itself - which won't work.

I've rearranged your code below and added comments to explain each change:

class Myclass {
    /**
     * No reason not to assign this already (and I've renamed it to explicitly,
     * let people reading the code know that it is not the nonce itself, but the
     * name of the nonce action - fooled me for a minute or two :p
     */
    private $nonce_action_name = 'my-plugin-nonce';

    /**
     * The __construct function is great for hooking everything you need to
     * hook, and for setting initial variables. Pretty much anything else
     * should NOT be in this function though!
     */
    public function __construct(){
        // Register your ajax action.
        add_action( 'wp_ajax_run_action', array( $this, 'run' ) );

        // Hook into the appropriate action for admin scripts
        add_action( 'admin_enqueue_scripts', array( $this, 'scripts' ) );
    }

    public function scripts() {
        /**
         * I've negated your if-statement here - basically we don't want to do
         * anything at all if we are not on the correct page - which is clearer
         * this way - also you had it in the __construct function, which will
         * actually produce a fatal error, since get_current_screen is not
         * usually defined yet at that point(!)
         */
        if( get_current_screen()->id !== 'nav-menus' ){
            return;
        }

        //Now enqueue (or register) the script
        wp_enqueue_script('my-script', plugins_url('/my-script.js', __FILE__));

        //Then localize it
        wp_localize_script(
            'my-script',
            'my_script',
            array(
                'nonce' => wp_create_nonce( $this->nonce_action_name ),
                'ajaxurl' => admin_url('admin-ajax.php'),
            )
        );
    }
    /**
     * Actual ajax handler
     */
    public function run(){
        if( ! wp_verify_nonce( $_POST['nonce'], $this->nonce_action_name ) ) {
            //This is a guess, but I think you'll want to wp_send_json_error
            //here to match up with your success below
            wp_send_json_error();
        } else {
            wp_send_json_success();
        }
        /**
         * Always recommended to explicitly die() after handling ajax - though
         * the wp_send_json_* family probably does it for you.
         */
        die();
    }
}
new Myclass;

A final note is that ajaxurl is actually always defined in the admin, so you don't really need to add that to your localization (though it only hurts by adding a few extra bytes).

Upvotes: 2

sirBlond
sirBlond

Reputation: 335

Note from the codex:

wp_localize_script() MUST be called after the script has been registered using wp_register_script() or wp_enqueue_script().

So your workflow should be as follows:

  1. Register script
  2. Localize it
  3. Enqueue your localized script.
  4. Tie it to appropriate action: wp_enqueue_scripts or admin_enqueue_scripts

For example:

Add action to your __construct method:

add_action('wp_enqueue_scripts', array($this, 'registerAjaxScript'));

Then create a method that registers and localizes your script:

function registerAjaxScript() {
  wp_register_script('my-script', 
         string $src, 
         array $deps, 
         string or bool $ver, 
         bool $in_footer
  );
  wp_localize_script('my-script',
        'my_script',
        array( 'nonce' => wp_create_nonce( $this->nonce ), 
             'ajaxurl' => admin_url('admin-ajax.php'),
        )
  );
}

Upvotes: 1

Related Questions