Created
August 13, 2015 21:14
-
-
Save wpsmith/6fd1ae9c87ec53d762bd to your computer and use it in GitHub Desktop.
PHP/JS: WordPress Ajax as OOP.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: TGM API Helper | |
* Plugin URI: https://thomasgriffin.io | |
* Description: Whitelists the plugins to be loaded during API requests to reduce overhead. | |
* Author: Thomas Griffin | |
* Author URI: https://thomasgriffin.io | |
* Version: 1.0.0 | |
*/ | |
// Make sure we can target a valid URI endpoint. | |
if ( ! isset( $_SERVER['REQUEST_URI'] ) ) { | |
return; | |
} | |
// Make sure that the endpoint being requested matches a valid API endpoint. | |
if ( strpos( stripslashes( $_SERVER['REQUEST_URI'] ), '/api/v1/' ) === false ) { | |
return; | |
} | |
// Define a constant that we can make use of in any API plugins we create. | |
define( 'TGM_API_REQUEST', true ); | |
// Now that we know this is an API request, let's filter available plugins. | |
add_filter( 'pre_option_active_plugins', 'tgm_whitelist_active_plugins' ); | |
/** | |
* Filters the plugins that should be loaded during this request to reduce overhead. | |
* | |
* since 1.0.0 | |
* | |
* @param array $plugins The active plugins to be loaded in the request. | |
* @retun array $whitelist Whitelisted plugins that should only be loaded during the request. | |
*/ | |
function tgm_whitelist_active_plugins( $plugins ) { | |
// This is my base API plugin to handle all API routes. I want this loaded before everything else. | |
$whitelist = array( | |
'api-routes/api-routes.php' | |
); | |
// You can easily conditionally load plugins based on the URI path. Here is an example for an API endpoint called "update". | |
if ( strpos( stripslashes( $_SERVER['REQUEST_URI'] ), '/api/v1/update/' ) !== false ) { | |
$whitelist[] = 'api-update-helper/api-update-helper.php'; | |
} | |
// Finally, we can load any API plugin that depends on all the others last. | |
$whitelist[] = 'api-depends/api-depends.php'; | |
// Return the whitelist instead of the default plugins. | |
return $whitelist; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* WP Ajax Abstract Class. | |
* | |
* @package WPS_Core | |
* @author Travis Smith <t@wpsmith.net> | |
* @copyright 2014 Travis Smith | |
* @license GPL-2.0+ | |
*/ | |
/** | |
* WPS_Ajax class. | |
* | |
* @package WPS_Core | |
* @author Travis Smith <t@wpsmith.net> | |
*/ | |
class WPS_Ajax { | |
/** | |
* WP Nounce | |
* | |
* @var string | |
*/ | |
protected $nonce = ''; | |
/** | |
* WP AJAX Name | |
* | |
* @var string | |
*/ | |
protected $name = ''; | |
/** | |
* Whether to hook AJAX callback into front-end. | |
* | |
* @var string | |
*/ | |
protected $nopriv = false; | |
/** | |
* Hook for scripts. | |
* Could be: wp_enqueue_scripts or login_enqueue_scripts or admin_enqueue_scripts | |
* | |
* @var string | |
*/ | |
protected $script_hook = 'admin_enqueue_scripts'; | |
/** | |
* Whether to keep the WP Heartbeat script. | |
* | |
* @var string | |
*/ | |
protected $heartbeat = true; | |
/** | |
* AJAX callback function name. | |
* | |
* @var string | |
*/ | |
protected $callback; | |
/** | |
* Constructor | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @param string $name Name (lower-case, without spaces, use underscore) of the WP Action | |
* @param array $script Array of script information: url, src (path), data (localized info). | |
* @return void. | |
*/ | |
public function __construct( $name, $script = array(), $callback ) { | |
$this->name = str_replace( ' ', '_', strtolower( $name ) ); | |
// if not doing ajax, load script | |
if ( ( defined( 'DOING_AJAX' ) && !DOING_AJAX ) || !defined( 'DOING_AJAX' ) ) { | |
$this->maybe_do_action( 'plugins_loaded', 'script' ); | |
} | |
// Hook up AJAX Action | |
$this->maybe_do_action( 'plugins_loaded', 'init' ); | |
// Hook into secured callback | |
add_action( "{$this->name}_wp_ajax_action", $callback ); | |
} | |
/** | |
* Sets object parameters. | |
* Available parameters: nopriv, script_hook, callback | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @param string $param Parameter name. | |
* @param mixed $value Value of parameter. | |
* @return void. | |
*/ | |
public function set( $param, $value ) { | |
switch ( $param ) { | |
case 'nopriv': | |
$this->nopriv = (bool) $value; | |
break; | |
case 'heartbeat': | |
$this->heartbeat = (bool) $value; | |
break; | |
case 'script_hook': | |
$hooks = array( | |
'wp_enqueue_scripts', | |
'login_enqueue_scripts', | |
'admin_enqueue_scripts', | |
); | |
if ( in_array( $value, $hooks ) ) { | |
$this->script_hook = strtolower( $value ); | |
} | |
break; | |
case 'callback': | |
if ( is_callable( $value ) ) { | |
$this->callback = $value; | |
} | |
break; | |
} | |
} | |
/** | |
* Gets object parameter. | |
* Available parameters: nopriv, script_hook, callback | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @param string $param Parameter name. | |
* @return mixed Value of parameter. | |
*/ | |
public function get( $param ) { | |
switch ( $param ) { | |
case 'nopriv': | |
return (bool)$this->nopriv; | |
case 'heartbeat': | |
return (bool)$this->heartbeat; | |
case 'script_hook': | |
return (string)$this->script_hook; | |
case 'callback': | |
return (string)$this->callback; | |
default: | |
return null; | |
} | |
} | |
/** | |
* Hooks up AJAX Action | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @return void. | |
*/ | |
protected function init() { | |
add_action( "wp_ajax_{$this->name}_action", array( $this, 'callback' ) ); | |
if ( $this->nopriv ) { | |
add_action( "wp_ajax_nopriv_{$this->name}_action", array( $this, 'callback' ) ); | |
} | |
} | |
/** | |
* Hooks action or executes action. | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @param string WordPress action to be checked with did_action(). | |
* @param string|array Function name/array to be called. | |
* @return void. | |
*/ | |
private function maybe_do_action( $hook, $action ) { | |
if ( !did_action( $hook ) ) { | |
add_action( $hook, array( $this, $action ) ); | |
} elseif ( is_callable( $action ) ) { | |
call_user_func( $action ); | |
} | |
} | |
/** | |
* Performs script operations: register, localize, and enqueue. | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @return void. | |
*/ | |
public function script() { | |
// Register Script | |
add_action( 'wp_loaded', array( $this, 'register' ) ); | |
// Make sure we hook scripts in proper place & prevent user error. | |
if ( $this->nopriv && 'admin_enqueue_scripts' === $this->script_hook ) { | |
$this->script_hook = 'wp_enqueue_scripts'; | |
} | |
// Go SCRIPT! | |
add_action( $this->script_hook, array( $this, 'localize' ) ); | |
add_action( $this->script_hook, array( $this, 'enqueue' ) ); | |
if ( !$this->heartbeat ) { | |
add_action( 'admin_enqueue_scripts', array( $this, 'no_heartbeat' ) ); | |
} | |
} | |
/** | |
* Properly Registers AJAX script. | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @return void. | |
*/ | |
public function register() { | |
wp_register_script( | |
$this->name, | |
$this->script['url'], | |
$this->script['deps'], | |
filemtime( $this->script['src'] ), | |
true | |
); | |
} | |
/** | |
* Properly Enqueues AJAX script. | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @return void. | |
*/ | |
public function enqueue() { | |
wp_enqueue_script( $this->name ); | |
} | |
/** | |
* Properly provides localized data for the action. | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @return void. | |
*/ | |
public function localize() { | |
// Get JS object name | |
$object = isset( $this->script['data_object'] ) ? $this->script['data_object'] : $this->name; | |
$this->nonce = wp_create_nonce( "{$this->name}_nonce" ); | |
$data = wp_parse_args( $this->script['data'], array( | |
'ajaxurl' => admin_url( 'admin-ajax.php' ), | |
'_ajax_nonce' => $this->nonce, | |
'action' => "{$this->name}_action", | |
'screen_id' => get_current_screen()->id, | |
)); | |
wp_localize_script( $this->name, "$object", $data ); | |
} | |
public function no_heartbeat() { | |
wp_deregister_script('heartbeat'); | |
wp_register_script('heartbeat', false); | |
} | |
/** | |
* Does proper AJAX security check & then calls "{$this->name}_wp_ajax_action" action. | |
* | |
* @since 1.0.0 | |
* @author Travis Smith <t@wpsmith.net> | |
* | |
* @return void. | |
*/ | |
public function _callback() { | |
$data = array_map( 'esc_attr', $_GET ); | |
! check_ajax_referer( $data['action'], "_ajax_nonce", false ) | |
AND wp_send_json_error(); | |
do_action( "{$this->name}_wp_ajax_action", $data ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment