2

I've implemented some AJAX functionality for my plugin and it works fine as long as I'm not logged in as admin - then wp_verify_nonce fails. It works for unauthorized users and authorized regular users too.

Here's my PHP class (I removed everything that is not relevant to the issue):

class My_Ajax {
    function __construct() {
        add_action( 'wp_ajax_geoip_citylist', array($this, 'geoip_citylist') );
        add_action( 'wp_ajax_nopriv_geoip_citylist', array($this, 'geoip_citylist') );
        add_action( 'wp_enqueue_scripts', array($this, 'geoip_localize_js'), 11 );
    }

    function geoip_citylist() {
        if ( ! wp_verify_nonce($_POST['geoipNonce'], 'my_geoip_nonce') ) {
            exit('Wrong nonce: ' . $_POST['geoipNonce']);
        }
    }


    function geoip_localize_js() {
        wp_localize_script(
            'my_custom_js', 'myGeoipAjaxObject', 
            array( 
                'myGeoipNonce' => wp_create_nonce('my_geoip_nonce')
            ) 
        );
    }
}

And here's my Javascript:

$.ajax({
    url: myMainAjaxObject.ajaxUrl,
    type: 'POST',
    dataType: 'json',
    data: {
        geoipNonce: myGeoipAjaxObject.myGeoipNonce,
        action: "geoip_citylist"
    },
    success: function(data) {
        replacePhones(data.user_city, data.current_phone, data.city_list);
    },
    error: function(error) {
        console.log(error);
    }
});

The nonce in PHP error response seems to be correct, but it still doesn't validate for some reason.

I've spent days trying to figure out what's wrong and trying to google this in every possible way, but so far I couldn't find a solution that would work. There are unanswered questions with similar issues on stackoverflow, like this one which was created in 2011... I could just assume that nonces don't work with admin accounts in Wordpress, but I would like to at least get a confirmation before giving up.

UPDATE: I've tried to use just the code that I provided here and it still resulted with the same error (I also double checked the cache and it was refreshed).

UPDATE 2: myMainAjaxObject and its ajaxUrl are inserted in another script. Since AJAX URL is same for every AJAX request, I just use the global one instead of redefining it every time. So this is not what's causing the error. Also if it wouldn't be defined it would never work. Once again, it doesn't work only for the admin, for other users and unauthorized users it works fine. And I do get "Wrong nonce: 73dd02f662" in the server response when I'm logged as admin. So I'm 100% sure that URL is correct.

2
  • 1. for non mutating operations you don't need to use nonce. 2. your code seems to be ok to me, are you sure there isn't something additional in play here. 3. nonce is must for logged in users (and therefor admins) for mutating operations Commented Oct 7, 2016 at 6:38
  • For this plugin I use nonce mostly to make sure that the request is coming from my website (I know I can't be sure just because of that, but this extra measure is nice enough), also I want to figure out what's wrong simply to improve my knowledge. I'm sure there's nothing else causing this, I even just tried to remove everything but the code I provided here and got the same result. Commented Oct 7, 2016 at 6:57

2 Answers 2

9

I think the problem was that I manually deleted my cookies a few times while testing. Among them was a cookie called "wordpress_logged_in_{token}" where {token} is an unique identifier. My best guess is that lack of this cookie caused issues with nonce creation or/and verification. It was hard to notice because I was still able to browse the admin panel (it looks like there WP is using a different cookie called "wordpress_{token}") and on the front end this website doesn't show user status anywhere (accounts are not used there, however login functionality is there, just hidden from the view).

The solution was very simple - I just re-logged as admin and my AJAX started working for the admin as well. So if someone runs into a similar issue, make sure that when you clear cookies, you either delete only ones that you need to remove/regenerate or, if you delete all of them like I did, make sure to re-log as admin.

PS: I'm sorry I didn't provide all the details from the start, but I did try to provide as much information as necessary. I knew I was missing something and now I feel stupid for even asking this question. However, I'm not going to delete it so that maybe someone who runs into the same issue could save some time.

3
  • 1
    If you downvote, please leave a comment telling why. Otherwise it's not helpful at all. Commented Oct 9, 2016 at 9:30
  • no idea why downvoted, but the lesson here should be that when you test, test properly, and don't use hacks to make it "faster". if you needed it you should have used the browser's privacy mode to ignore the current cookies Commented Oct 9, 2016 at 10:18
  • 1
    Thank you for the comment! Indeed, it was totally my fault, but according to search I'm not the only one who ran into such issue and yet seem to be the only one that figured the reason and posted it, now I get the downvotes for that... oh, well, I hope at least someone would learn from it one day... I used the private mode for testing, but I also wanted to make sure that everything works for the admin as well and for that I needed to clear the cookies, but I did it the wrong way and wiped out all of them instead of just deleting the ones that I needed to refresh... Commented Oct 9, 2016 at 10:51
2

Ajax URL in WordPress is something like this https://examle.com/wp-admin/admin-ajax.php. When you are not logged in and you are in the frontend, you need to pass the URL to the script.

In your code, you are using this:

url: myMainAjaxObject.ajaxUrl,

but myMainAjaxObject.ajaxUrl is not defined. You could do it like this:

wp_localize_script(
    'my_custom_js', 'myGeoipAjaxObject', 
    array( 
        'myGeoipNonce' => wp_create_nonce('my_geoip_nonce'),
        'ajaxUrl'      => admin_url( 'admin-ajax.php' )
    )
);

Now, you can use myMainAjaxObject.ajaxUrl in the frontend and for non-logged in users.

3
  • I forgot to mention, myMainAjaxObject is inserted in another script. Since AJAX URL is same for every AJAX request, I just use global one instead of redefining it every time. So this is not what's causing the error. Also if it wouldn't be defined it would never work. Once again, it doesn't work only for the admin, for other users and unauthorized users it works fine. And I do get "Wrong nonce: 73dd02f662" in server response when I'm logged as admin. So I'm 100% sure it's not the URL. Thank you for the suggestion though. Commented Oct 7, 2016 at 22:35
  • There is nothing about myMainAjaxObject in your question, only myGeoipAjaxObject and the information is incomplete; that is why good descriptions in questions lead to good answers, while incomplete information leads to guessing anwers like this one. For future questions, please remember to include as much information as posible in the question, a repoducible code is the best description.
    – cybmeta
    Commented Oct 8, 2016 at 7:56
  • Sure, it's my bad, I've already updated the question. Commented Oct 8, 2016 at 21:22

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.