Creating Ajax backend for Specialised Page Template? Should admin-ajax.php be used?

Custom implementation vs. Standard API usage

Using the WP AJAX API is the way to go. First off, you get access to the complete set of WP APIs, you can leverage standard jQuery $.ajax() and similar API calls and you are running standard conform, gaining access to all knowledge spread around the web with articles or for e.g. in answers on this site. In the short term, you might think you are faster, but in the long term you are just cutting yourself off of all help sources.

Example: Debugging

You will have to implement custom debugging routes, while WordPress AJAX has lots of sources that will help you getting around it.

External Database

The best thing to do is to use the $wpdb class.

class CustomDatabaseHandler extends wpdb
{
    // Overwrite what you need here
}

More info in this answer.

Overhead?

The main “problem”/performance drawback when using WP AJAX is that every request to admin-ajax.php actually reloads the whole WordPress core. This file can be replaced, as shown by @Rarst in this answer with a custom file that reduces the impact and only loads what you need.

Custom Application

As I am doing it on a day to day basis: It’s no problem developing your application outside of WordPress and then simply pulling it in via Composer (or whatever package manager you are using) and loading it from a simple single file in your plugins folder that has nothing than a call to require our autoloader, a controller and a header comment that declares it as a plugin.

<?php
/** Plugin Name: Custom Application as Plugin */

# Composer autoloader
include_once __DIR__.'/vendor/autoload.php';

add_action( 'plugins_loaded', function()
{
    // Initialize your plugin here
} );

That’s all you need.

Web Applications

If you are running an Angular.js, Ember or Backbone WeApp it’s no problem. WP AJAX will work with that without a problem.

Security

WordPress reuses its nonces, which is a well known fact. This does not really expose anything or open a security whole, but you can go one step further and generate a new nonce [for every request as well], making your calls … ubersecure.

Basics

As it doesn’t make sense to repeat other answers, simply read through , look at my example GitHub Gist or my other GitHub Gist that shows different implementations to show that callbacks can be attached in any possible way.

Overall, your plugin won’t do much than the following:

// Public or private?
// 'wp_enqueue_scripts"https://wordpress.stackexchange.com/"admin_enqueue_scripts'
// or only on login?
// 'login_enqueue_scripts'
add_action( 'wp_enqueue_scripts', function()
{
    $name="handle";
    wp_register_script(
        $name,
        plugins_url( 'assets/ajax.js', __FILE__ ),
        [ 'jquery' ],
        filemtime( plugins_dir_path( __FILE__ ).'assets/ajax.js' ),
        true
    );
    wp_enqueue_script( $name );
    wp_localize_script(
        $name,
        "{$name}Obj", // This string is what gives you access to below array
        [
            'ajaxurl'     => admin_url( 'admin-ajax.php' ),
            '_ajax_nonce' => wp_create_nonce( "{$name}_action" ),
            'action'      => "{$name}_action",
            'data'        => [ /* additional data as array */ ],
        ]
    );
} );

You just register that and your AJAX callback and you are done:

// Public or private?
add_action( "wp_ajax_{$name}_action", 'ajaxCb' );
add_action( "wp_ajax_nopriv_{$name}_action", 'ajaxCb' );

public function ajaxCb( $data )
{
    check_ajax_referer( $data['action'] );

    # @TODO sanitize data here:
    // filter_var() filter_var_array() and filter_input()
    # @TODO Custom logic here

    // Error?
    if ( is_wp_error( $thing ) )
        wp_send_json_error( $data );

    // Success!
    wp_send_json_success( $data );
}

Note: Comprehensive example Gist on how to sanitize using filter_var_array().

And you AJAX.js file will look close to the following:

/*global jQuery, $, handleObj */
( function( $, plugin ) {
    "use strict";
        var pass = $( '#password__field' ).val(),
            name = $( '#name__field' ).val();

        // @TODO other setup tasks for static vars in here

        $.ajax( {
            url  : plugin.ajaxurl,
            data : {
                action      : plugin.action,
                _ajax_nonce : plugin._ajax_nonce,
                userName    : name,
                passWord    : pass
            },
            beforeSend : function( d ) {
                // @TODO Add loading animation
            }
        } )
            .done( function( response, textStatus, jqXHR ) {
                // @TODO Clear loading animation
                if ( ! response.success ) {
                    // @TODO Custom error
                }
                else {
                    // @TODO success
                }
            } )
            .fail( function( jqXHR, textStatus, errorThrown ) {
                console.log( errorThrown );
            } );
} ( jQuery, handleObj || {} ) );

There’s not really much more to do aside from filling in the gaps/your application logic into what is shown above in code.

Leave a Comment