admin-ajax.php doesn’t work when using POST data and Axios

I’m trying to create an email signup form with an AJAX request.

Early on I found that WordPress empties the $_POST variable by default. I tried using admin_post and admin_post_nopriv but neither of those seemed to be working. I’m now trying the following:

add_action('wp_ajax_nopriv_newsletter', 'subscribeToNewsletter');
add_action('wp_ajax_newsletter', 'subscribeToNewsletter');

function subscribeToNewsletter()
{

  echo json_encode([ 'success' => true ]);

In my JavaScript, if I use the following:

axios
  .post('/wp-admin/admin-ajax.php', {
    'email' : '[email protected]',
    'action' : 'newsletter',
  })
  .then(response => {
    console.log(response.data);
  });

I get a 400 bad request and a 0 returned. If I change it to:

axios
  .get('/wp-admin/[email protected]&action=newsletter')
  .then(response => {
    console.log(response.data);
  });

everything works.

Can admin-ajax.php not handle POST requests? I don’t want to use a GET request* for subscribing someone to a newsletter, and I’d like to do it over AJAX.


*From W3 schools (which normally I hate but has a good overview on requests):

Some other notes on GET requests:

  • GET requests can be cached
  • GET requests remain in the browser history
  • GET requests can be bookmarked
  • GET requests should never be used when dealing with sensitive data
  • GET requests have length restrictions
  • GET requests is only used to request data (not modify)

1 Answer
1

The issue here, I think, is how axios works. Not WordPress. But you’re absolutely correct to want to use a POST request here.

By default I believe axios sends data in a POST request as JSON in the body. To get JSON in the body of the request in PHP you need to do this (from here):

$inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); //convert JSON into array

The problem with that is that for the wp_ajax_ hooks to work, WordPress looks for the action in $_REQUEST['action']. This won’t be set if the action name is part of the request body, since $_REQUEST isn’t populated when the data is sent as JSON.

I believe that if you want to send POST data in axios the way a form does, and access it with $_POST or $_REQUEST, then you need to send it as FormData in the script:

var data = new FormData();

data.append('email', '[email protected]');
data.append('action', 'newsletter');

axios
    .post('/wp-admin/admin-ajax.php', data)
    .then(response => {
        console.log(response.data);
    });

PS: Just so you’re aware, this syntax: response => {, won’t work in any version of IE.

Leave a Comment