I've written a simple plugin that works on a clean install. All it does is once a page is loaded it requests some ajax via admin-ajax.php and then outputs the returned data to the console. When I put on the site I am working which is nothing out of the ordinary it just some custom post types it only works if I am logged in.

When the function that generates the ajax output test_ajax_process_request() is called via wp_ajax_test_ajax when user is logged in it works fine, the console shows what is loaded from admin-ajax.php. But if I am not logged in wp_ajax_nopriv_test_ajax seems to not call test_ajax_process_request(), I know this as I am using error_log to trace when test_ajax_process_request() called. Usually if there is a problem admin-ajax.php will just return a 0 but in this case it's returning my thame's HTML.

My plugin is made of 2 files: ajax_test.php:

Plugin Name:  Simple AJAX test 2018-05-22
Author:       Kevin Meredith
Description:  Pluggin to test client site AJAX request
Version:      1

// disable direct file access
if ( ! defined( 'ABSPATH' ) ) {

function load_js() {

    wp_enqueue_script('ajax_test', plugin_dir_url( __FILE__ ) . 'ajax_test.js', array('jquery'), null, true );

     $test_nonce = wp_create_nonce('test_nonce');
            'ajax_url' => admin_url( 'admin-ajax.php' ),
            'nonce'    => $test_nonce,
    error_log('Load JS TEST SITE');
    // wp_localize_script is used to send an array of php values to javascript
    // it embeds values in the HTML so that be used by java script
add_action( 'wp_enqueue_scripts', 'load_js' );  

function test_ajax_process_request() {
    error_log('test_ajax_process_request() has been called');
    // first check if data is being sent and that it is the data we want
    //check_ajax_referer( $action, $query_arg, $die )
    if ( check_ajax_referer( 'test_nonce', 'js_nonce', false) ) {
        // 1st parameter is the were the nonce is stored in the $_POST array or what the nonce from field name
        // 2nd parameter is the name of the nonce which is set up in wp_create_nonce()
        // 3rd parameter is die, if true and nonce fails they function will return false
        $ran = rand(0, 100);
      $return_string = 'string from JS: "'.$_POST["from_js"].'" random number from server: '.$ran.' nonce: '.$_POST["js_nonce"].' TEST SITE';
      echo $return_string;
      $return_string = 'nonce fail (ajax_test.php)';
        echo ($return_string);
add_action('wp_ajax_test_ajax', 'test_ajax_process_request');
add_action('wp_ajax_nopriv_test_ajax', 'test_ajax_process_request');

And my JS file: ajax_test.php

var $ = jQuery.noConflict();

$( document ).ready(function() {

    console.log('Nonce: '+wbs_ajax_obj.nonce+' from ajax_test.js');

      url: wbs_ajax_obj.ajax_url, // 'https://lomokev.com/ajaxtest'
      data: {
          action: "test_ajax", // name of the wordpress hook that will trigger function so in this case wp_ajax_nopriv_test_ajax and wp_ajax_test_ajax'
          js_nonce: wbs_ajax_obj.nonce,
          from_js: 'value of from_js from ajax_test.js'
      error: function(errorThrown){


    // if it's a 404 the error says "error"
    // but this says "Bad Request"


out from logged in and none logged in user

  • Have you considered using a REST API endpoint instead? They're much easier to debug, and much more secure – Tom J Nowell May 22 '18 at 14:13
  • I’ve also come to that conclusion myself it's just a little annoying because spent time learning how to do it this way ;-). – lomokev May 22 '18 at 15:02
  • Is there a chance that some other plugin already registered action wp_ajax_nopriv_test_ajax? It's a pretty common name, so there is such chance, I guess. In such case the response can be generated not by your function. You can change priority of your hook. – Krzysiek Dróżdż May 23 '18 at 5:45
  • 1
    @KrzysiekDróżdż I did it on a clean install so the hook was not clashing, that said it's a really good point test_ajax is an obvious name for ajax hook ;-) I did figure it out I had some code that was redirecting none logged in users away from the wp-admin which would include admin-ajax.php see my answer below if your interested. – lomokev May 23 '18 at 20:53

Found the solution, reason why it was returning HTML is because it was doing a 302 redirect to the home page.

Turns out that I had a function in my theme that redirects none logged in users away from the wp-admin pages which is where admin-ajax.php is.

    // IF SUSBSCIBER GOES TO ADMIN /wp-admin THEY ARE REDIRCTED TO THE HOME PAGE START : this code works as of 2018-01-29 (no plugins)

      * Redirect back to homepage and not allow access to
      * WP admin for Subscribers.

     function themeblvd_redirect_admin(){
          if ( ! current_user_can('delete_published_posts')) { // changed from edit_posts so that it works for contibuters to
               wp_redirect( site_url() );
     add_action( 'admin_init', 'themeblvd_redirect_admin' );

I have it there for testing, so if have testing with a holding page I allow clients to login using a subscriber account, once they are logged in they are redirected to the home page instead of seeing the there user page. I found the solution for this once I released it was a 302 redirect, I found this thread on the subject: https://stackoverflow.com/questions/9408334/wordpress-admin-ajax-results-in-error-302-redirect

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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