Ryan4021
7/25/2016 - 7:22 PM

AJAX in WordPress. Class based example.

AJAX in WordPress. Class based example.

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

	// Working with promises to bubble event later than core.
	$.when( someObjectWithEvents ).done( function() {
		console.log( 'AJAX request done.' );
	} )
		.then( function() {
			setTimeout( function() {
				console.log( 'AJAX requests resolved.' );
			}, 500 );
		} );

	// Same as above, but happens as onClick Action
	$( '#form-button' ).on( 'click', function() {
		// Debug: return; here if we need to debug/var_dump the save_post callback in PHP.
		// return;

		// Working with promises to bubble event later than core.
		$.when( someObjectWithEvents ).done( function() {
			setTimeout( function() {
				console.log( 'AJAX requests done. Happened after onClick event.' );
			}, 2000 );
		} );
		// One can happily use .then() here as well.
	} );

	// Alternate solution: jQuery.ajax()
	// One can use $.post(), $.getJSON() as well
	// I prefer defered loading & promises as shown above
	$.ajax( {
		 url  : plugin.ajaxurl,
		 data : {
			action      : plugin.action,
			_ajax_nonce : plugin._ajax_nonce,
			// WordPress JS-global
			// Only set in admin
			postType     : typenow,
		 },
		 beforeSend : function( d ) {
		 	console.log( 'Before send', d );
		 }
	} )
		.done( function( response, textStatus, jqXHR ) {
			console.log( 'AJAX done', 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 finished', jqXHR, textStatus, errorThrown );
		} );
} )( jQuery, ajaxexampleObject || {} );
<?php
/** Plugin Name: (WCM) AJAX Example Plugin */

add_action( 'plugins_loaded', array( 'PoorMansNameSpaceAJAX', 'getInstance' ) );
class PoorMansNameSpaceAJAX
{
	public static $instance = null;

	public $nonce = '';

	public $name = 'ajaxexample';

	public static function getInstance()
	{
		null === self::$instance AND self::$instance = new self;
		return self::$instance;
	}

	public function __construct()
	{
		add_action( 'wp_loaded', array( $this, 'scriptsRegister' ) );
		# Could as well be: wp_enqueue_scripts or login_enqueue_scripts
		add_action( 'admin_enqueue_scripts', array( $this, 'scriptsEnqueue' ) );

		# Logged in users:
		# add_action( "wp_ajax_{$this->name}_action", array( $this, 'ajaxCb' ) );
		# Guests:
		add_action( "wp_ajax_nopriv_{$this->name}_action", array( $this, 'ajaxCb' ) );

		add_action( 'admin_enqueue_scripts', array( $this, 'scriptsLocalize' ) );
	}

	public function scriptsRegister( $page )
	{
		$file = 'ajax.js';
		wp_register_script(
			$this->name,
			plugins_url( $file, __FILE__ ),
			array(
				'jquery',
			),
			filemtime( plugin_dir_path( __FILE__ )."/{$file}" ),
			true
		);
	}

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

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

	public function renderForm()
	{
		wp_nonce_field( "{$this->name}_action", $this->name );
		# @TODO Build form
		# @TODO Hook somewhere
	}

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

		! check_ajax_referer( $data['action'], "_ajax_nonce", false )
			AND wp_send_json_error();

		# @TODO Handle processing of data in here
		# @TODO Validate data with absint(), esc_*(), etc.

		# @example #2)
		if ( ! $data['foo'] )
			wp_send_json_error();

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