Retrieve POST data from AJAX call

Problem

“Serialization” is the act of turning a data-object into a string-representation. jQuery automatically serializes the data property before sending an AJAX request. The server then deserializes the GET querystring from the URL, and the request body for POST requests before populating PHP’s request variables.

Your code functioned as expected when data consisted solely of your serialized form data (i.e. data: newFormRecherche,) as the data was already in a string format, and thus could not be further serialized. The server’s deserialization pass then properly parsed your form data into request variables.

However, when the data argument is an object jQuery must serialize it in order to pass it to a server. As a property of that object, your pre-serialized form data is handled as though it were any other string – specifically, it is escaped in such a manner to prevent it from being “mistaken” for a serialized object. So when the server then deserializes data, newFormRecherche is deserialized into the value which jQuery originally received it as – that is, a string – and thus requires the second pass of deserialization that @czerspalace alluded to in the comments in order to produce an associative array of form data.


Solutions

– jQuery

To prevent the double-serialization of your form data, acquire it as an array of key/value pairs instead of a serialized string by invoking jQuery’s .serializeArray() method on the form element instead of .serialize().

While jQuery is capable of properly serializing this key/value-array-format of data, it seems it chokes when such an array is nested as property of a data object (instead sending the string '[object Object]' in place of each key/value pair), as well as when attempting to nest such a key/value-array inside another. As such, I think the best way to send form data as a part of multi-dimensional data is to convert the key/value-array into an object.

All of this can be done as follows:

function ajaxSubmit() {
  var newFormRecherche = jQuery( this ).serializeArray();

  jQuery.ajax({
    type:"POST",
    data: { 
      action: "mon_action",
      newFormRecherche: formFieldsToObject( newFormRecherche )
    },
    url: ajaxurl,
    success: function( response ){
      console.log( response );
    }
  });

  return false;
}

function formFieldsToObject( fields ) {
  var product = {};

  for( var i = 0; i < fields.length; i++ ) {
    var field = fields[ i ];

    if( ! product.hasOwnProperty( field.name ) ) {
      product[ field.name ] = field.value;
    }
    else {
      if( ! product[ field.name ] instanceof Array )
        product[ field.name ] = [ product[ field.name ] ];

      product[ field.name ].push( field.value );
    }
  }

  return product;
}

– HTML5 FormData

Alternately, if you need only support modern browsers or don’t mind loading a polyfill to support older ones, just use the FormData object to pass your form data as a proper data object:

function ajaxSubmit() {
  var newFormRecherche = new FormData( this );

  jQuery.ajax({
    type:"POST",
    data: { 
      action: "mon_action",
      newFormRecherche: newFormRecherche
    },
    url: ajaxurl,
    success: function( response ){
      console.log( response );
    }
  });

  return false;
}

– Server-Side Double-Deserialization

As @czerspalace suggests in the comments, accounting for the double-serialization by simply manually deserializing the form data on the server is also an entirely valid solution:

add_action( 'wp_ajax_mon_action', 'mon_action' );
add_action( 'wp_ajax_nopriv_mon_action', 'mon_action' );

function mon_action() {
  if( isset( $_POST[ 'newFormRecherche' ] ) ) {
    parse_str( $_POST[ 'newFormRecherche' ], $newFormRecherche );
    die( json_encode( $newFormRecherche ) );
  }
}

I’m inclined to think that the other approaches are more “professional” in that all of the data sent to the server is packaged in a consistent and expected format – no additional “decoding” is necessary on the server’s part, improving code modularity.

But code modularity and subjective “professionalism” aren’t always the most important factors – sometimes the most simple solution is the most appropriate.


Remember to validate and sanitize request
data

on the server before you use it in order to mitigate security vulnerabilities.

Leave a Comment