I notice that a lot of people visit my blog because they want to get WP-PostViews or Popularity Contest plugin to work with a WordPress cache plugin like WP Super Cache. In this post I will show you the general technique I use to make (almost) any plugin compatible with WP Super Cache.
Understanding WP Super Cache
As you all may know, WP Super Cache when fully enabled works by saving a copy of the generated HTML file and using .htaccess to redeliver that same static file upon repeated requests. The benefit of this is obviously the time saving from the absence of PHP execution and database queries. This “feature” also has the side effect of staticizing any parts of the page that needs to be dynamic, such as:
- Statistics tracking: This includes things like page view counting/displaying and visitor tracking. Some plugins that do this are WP Post Views and Popularity Contest.
- Dynamic visitor targeting: This includes things like showing different content depending on who your visitor is. Some plugins that do this are What Would Seth Godin Do and Who Sees Ads.
Strategy
So what can we do to make a static HTML document become dynamic? The answer is Asynchronous Javascript And XML (also better known as AJAX)!
The goal here is to use client side Javascript to make HTTP requests to the server to perform any PHP execution that you need and then return the result back to Javascript client. Here is what will take place step by step:
- A visitor comes to your site requesting a document.
- .htaccess redirects them to a static HTML file with Javascript code inside of it.
- The visitor downloads the said HTML file
- The Javascript starts executing on the client side making a special HTTP request to the server again, passing any parameters necessary for the server side PHP to do its job.
- The server receives the special HTTP request, the PHP code executes, and the result is sent back to the client side Javascript
- Client side Javascript receives the result and decides what to do with it (such as display the content).
By doing this, you have effectively made a part of the static HTML file dynamic.
Implementation
There are definitely many ways to achieve this, but I will show you one way that you can hopefully take and implement anywhere you need.
Simplify the Problem
Let’s say we have a simple plugin that displays the current server timestamp and the visitor’s referring URL. The plugin is equivalent to adding this code to your functions.php file:
<?php function omni_ts_and_ref() { echo time(); echo '<br/>'; echo $_SERVER['HTTP_REFERER']; } ?>
You can call this function by running <?php omni_ts_and_ref(); ?> anywhere within your theme.
Now if your site was being cached, the server timestamp will not update on subsequent visits and the visitor referring URL will be wrong for everybody except the first visitor. As you can see, we have recreated this problem with the simplest plugin.
PHP
Before we do anything we have to make sure that the PHP code is able to accept the unique Javascript requests to the server.
First, we will need to create a function hook for intercepting Javascript calls like so:
<?php function omni_request_handler() { if ( isset($_GET['omni_action']) && $_GET['omni_action'] == 'ts_and_ref' ) { omni_ts_and_ref(); exit(); } } add_action('init', 'omni_request_handler'); ?>
In the code above we have made the PHP code intercept and call omni_ts_and_ref() only if the request URL contains the GET parameter “omni_action” with the value of ‘ts_and_ref’.
Next we added this request handler function to the WordPress ‘init’ action so that it gets called before the bulk of the WordPress page starts displaying.
The next important thing worth mentioning is that the call to $_SERVER['HTTP_REFERER'] in omni_ts_and_ref() will not be the correct value if the function is called via AJAX. We have to fix the function to not use $_SERVER, but the parameter that we will pass via AJAX instead.
<?php function omni_ts_and_ref() { echo time(); echo '<br/>'; echo urldecode($_GET['omni_ref']); // we will see how AJAX is passing this over in a bit } ?>
Here is the complete functions.php file (rename from *.txt to *.php and ignore omni_display() for now).
Now that the PHP side is set up, let’s move on to the client side Javascript.
Javascript
As we discussed before, the client side Javascript will be making HTTP requests to the server. To make this task easier, we should use the built-in AJAX methods in the jQuery library. Here is what our Javascript code should look like. You can place this anywhere in your theme or make the call to <?php omni_display() ?> (included in functions.php).
<script type='text/javascript' src='http://example.com/wp-includes/js/jquery/jquery.js?ver=1.2.6'></script> <div id="omni_div"></div> <script type="text/javascript"> jQuery(document).ready(function($){ $.ajax({ type : "GET", url : "index.php", data : { omni_action : "ts_and_ref", omni_ref : encodeURIComponent(document.referer) }, success : function(response){ // the server has finished executing PHP and has returned something, so display it! ("#omni_div").html(response); } }); }); </script>
There are a few things to notice in the code above:
- The AJAX call is made to index.php. It really doesn’t matter what page the call is made to as long as we have added omni_request_handler() to the WordPress “init” hook.
- We have passed the key “omni_action” along with the value “ts_and_ref” to get omni_request_handler() to intercept this HTTP request.
- We have passed in the key “omni_ref” along with the URI encoded referrer value that omni_ts_and_ref() can use to perform an echo.
- On successful PHP code execution, we are dynamically writing the server response into the <div id=”omni_div”></div> block using jQuery.
Drawbacks
- It is AJAX so it will not work for people who browse with Javascript disabled.
- You have to be careful what values you want to pass through from the Javascript as these values are plain text by default. Make sure you do not try to pass through passwords or anything secure across Javascript.
Last Words
This method should work on most plugins. Though it might be a little bit involved to convert an existing plugin to be WP Super Cache compliant, it is definitely not that hard if you start coding your plugin this way from the beginning (that’s how I felt with WP Greet Box). ::cough:: Plugin developers ::cough::
Is my method weak sauce? Do you have a better method? Please feel free let me know if you have any questions, comments, or suggestions about this method in the comment form below.
This website uses IntenseDebate comments, but they are not currently loaded because either your browser doesn't support JavaScript, or they didn't load fast enough.