NeuroAgent

Fix WordPress AJAX 400 Error: Complete Guide

Learn how to fix WordPress AJAX 400 errors with strict-origin-when-cross-origin issues. Complete troubleshooting guide covering common causes, CORS configuration, and step-by-step solutions for developers.

Troubleshooting WordPress AJAX 400 Error

I’m encountering a 400 error (strict-origin-when-cross-origin) with my WordPress AJAX implementation despite following standard practices. Here’s my code:

Plugin Setup

php
require_once( plugin_dir_path( __FILE__ ) . 'classes/duplicate_statement_controller.class.php' );

add_action( 'wp_enqueue_scripts', function(){
    wp_enqueue_style('duplicate-tax-css' , plugin_dir_url( __FILE__ ) . '/assets/duplicate-tax.css' );
    
    wp_enqueue_script( 'duplicate-tax-js', plugin_dir_url( __FILE__ ) . '/assets/duplicate-tax.js', array('jquery'), '1.0', true );
    
    wp_localize_script( 'duplicate-tax-js', 'tax_object',
        array(
            'ajax_url' => admin_url( 'admin-ajax.php' ),
            'nonce' => wp_create_nonce('tax-nonce')
        )
    );
} );

jQuery AJAX Call

javascript
$.ajax({
    url: tax_object.ajax_url,
    type: 'post',
    data: {
        action: 'add_row',
        nonce: tax_object.nonce
    },
  success: function (response) {
    // probably re-calc here
    console.log(response);
  }
});

PHP AJAX Handler

php
private function __construct() {
    //Wordpress hooks and filters
    add_action( 'init', array ( $this , 'action_init' ) );

    // Ajax actions for rows
    add_action('wp_ajax_add_row',  array( $this , 'add_row' ) );
    add_action('wp_ajax_nopriv_add_row',  array( $this , 'add_row' ) );
    add_action('wp_ajax_remove_row',  array( $this , 'remove_row' ) );
    add_action('wp_ajax_nopriv_remove_row',  array( $this , 'remove_row' ) );
}


public function add_row() {
    error_log("!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}

Problem Description

Every time I run this, I get a 400 error (strict-origin-when-cross-origin). I’ve registered the AJAX calls, used wp_enqueue and wp_localize_script, and included both wp_ajax and wp_ajax_nopriv hooks as recommended. The syntax appears correct, and this same code works in another plugin without issues.

What could be causing this 400 error, and how can I troubleshoot it further?

NeuroAgent

The WordPress AJAX 400 error with “strict-origin-when-cross-origin” indicates both a server-side 400 Bad Request response and a client-side CORS policy issue. This combination suggests your AJAX request isn’t reaching the server properly due to browser security restrictions, or the server is rejecting the request for specific reasons.

Based on your code and the research findings, here’s a comprehensive troubleshooting guide:

Contents

Understanding the Error Combination

The “400 error (strict-origin-when-cross-origin)” is actually two separate issues combined:

  1. 400 Bad Request: Server-side error indicating the request format is incorrect
  2. strict-origin-when-cross-origin: Browser security policy preventing cross-origin requests

As noted in the research findings, “that’s not one single error, that’s two.” The browser is likely blocking the request before it even reaches your server, or the server is rejecting it with a 400 status code.

Common Causes and Solutions

1. Action Parameter Issues

The most common cause of WordPress AJAX 400 errors is missing or incorrect action parameters:

javascript
// Your current code
data: {
    action: 'add_row',
    nonce: tax_object.nonce
}

Solution: Ensure the action parameter exactly matches what you registered. Double-check for typos and case sensitivity.

2. Content-Type Mismatch

Based on the research findings, the old admin-ajax.php endpoint doesn’t support JSON payloads:

“the contentType part in your JS script, which submits the form data as a JSON payload, but note that the old admin-ajax.php endpoint doesn’t support JSON payload, hence $_REQUEST[‘action’] would be empty”

Solution: Remove any contentType: 'application/json' from your AJAX call and let jQuery use the default application/x-www-form-urlencoded:

javascript
$.ajax({
    url: tax_object.ajax_url,
    type: 'post',
    data: {
        action: 'add_row',
        nonce: tax_object.nonce
    },
    // Remove contentType setting entirely
    success: function (response) {
        console.log(response);
    }
});

3. Hook Registration Timing

Your hooks are registered in the constructor, but they might be too late:

php
private function __construct() {
    add_action( 'init', array ( $this , 'action_init' ) );
    // AJAX hooks here
}

Solution: Move the AJAX hook registration earlier in the load process:

php
add_action( 'plugins_loaded', array( $this, 'init' ) );

private function init() {
    // Register AJAX hooks immediately
    add_action('wp_ajax_add_row', array( $this, 'add_row' ));
    add_action('wp_ajax_nopriv_add_row', array( $this, 'add_row' ));
}

Step-by-Step Troubleshooting

Step 1: Basic Verification

  1. Check browser network tab: Look at the actual request details in your browser’s developer tools
  2. Verify action parameter: Ensure action: 'add_row' matches your registered hook exactly
  3. Test with simplified request: Remove the nonce temporarily to isolate the issue
javascript
// Test without nonce
$.ajax({
    url: tax_object.ajax_url,
    type: 'post',
    data: {
        action: 'add_row'
    },
    success: function (response) {
        console.log(response);
    }
});

Step 2: Debug Server Response

Add debugging to your PHP handler:

php
public function add_row() {
    // Log all received data
    error_log("Received data: " . print_r($_REQUEST, true));
    error_log("Action: " . $_REQUEST['action']);
    
    // Return something to test
    wp_send_json_success('Hello World');
}

Step 3: Check for Plugin Conflicts

As recommended in the research findings:

“Check if the issue persists when deactivating all plugins or switching to a default WordPress theme”

  1. Deactivate all plugins except yours
  2. Switch to a default theme (like Twenty Twenty-Four)
  3. Test the AJAX call
  4. If it works, re-enable plugins one by one to find the conflict

Step 4: Reset Permalinks

Corrupted permalink settings can cause 400 errors:

  1. Go to Settings > Permalinks
  2. Don’t make any changes, just click “Save Changes”
  3. Test your AJAX call again

Advanced CORS Configuration

If you’re making cross-origin requests, you’ll need to configure CORS headers:

Method 1: Using WordPress Filters

php
add_filter('allowed_http_origins', function($origins) {
    // Add your domain
    $origins[] = 'https://yourdomain.com';
    return $origins;
});

add_filter('wp_headers', function($headers) {
    $headers['Access-Control-Allow-Origin'] = 'https://yourdomain.com';
    $headers['Access-Control-Allow-Credentials'] = 'true';
    return $headers;
});

Method 2: Using .htaccess (for Apache)

apache
<IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "https://yourdomain.com"
    Header set Access-Control-Allow-Credentials "true"
</IfModule>

Method 3: Using PHP in theme functions

php
add_action('send_headers', function() {
    header('Access-Control-Allow-Origin: https://yourdomain.com');
    header('Access-Control-Allow-Credentials: true');
});

Plugin and Theme Conflicts

If the issue persists after basic troubleshooting:

  1. Check for JavaScript conflicts: Look for other scripts that might be interfering
  2. Verify nonce implementation: Ensure your nonce is properly created and verified
  3. Check server logs: Look for PHP errors or warnings

Alternative Approaches

1. Use WordPress REST API

Consider migrating to the modern WordPress REST API instead of the legacy admin-ajax.php:

javascript
fetch('/wp-json/wp/v2/posts', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-WP-Nonce': wpApiSettings.nonce
    },
    body: JSON.stringify({
        title: 'Hello World'
    })
})

2. Frontend-Only Solution

If your AJAX call doesn’t require WordPress backend processing, consider handling it entirely on the frontend:

javascript
// Process data without server roundtrip
function addRow() {
    // Your frontend logic here
    console.log('Row added');
}

3. Check Server Configuration

If you’re on a local development environment like MAMP, server configuration might be causing issues:

  • Check PHP error logs
  • Verify server modules are enabled
  • Ensure proper file permissions

Remember that the “strict-origin-when-cross-origin” error is primarily a browser security feature, so focus first on ensuring your request format is correct before diving into CORS configuration. The 400 error suggests the server is rejecting your request before it can even process the CORS headers.

Sources

  1. Stack Overflow - Getting a 400 error with WordPress AJAX call
  2. WordPress Stack Exchange - Cannot load admin-ajax.php
  3. Expertrec - Troubleshooting Admin-ajax.php 400 Error
  4. WPBeginner - Fix WordPress Admin Ajax 400 Error
  5. WordPress Stack Exchange - admin-ajax.php 400 bad request
  6. 24x7 WP Support - Fix WordPress admin-ajax.php 400 Error

Conclusion

The WordPress AJAX 400 error with “strict-origin-when-cross-origin” typically stems from one of these issues:

  1. Incorrect action parameter leading to server rejection
  2. Content-Type mismatch between frontend and backend expectations
  3. CORS policy blocking cross-origin requests
  4. Plugin or theme conflicts interfering with AJAX execution
  5. Improper hook registration timing

Start with the simplest troubleshooting steps: verify your action parameter, remove any custom content-type settings, and test with a minimal request. If the issue persists, investigate plugin conflicts and CORS configuration. Consider migrating to the WordPress REST API for a more modern approach if you continue to face issues with the legacy admin-ajax.php endpoint.