Plugin: AJAX query external API to sync to tables

I’m planning to write a plugin that hooks into an external API and syncs to a couple of database tables some information.

I want to do this in a best practice way if there is one. I want the user to be able to click a button under the admin options for the plugin and do it manually as an option via cron.

I suppose it could take a few minutes the process, so was thinking about using some sort of button and attaching an action to be commenced using jQuery to fire off via AJAX and put some sort of timer up until complete.

For some reason I’m struggling to think of what way to achieve this and was hoping for a bit of direction on best practice way using WP features rather than a hack job. Had my eye out of plugin development for a while trying to find my feet again.

Solutions Collecting From Web of "Plugin: AJAX query external API to sync to tables"

Sketch/Concept

To make requests to remote/external APIs, use the WP HTTP API. More in depth examples/details can be found in some of my answers here.

Then simply add an admin page with add_submenu_page() or add_menu_page() or the related functions.

Finally add a script via wp_register/enqueue_script() on the admin_enqueue_scripts-hook. There you fire an ajax (search archives) call and update your tables.

Use ajax in plugins

It’s pretty simple. Here’s a quick mockup. It shows everything that is needed to do every possible AJAX call. I splitted up the registration and the queuing of the script so you can enqueue the script when and where ever you need.

Nonces

Nonces and referrer checks are already implemented for security. It uses a constant naming scheme so it gets less confusing (especially with the nonce checks).

OOP construct with a shared name

The PHP:

class WPSEexampleAJAX
{
    public $name = 'wpse';

    public function __construct()
    {
        add_action( 'wp_loaded', array( $this, 'scriptsRegister' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'scriptsEnqueue' ) );

        // Logged in users - everybody in Admin
        add_action( "wp_ajax_{$this->name}_action", array( $this, 'ajaxCb' ) );
        // Guests/not logged in
        add_action( "wp_ajax_nopriv_{$this->name}_action", array( $this, 'ajaxCb' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'scriptsLocalize' ) );
    }

    public function scriptsRegister( $page )
    {
        $file = 'WPSEexample.js';
        wp_register_script(
            $this->name,
            plugins_url( "assets/scripts/{$file}", __FILE__ ),
            array(
                'jquery',
                // 'add other possible dependencies in here',
            ),
            filemtime( plugin_dir_path( __FILE__ )."assets/scripts/{$file}" ),
            true
        );
    }

    public function scriptsEnqueue( $page )
    {
        wp_enqueue_script( $this->name );
    }

    public function scriptsLocalize( $page )
    {
        wp_localize_script( $this->name, "{$this->name}Object", array(
            'ajaxurl'          => admin_url( 'admin-ajax.php' ),
            '_ajax_nonce'      => wp_create_nonce( "{$this->name}_action" ),
            'action'           => "{$this->name}_action",
            'post_type'        => get_current_screen()->post_type,
            // 'foo'              => 'bar',
        ) );
    }

    public function ajaxCb()
    {
        $data = array_map( 'esc_attr', $_GET );

        check_ajax_referer( $data['action'] );

        // DO STUFF IN HERE

        wp_send_json_success( array(
            // 'foo' => 'bar',
        ) );
    }
}

The JavaScript an actual AJAX send/catch

Inside your registered JavaScript file, you just fire the ajax call and retrieve the result. Nowadays you got different points where you can intercept or catch the result. The script isn’t really doing anything, but just logging into the console. The wpseObject that was localized has an alias in the function call, so you can simply use plugin instead. I like doing it that way, so I can easily identify the localized object later on (also shorter to write). It’s just my personal naming convention.

( function( $, plugin ) {
    "use strict";

        $.ajax( {
            url  : plugin.ajaxurl,
            data : {
                action      : plugin.action,
                _ajax_nonce : plugin._ajax_nonce,
                foo         : plugin.foo,
            },
            beforeSend : function( d ) {
                console.log( 'AJAX Before send', d );
            }
        } )
            .done( function( response, textStatus, jqXHR ) {
                // console.log( 'AJAX done', data, textStatus, jqXHR, jqXHR.getAllResponseHeaders() );
            } )
            .fail( function( jqXHR, textStatus, errorThrown ) {
                console.log( 'AJAX failed', jqXHR.getAllResponseHeaders(), textStatus, errorThrown );
            } )
            .then( function( jqXHR, textStatus, errorThrown ) {
                console.log( 'AJAX after', jqXHR, textStatus, errorThrown );
            } );
} )( jQuery || {}, wpseObject || {} );

More info on the different parts for the $.ajax() call in the official jQuery documentation.

Hint: Make sure you always use jQuery from WordPress core and no CDN version. Else you’ll likely hit a wall with conflicts or outdated versions in case a user updates core, but not your plugin.