I recently found the need to give AJAX abilities to a WordPress widget. Notably, I had a request from Kjell Martin Bovre of Scribo.no to allow ThinkTwit to update when used with a caching engine, for instance WP Super Cache. Caching engines work by converting the pages of a site in to HTML and, rather than loading the website code using calls to its database, calling these pages directly when a user makes a request.
The first time that a user visits a site with a caching engine the pages they visit will be converted to HTML. After a period of time these pages will get updated, but if you have a particular item on that page that should be updated more often this will not happen. One way to ensure this item is updated correctly is to enable it to use AJAX. The AJAX code will get called whenever the site is loaded, even in its HTML format – therefore it will work even when cached as the Javascript will make a server call, the server will respond with the up-to-date data and the Javascript will then update the HTML within that page.
After a good few hours research I was able to find a site that helped me do most of this, but there were some errors and it did not work with WordPress widgets as it would break their ability to create multiple instantiations. It was therefore necessary to update the code to allow this, so I thought I would just write a quick and easy guide to writing AJAX capable widgets to allow other developers to quickly and easily resolve this issue. I hope it comes in handy!
- In your widget constructor e.g.
public function myWidget()
, enqueue jquery:// Load jQuery wp_enqueue_script('jquery');
- In your widget declaration i.e.
public function widget($args, $instance)
, and afterextract($args);
(if it exists) get the widget id:// Get the div id of the widget $widgetid = $args['widget_id'];
- Create a variable to store an option that allows your users to turn on or off AJAX within the widget. Do this in the same function:
$useAjax = isset($instance['useAjax']) ? $instance['useAjax'] : false;
- Next you should ensure that the code that outputs the main body of your widget is contained within one function. It may be that you split your code in to many functions, but for simplicity you should call each of those functions from one function that returns your output e.g.
function mainFunction($parameter1, $parameter2, $parameter3) { $output = firstFunctionCall($parameter1, $parameter2); $output .= secondFunctionCall($parameter3); return $output; }
- Still in the widget function, and after your widget’s title (“
echo $before_title . $title . $after_title;
“) enter the following code (this is further explained below):// If the user selected to use AJAX then output AJAX method if ($useAjax) { ?> <script type="text/javascript"> jQuery(document).ready(function($){ $.ajax({ type : "GET", url : "index.php", data : { mywidget_request : "some_action", mywidget_parameter1 : "<?php echo $parameter1; ?>", mywidget_parameter2 : "<?php echo $parameter2; ?>", mywidget_parameter3 : "<?php echo $parameter3; ?>"}, success : function(response) { // The server has finished executing PHP and has returned something, // so display it! $("#<?php echo $widgetid; ?>").append(response); } }); }); </script> <?php // Otherwise output HTML method } else { echo mainFunction($parameter1, $parameter2, $parameter3); }
So the key parts to this code are:
- The if statement checks to see if the (admin) user has specific that the widget should use AJAX
- If the user wishes to use AJAX it will output some Javascript.
- The first two lines tells jQuery to create a function.
- The third line (type) tells the function to use a GET request.
- The fourth (url) tells it to use the index.php address (it could technically be almost any page as they should all have access to our method).
- The fifth line (data) specifies the parameter that will help us find our request.
- The sixth, seventh and eighth lines pass our parameters across the AJAX call.
- And finally the ninth, tenth and eleventh tell our Javascript what to do when the request has been returned – that is to append the returned data to the widget with the id that we dug out previously.
- The else, from the if statement, then tells WordPress to simply output the returned data from the function as the user has decided not to use AJAX.
- In the update function i.e.
public function update($new_instance, $old_instance)
, add in some code to save your new “useAjax” setting:$instance['useAjax'] = (strip_tags($new_instance['useAjax']) == "Yes" ? true : false);
- In your form function i.e.
public function form($instance)
, add in a default value to your “defaults” array (if it exists) to set a default value for “useAjax”:$defaults = array('title' => 'My title', 'first' => 'somevalue', 'second' => 'somevalue', 'third' => 'somevalue', 'useAjax' => false);
- In the same function add some code to add a drop-down box with yes and no options, to allow the user to enable/disable the useAjax setting:
<p><label for="<?php echo $this->get_field_id('useAjax'); ?>"> <select id="get_field_id('useAjax'); ?>" name="get_field_name('useAjax'); ?>" class="widefat"> <option <?php if ($instance['useAjax'] == true) echo 'selected="selected"'; ?>>Yes <option <?php if ($instance['useAjax'] == false) echo 'selected="selected"'; ?>>No </select></label></p>
- Outside of the widget class declaration i.e.
class ThinkTwit extends WP_Widget { // Constructor public function myWidget() { ... } } // Here
Create a new function that will handle your AJAX request on the server side:
// Function for handling AJAX requests function mywidget_request_handler() { // Check that all parameters have been passed if ((isset($_GET['mywidget_request']) && ($_GET['mywidget_request'] == 'some_action')) && isset($_GET['mywidget_parameter1']) && isset($_GET['mywidget_parameter2']) && isset($_GET['mywidget_parameter3'])) { // Output the response from your call and exit echo mainFunction(strip_tags($_GET['mywidget_parameter1']), strip_tags($_GET['mywidget_parameter2']), strip_tags($_GET['mywidget_parameter3'])); exit(); } elseif (isset($_GET['mywidget_request']) && ($_GET['mywidget_request'] == 'some_action')) { // Otherwise display an error and exit the call echo "Error: Unable to display request."; exit(); } }
- Finally we add the handler to WordPress’
init()
function to ensure that it’s included at the top of the page (although not visible) when WordPress is loaded:// Add the handler to init() add_action('init', 'mywidget_request_handler');
NOTE: One final note to be made is that for the widget to be displayed it relies on the theme it’s running in to be written correctly to display widgets in the dynamic sidebar. This means that each instance of the widget should have an id. To do this it should have code in the functions.php file (or somewhere that is called by this file) along the lines of:
if ( function_exists('register_sidebar') ) { register_sidebar(array( 'before_widget' => '<li id="%1$s" class="widget %2$s">', 'after_widget' => '</li>', 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>', )); }
where the key part here is id="%1$s"
in 'before_widget'
.
I know that was quite a long procedure but it should give you everything you need to convert your WordPress Widget to one that can use AJAX. To assist, I have built a working example which you may download and use as you wish. If you have any questions please feel free to ask below.
Many thanks to Thaya Kareeson of omninoggin.com for his article Make Any Plugin Work with WP Super Cache.
13 replies on “AJAX-ifying WordPress Widgets”
This was really helpful. I’m working on a WordPress plugin and haven’t been able to find much information regarding AJAX and widgets.
I’ve adapted your code a bit to suit my purposes, but this was a great starting point as I didn’t really know where to begin.
Thanks!
Hi Ross,
I’m glad it was helpful! All the information is about on the net but it was a bit of a pain to find so I thought I’d put it here in the hope that it would help someone else, so I’m happy that it has 🙂 Thanks for the feedback!
Oh and I love your theme – it’s simple but effective, and the slider is cool! 🙂
Steve
[…] […]
I was able to do something similar to create updating Ajax widgets using jQuery. I have created a post and plug-in to get started with creating widgets that update there UI via Ajax.
http://www.explodybits.com/2011/11/wordpress-ajax-widgets/
Note @8: the select control is missing some code, it should read:
<select class="widefat" id="get_field_id(‘useAjax’); ?>” name=”get_field_name(‘useAjax’); ?>”>
ah! i see what happened, the php got stripped, same mistake in my comment:
<select class=”widefat” id=”<?php echo $this->get_field_id(‘useAjax’); ?>” name=”<?php echo $this->get_field_name(‘useAjax’); ?>”>
I’m not criticizing your technique, it’s entirely possible that I’m overlooking something here. But, if you are forced to handle the ajax request from outside of your widget class, why not use the “standard” admin-ajax.php way of handling the request?
Hi Cosmo,
No offence taken – I do appreciate queries and criticism, especially constructive 🙂
I’ll be honest – I don’t have much time for development, especially with WordPress, as my day job is to manage a development team and IT strategy/implementation so my blog is here to help make sure I at least maintain some level of development. I wasn’t aware of the admin-ajax.php when I initially wrote this so that is the only reason really. If you have any improvements to this you’d like to share I’d be happy to update the post or else I may do it when I have some time in future 🙂
Thanks.
Hi Stephen, thank you for this helpful post. I would like to extend your widget so that AJAX is employed upon user request, not everytime the site loads. I would like the user to be able to give some parameters in a small HTML form in the widget. When the user clicks the submit button the AJAX request (filled with the form parameters) should be launched and then the result from the server is displayed in some div in the widget based upon the parameters the user gave. Do you have any directions on that? Glad to hear!
Hi Teelo,
So help me to understand this…when a user loads your site with ThinkTwit on the page in HTML (no AJAX) you want them to be able to click a submit button which will then update the feed? Or would it not already be there and then instead only appear when they hit the submit button?
Stephen, thanks for you answer. Here is what I need to do. I want to program a domain availability check widget. The domain availability widgets that are already out there simply open a new third-party website, that displays the result. Instead I want the user to fill in the desired domain name, click the submit button and let a php script check for availabiliy and then return the result to the client. The widget itself should then display the result without opening a new tab or window. I hope I could clarify the scenario.
Ah I got you, sorry I thought this was specific to ThinkTwit (didn’t read carefully!).
What I would do is create a form with no action, and using jQuery add an onclick event which posts to your server with an AJAX request which would query the domain. When the response comes back I would then add a div or some other placeholder above the form (so you can do further requests if you want) and in this place your response.
You could use the code above to implement this, just change the script so that it doesn’t work on “ready()”, but instead on “ready()” it adds the onclick event.
[…] http://www.thepicketts.org/2010/03/ajax-ifying-wordpress-widgets/ Share this:EmailPrintTwitterFacebookLinkedInStumbleUponDiggRelated posts: […]