What you’re experiencing (AJAX works locally, but not on the server) there is a delay problem. Locally everything works that fast, that you can’t see your problem. In short, this is your problem:
AJAX callback (A) executes > AJAX Callback (B) doesn’t know that it has to wait for (A) > You can’t see the problem in your local install as (A) is finished too fast.
So you need to find a way how to tell your Callback (B) that it has to wait for (A). Here’s how:
Register Scripts and move data from PHP to JS
Register and enqueue and localize your data the right way: Wrap it in a function or method and hook it to wp_enqueue_scripts
(public/themes), login_enqueue_scripts
(password/login/register) or admin_enqueue_scripts
. The use wp_localize_script()
to move data from PHP to JS and make it accessible there.
add_action( 'admin_enqueue_scripts', 'wpse118772jsObject' );
function wpse118772jsObject()
{
$scriptHandle="custom-script-name";
// Should be divided into separate functions or methods
wp_register_script(
$scriptHandle,
plugins_url( __FILE__, 'your/path' ),
array( 'jquery' ),
plugin_dir_path( __FILE__ ).'your/path' ),
true
);
wp_enqueue_script( $scriptHandle );
wp_localize_script(
$scriptHandle,
'pluginObject',
array(
'ajaxURl' => admin_url( 'admin_ajax.php' ),
'custom' => array(
// custom data in here
),
),
);
}
How to use jQuery AJAX the proper way.
There’re several functions you can use: The default $.ajax({});
function or their shortcuts $.post();
, $.getJSON();
, etc.
So you can simply use something like the following – using the success/fail
object methods.
( function( $, plugin ) {
"use strict";
$.ajax( {
url : plugin.ajaxURl,
data : {
// other data
},
// We assume you're responding with a proper wp_send_json_success/error() in the PHP Cb.
dataType : "json",
// Request transformation possible in here.
beforeSend : function( xhr ) {
// Example:
// xhr.overrideMimeType( 'application/json' );
},
// The actual handlers
success : function( data, textStatus, jqXHR ) {
// Handle data transformation or DOM manipulation in here.
},
error : function( jqXHR, textStatus, errorThrown ) {
// silent: Log the error
console.info( errorThrown );
// loud: Throw Exception
throw errorThrown;
}
} );
} )( jQuery, pluginObject || {} );
If you want to go more in depth and do things really the right way, you’ll have to use method chaining. (There’s still room for improvement left).
( function( $, plugin ) {
"use strict";
$.ajax( {
url : plugin.ajaxURl,
data : {
// other data
},
} )
.done( function( data ) {
// Handles successful responses only
} )
.fail( function( reason ) {
// Handles errors only
console.debug( reason );
} )
.always( function( data, textStatus, response ) {
// If you want to manually separate stuff
// response becomes errorThrown/reason OR jqXHR in case of success
} )
.then( function( data, textStatus, response ) {
// In case your working with a deferred.promise, use this method
// Again, you'll have to manually separates success/error
} );
} )( jQuery, pluginObject || {} );
Note: For better examples of the wrapper around the callback, take a look at commonjs or AMD and their difference.
Waiting for other AJAX responses
The interesting – and most powerful part of the whole jQuery (and other libararies) AJAX handling – question is how to wait until A is finished to then start B and its processing. The answer is “deferred” loading and “promises”.
I’ll add a quick example. You should maybe think about building and object and separating stuff by appending it via this.
to the object, but for an example the following should be enough:
Example (A) This basically like I do it. You’ll have to fill the bits your own.
( function( $, plugin ) {
"use strict";
$.when(
$.ajax( {
url : pluginURl,
data : { /* ... */ }
} )
.done( function( data ) {
// 2nd call finished
} )
.fail( function( reason ) {
console.info( reason );
} )
)
// Again, you could leverage .done() as well. See jQuery docs.
.then(
// Success
function( response ) {
// Has been successful
// In case of more then one request, both have to be successful
},
// Fail
function( resons ) {
// Has thrown an error
// in case of multiple errors, it throws the first one
},
);
} )( jQuery, pluginObject || {} );
Example (B) I never tried it like this, but it should work as well. Easier to read, but I like $.when()
resolved promises more.
( function( $, plugin ) {
"use strict";
$.ajax( {
url : plugin.ajaxURl,
data : {
// other data
}
} )
.done( function( data ) {
// Handles successful responses only
} )
.fail( function( reason ) {
console.info( reason );
} )
// Promise finished:
.then( function( data ) {
$.ajax( {
url : pluginURl,
data : { /* ... */ }
} )
.done( function( data ) {
// 2nd call finished
} )
.fail( function( reason ) {
console.info( reason );
} );
} );
} )( jQuery, pluginObject || {} );
If you want to get even more in depth, read the Docs about deferred
and then
.
async/ await
EDIT As this answer receives quite some attention over the years and already is 8 years old, please take a look at the following snippet.
Keep in mind, that async/await
still deals with Promises. It’s just synthetic sugar. Also keep in mind what this
refers to, when using short hand functions like seen in handlerB()
.
That will even work with jQuery.
( function( $, plugin ) {
const handlerA = async function( plugin ) {
try {
let res = await $.ajax( {
url : plugin.ajaxURl,
data : { /* some data */ }
} )
.done( function( data ) {
// Handles successful responses only
} )
.fail( function( reason ) {
console.error( reason );
} )
return res;
} catch ( err ) {
console.error( err )
}
}
const handlerB = async data => { /* yet another AJAX request */ }
// Execute
// …wait…
let $resultA = await handlerA( plugin )
// Now exec B
let $resultB = await handlerB( $resultA )
// Do something with $resultB
} )( jQuery, pluginObject || {} );