How to use JSONP (AJAX to SSL) in WordPress, an EASIER way


I’ve already written about How to use JSONP in WordPress Development. I explain how it works, and why you would use it there.

At work we work with several domains and I’ve had to use quite a bit of JSONP, I’ve rethought how to use it, and made this micro-framework to make it a LOT easier. Mostly, I wrote this to solve the problem that I’m using a lot of AJAX, and don’t want the overhead of the .ajax call each time.

There are a lot of values you need to set when making a JSONP call in general, and specifically with WordPress, this greases those wheels.

The paradigm is all you do is execute:

wp_jsonp("wp_jsonp", "getStuff", {variable: "hello world"}, getStuff);

and the rest is taken care of on the JS side. I wrote it to be agnostic of the server-side processing as well, this gives you the benefit of a pseudo factory design pattern with your switch statement.

You can download the whole repo to peruse or play with if you like, I made some gists for easy embedding.

This is the guts of the operation, I created this javascript object that handles everything, you past the ajax event, method, parameters and a callback function. The plugin takes care of the nitty gritty details that are a pain to remember for getting jsonp to work.

It’s well commented, so read through and feel free to ask questions in the comments if you have any.

if (typeof wp_jsonp === 'undefined')
    var wp_jsonp = function (event, method, params, callbackFunc) {
        // data needed to send jsonp
        var data = {
            action: event,	// wp ajax action
            ajaxSSLNonce: wp_jsonp_vars.wpAJAXNonce, // nonce
            method: method, // server has switch/case for processing
            params: params // data to be processed
        };

        jQuery.ajax({
            type: "GET", // this is the essence of jsonp
            url: wp_jsonp_vars.ajaxurl, // wp ajax url
            cache: false, // to ensure proper data response
            dataType: "jsonp", // jsonp
            crossDomain: true, // enable ssl/nonssl
            data: data, // data to be sent

            success: function (response) {
                //console.log('success', response);
                // your callback function
                callbackFunc(response);
            },

            complete: function (response) {
                //console.log('complete', response);
            },

            error: function (response) {
                console.log('error', response);
            }
        });
    };
<?php

/**
 * Plugin Name: WordPress JSONp Helper
 * Plugin URI: http://www.jackreichert.com/2015/07/02/how-to-jsonp-ajax-to-ssl-in-wordpress-an-easier-way/
 * Description: A paradigm for easy AJAX over SSL in WordPress using JSONP.
 * Version: 0.1
 * Author: jackreichert
 * Author URI: http://www.jackreichert.com/
 * License: GPL3
 */
class WP_AJAX_JSONp {
	// actions on instatiation
	function __construct() {
		add_action( 'wp_enqueue_scripts', array( $this, 'wp_jsonp_scripts' ) );
	}

	// enqueue scripts
	function wp_jsonp_scripts() {
		wp_enqueue_script( 'wp_jsonp_script', plugins_url( '/jsonp.js', __FILE__ ), array( 'jquery' ) );
		wp_localize_script( 'wp_jsonp_script', 'wp_jsonp_vars', array(
			'ajaxurl'     => admin_url( 'admin-ajax.php' ),
			'wpAJAXNonce' => wp_create_nonce( 'wpAJAX-nonce' )
		) );
	}
}

$WP_AJAX_JSONp = new WP_AJAX_JSONp();

Here’s the example, you might say, wait a minute, don’t you get a callback from jQuery already? Sure, good luck using it. It’s a little funny ignoring that, but hey, this works nicely.

<?php

/**
 * Plugin Name: another plugin
 * Plugin URI: http://www.jackreichert.com/2015/07/02/how-to-jsonp-ajax-to-ssl-in-wordpress-an-easier-way/
 * Description: An example of how you might use wp_jsonp.
 * Version: 0.1
 * Author: jackreichert
 * Author URI: http://www.jackreichert.com/
 * License: GPL3
 */
class Another_Plugin {
	// actions on instatiation
	function __construct() {
		include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
		if ( is_plugin_active( 'jsonp/jsonp.php' ) ) { // plugin is active? Great we can use it!
			add_action( 'wp_enqueue_scripts', array( $this, 'plugin_scripts' ) );
			add_action( 'wp_ajax_wp_jsonp', array( $this, 'wp_jsonp_func' ) );
			add_action( 'wp_ajax_nopriv_wp_jsonp', array( $this, 'wp_jsonp_func' ) );
		}
	}

	// enqueue scripts
	function plugin_scripts() {
		wp_enqueue_script( 'wp_jsonp_call', plugins_url( '/scripts.js', __FILE__ ), array( 'wp_jsonp_script' ) );
	}

	// process the ajax calls
	function wp_jsonp_func() {
		if ( ! wp_verify_nonce( $_GET['ajaxSSLNonce'], 'wpAJAX-nonce' ) ) {
			die ( 'Busted!' );
		}

		$response = array();
		$method   = $_GET['method'];

		/**
		 * Send what should be processed here.
		 * Note: since you are sending the method via ajax, you MUST validate your data.
		 * If you don't you probably should check your SQL queries because you probably don't sanitize those either.
		 */
		switch ( $method ) {
			case 'getStuff':
				// if you get "hello world back, then it worked"
				$response = "Hello World";
				break;
			default:
				$response = "You didn't send any methods to process your variables?!";
				break;
		}

		// response output
		header( "content-type: text/javascript; charset=utf-8" ); // We're sending back a javascript function, remember?
		header( "access-control-allow-origin: *" ); // This is needed for JSONP.
		echo htmlspecialchars( $_GET['callback'] ) . '(' . json_encode( $response ) . ')'; // jQuery set up the callback for us.

		// IMPORTANT: don't forget to "exit"
		exit;
	}
}

$Another_Plugin = new Another_Plugin();
jQuery(document).ready(function ($) {
    // client side response processing of getStuff response
    var getStuff = function (response) {
        console.log(response);
    }

    jQuery(document).ready(function (e) {
        // make the jsonp call: ajax_action, method, variables, callback
        wp_jsonp("wp_jsonp", "getStuff", {variable: "hello world"}, getStuff);
    });
});

Maybe I’m overthinking / over-complicating things, I don’t know, once it’s set up you can move really quickly, isn’t that the point of a framework?

Just one important note: make sure to validate the hell out of things because you’re giving that JS function a LOT of power.

I’d love to hear your thoughts, if you have suggestions for improving it, by all means, please comment below!