In this two part series, we're taking a look at how to properly introduce Ajax-specific functionality into the WordPress Dashboard.
In the first article in the series, we began working on a plugin that displays a notification as soon as it's activated ... but that's it. In this article, we'll add Ajax-enabled functionality that will allow users to dismiss the message and we'll finish up with a working version of the plugin.
Specifically, we're going to cover all of the things necessary on both the server-side and the client-side that are necessary to process an Ajax request and respond appropriately.
Finally, we'll review a checklist of items that all Ajax-based WordPress functionality should have to make sure that you properly employ the API in future projects.
Remember the Nonce
Before we get started, it's important to make sure that you have the nonce value in the function that renders your notification method. For review, here's the function that we included in the first article:
public function display_admin_notice() { $html = '<div id="ajax-notification" class="updated">'; $html .= '<p>'; $html .= __( 'The Ajax Notification example plugin is active. This message will appear until you choose to <a href="javascript:;" id="dismiss-ajax-notification">dismiss it</a>.', 'ajax-notification' ); $html .= '</p>'; $html .= '<span id="ajax-notification-nonce" class="hidden">' . wp_create_nonce( 'ajax-notification-nonce' ) . '</span>'; $html .= '</div><!-- /.updated -->'; echo $html; }
Notice that we're rendering the nonce value using wp_create_nonce
in a span element having the ID of ajax-notification-nonce
. I bring this up for three reasons:
- Nonce values provide security measures and are important when you're making any type of request from the front-end to the back-end.
- In my experience, this is one of the things that developers most often leave out of their work - this is meant to make sure we have this covered prior to writing any additional code.
- The element containing the nonce value needs a specific ID so that we can easily access it using JavaScript when initiating our Ajax request.
With that, let's get to writing the Ajax functionality.
On to Ajax
Building Ajax-based functionality in the WordPress Dashboard typically includes four key points:
- Some JavaScript functionality that will respond to the user's event and send it to the server
- A server-side callback function that is responsible for managing the request coming from the browser
- Server-side functionality that will send the data back to the browser
- JavaScript functionality responsible for handling the response
Though there's no particular order in which we need to write this code, we'll just go down the list as it's stated above and work through it.
Sending the Request
The JavaScript code for sending the request is relatively boilerplate stuff, but we need to first outline what it is that we're actually going to do:
- The user decides to dismiss the notification
- The user clicks on the dismiss anchor that we've provided
- JavaScript responds to the event when the user clicks on said anchor
- JavaScript sends a request to the server
We'll write the code incrementally to make sure that it's easy to follow along. First, we'll start by setting up the code after the window has loaded and we'll make sure that the Ajax notification message is present:
(function ($) { $(function () { // Check to see if the Ajax Notification is visible; otherwise, // we won't worry about doing any of this. if ($('#dismiss-ajax-notification').length > 0) { // Stuff TODO here... }); }); }(jQuery));
Next, we need to setup an event handler that will fire once the user clicks on the anchor that we've placed in the notification. For this, we need the ID of the message's element - that is, dismiss-ajax-notification
.
Because an anchor's default behavior is to try to navigate to its href
attribute, we need to also prevent the default action from occurring.
(function ($) { "use strict"; $(function () { // Check to see if the Ajax Notification is visible if ($('#dismiss-ajax-notification').length > 0) { // If so, we need to setup an event handler to trigger it's dismissal $('#dismiss-ajax-notification').click(function (evt) { evt.preventDefault(); // More TODO here... }); } // end if }); }(jQuery));
At this point, we're ready to actually send the request to the server. To do this, we'll be using the jQuery post
function. We'll be passing it three arguments:
- The URL of the address to which the request should be sent. This is a global value provided by WordPress. It's stored in the
ajaxurl
variable - The hash of options to send to the server. This includes the action - or the function - to fire on the server and the nonce value for validation
- The function used to handle the response
Let's write out all of this now (including stubbing out the response function) and then we'll hop over to the server-side code.
(function ($) { $(function () { // Check to see if the Ajax Notification is visible if ($('#dismiss-ajax-notification').length > 0) { // If so, we need to setup an event handler to trigger it's dismissal $('#dismiss-ajax-notification').click(function (evt) { evt.preventDefault(); // Initiate a request to the server-side $.post(ajaxurl, { // The name of the function to fire on the server action: 'hide_admin_notification', // The nonce value to send for the security check nonce: $.trim($('#ajax-notification-nonce').text()) }, function (response) { // TODO response handler }); }); } // end if }); }(jQuery));
Recall earlier that I said we'd need to know the ID of the field containing the nonce value - that is, ajax-notification-nonce
. Notice above that we're grabbing the text value of that element and sending it to the server as the value of the nonce
key.
The second thing to notice is that we're sending along an action key that has the value of hide_admin_notification
. This is a function that we need to write on the server as it's what will be responsible for actually hiding the notification.
Handling the Request
In our plugin file, we need to create a function that has the name as the action value mentioned above: hide_admin_notification
.
As usual, I like to talk about what the function is going to do before writing any code. In this case, here's what needs to be done:
- We need to make sure the incoming nonce is correct; otherwise, we don't want to execute any code
- We need to update the option that we created in the first article to set the dismiss to false
- We need to send a value back to the browser so that it can respond appropriately to the function
Here's the code for making that happen:
public function hide_admin_notification() { // First, check the nonce to make sure it matches what we created when displaying the message. // If not, we won't do anything. if( wp_verify_nonce( $_REQUEST['nonce'], 'ajax-notification-nonce' ) ) { // If the update to the option is successful, send 1 back to the browser; // Otherwise, send 0. if( update_option( 'hide_ajax_notification', true ) ) { die( '1' ); } else { die( '0' ); } // end if/else } // end if }
It's relatively simple, isn't it? The key thing to understand is that we're sending the value of '1' in the context of die
if the option is successfully updated; otherwise, we send the value of '0'. This will allow us to read the value in the response on the browser to determine how best to respond.
Obviously, if the returned value is 1, then we can hide the notification.
Before hopping back into the JavaScript, we need to make sure that we wire this function up using the appropriate hook. So, in the plugin's constructor, let's add a line for add_action
:
add_action( 'wp_ajax_hide_admin_notification', array( &$this, 'hide_admin_notification' ) );
The key thing to note here is that the tag for the function is labeled 'wp_ajax_hide_admin_notification
'.
If you're working with Ajax in the WordPress dashboard, then your hook must be added with the
wp_ajax_
prefix and it should end with the name of the function.
This is easily the second most important thing I see developers miss when working on Ajax-based code.
From here, we're ready to hop back into the client-side code.
Handling the Response
Finally, we're ready to handle the response. This is easy: If the server responds with a 1, then we'll hide; otherwise, we won't do anything.
Granted, the best practice would be to display an error message or some type of feedback to let the user know that something went wrong, but the main point of the article is to demonstrate Ajax in WordPress so we'll simply change out the class name from updated
to error
.
Here's what needs to be added to the JavaScript source to handle the response:
function (response) { // If the response was successful (that is, 1 was returned), hide the notification; // Otherwise, we'll change the class name of the notification if ('1' === response) { $('#ajax-notification').fadeOut('slow'); } else { $('#ajax-notification') .removeClass('updated') .addClass('error'); } // end if }
And that's really it. The full JavaScript source should look like this:
(function ($) { $(function () { // Check to see if the Ajax Notification is visible if ($('#dismiss-ajax-notification').length > 0) { // If so, we need to setup an event handler to trigger it's dismissal $('#dismiss-ajax-notification').click(function (evt) { evt.preventDefault(); // Initiate a request to the server-side $.post(ajaxurl, { // The name of the function to fire on the server action: 'hide_admin_notification', // The nonce value to send for the security check nonce: $.trim($('#ajax-notification-nonce').text()) }, function (response) { // If the response was successful (that is, 1 was returned), hide the notification; // Otherwise, we'll change the class name of the notification if ('1' === response) { $('#ajax-notification').fadeOut('slow'); } else { $('#ajax-notification') .removeClass('updated') .addClass('error'); } // end if }); }); } // end if }); }(jQuery));
And the plugin's PHP should look like this:
/* Plugin Name: Ajax Notification Plugin URI: http://github.com/tommcfarlin/ajax-notification Description: An example plugin used to demonstrate the WordPress Ajax API for a companion article on Envato's WPTuts+ site. Version: 1.0 Author: Tom McFarlin Author URI: http://tommcfarlin.com Author Email: [email protected] License: Copyright 2012 Tom McFarlin ([email protected]) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class Ajax_Notification { /*--------------------------------------------* * Constructor *--------------------------------------------*/ /** * Initializes the plugin by setting localization, filters, and administration functions. */ function __construct() { load_plugin_textdomain( 'ajax-notification', false, dirname( plugin_basename( __FILE__ ) ) . '/lang' ); register_activation_hook( __FILE__, array( &$this, 'activate' ) ); register_deactivation_hook( __FILE__, array( &$this, 'deactivate' ) ); add_action( 'admin_enqueue_scripts', array( &$this, 'register_admin_scripts' ) ); // Display the admin notice only if it hasn't been hidden if( false == get_option( 'hide_ajax_notification' ) ) { add_action( 'admin_notices', array( &$this, 'display_admin_notice' ) ); } // end if add_action( 'wp_ajax_hide_admin_notification', array( &$this, 'hide_admin_notification' ) ); } // end constructor /*--------------------------------------------* * Core Functions *---------------------------------------------*/ /** * Upon activation, add a new option used to track whether or not to display the notification. */ public function activate() { add_option( 'hide_ajax_notification', false ); } // end activate /** * Upon deactivation, removes the option that was created when the plugin was activated. */ public function deactivate() { delete_option( 'hide_ajax_notification' ); } // end deactivate /** * Registers and enqueues admin-specific minified JavaScript. */ public function register_admin_scripts() { wp_register_script( 'ajax-notification-admin', plugins_url( 'ajax-notification/js/admin.min.js' ) ); wp_enqueue_script( 'ajax-notification-admin' ); } // end register_admin_scripts /** * Renders the administration notice. Also renders a hidden nonce used for security when processing the Ajax request. */ public function display_admin_notice() { $html = '<div id="ajax-notification" class="updated">'; $html .= '<p>'; $html .= __( 'The Ajax Notification example plugin is active. This message will appear until you choose to <a href="javascript:;" id="dismiss-ajax-notification">dismiss it</a>.', 'ajax-notification' ); $html .= '</p>'; $html .= '<span id="ajax-notification-nonce" class="hidden">' . wp_create_nonce( 'ajax-notification-nonce' ) . '</span>'; $html .= '</div><!-- /.updated -->'; echo $html; } // end display_admin_notice /** * JavaScript callback used to hide the administration notice when the 'Dismiss' anchor is clicked on the front end. */ public function hide_admin_notification() { // First, check the nonce to make sure it matches what we created when displaying the message. // If not, we won't do anything. if( wp_verify_nonce( $_REQUEST['nonce'], 'ajax-notification-nonce' ) ) { // If the update to the option is successful, send 1 back to the browser; // Otherwise, send 0. if( update_option( 'hide_ajax_notification', true ) ) { die( '1' ); } else { die( '0' ); } // end if/else } // end if } // end hide_admin_notification } // end class new Ajax_Notification();
Conclusion
You can grab the plugin on GitHub. For reference, be sure to review the following resources:
Comments