With the next release of WP Super Cache in a day or two the long awaited move away from mfunc, mclude and friends will be complete.
This means that if you have been using mfunc, mclude or dynamic-cached-content the dynamic portions of your sites will go blank if you upgrade WP Super Cache without updating that dynamic code. This may seem complicated but there’s an example script included and detailed explanations below. A lot of effort was made to make this backwards compatible but unfortunately it wasn’t possible.
In their place is a new cacheaction filter called wpsc_cachedata and it’s sidekick wpsc_cachedata_safety. In the future when a site owner using WP Super Cache wants to make part of their website dynamic they will use those filters to modify pre-defined text strings and replace them with the data they want displayed to the end user. There’s an example script ready to be ripped apart to help you figure all this out.
There are two ways of using this:
- The dynamic content is the return value of a simple process, be it
date()
or any of the numerous get_*() functions in WordPress. That data can simply be slotted in place of the pre-defined text mentioned above.
- The more difficult bit comes when you need to use an output buffer to collect the data for display. Due to a limitation in PHP it’s impossible to run an output buffer in the callback function of another output buffer, which is when the wpsc_cachedata filter runs. We need to collect that data before the callback function executes.
The first way above is easy. Simply add a text string of random characters to your theme where you want the dynamic content to appear, then hook a function on to the wpsc_cachedata filter to str_replace() it with your dynamic content. These functions in this script do that:
- dynamic_cache_test_filter()
- dynamic_cache_test_template_tag()
- dynamic_cache_test_init()
You’ll have to hook on to the wpsc_cachedata_safety action and return the numeral 1 to actually run the wpsc_cachedata filter. This is a fail safe used by the plugin to make sure things are ok when the filter runs.
Unfortunately if you want to use an output buffer it’s a lot harder. As stated above an output buffer can’t run in the callback function of another output buffer. This means you have to generate your dynamic content earlier in the PHP process.
This could be as easy as calling your dynamic content function (dynamic_output_buffer_test() in the example script) from the wp_footer action, or calling it from any action before shutdown, whichever is appropriate. You’ll also need to add a template tag of your own choosing to your theme.
Your dynamic content function will run just fine for cached pages, so after the new page has run it store the output in a constant or global variable that the same function can look for when the wpsc_cacheaction runs it. If it finds that information, it can do the search and replace of your template tag without running the output buffer again.
Some pages won’t run the dynamic content function however. This includes feeds and sitemaps. Those pages will generate a PHP error because the output buffer will try to run in the callback!
“PHP Fatal error: ob_start(): Cannot use output buffering in output buffering display handlers in…”
To stop that happening you must check that there’s text to shove in the cached page. That’s what happens in the function dynamic_output_buffer_test_safety() in the example script. It fires on the wpsc_cachedata_safety filter and returns the numeral 1 if successful.
Anatomy of an Output Buffer
I’m going to try and explain the output buffer functions in more detail here. They’re only example functions and if you spot a bug or can suggest improvements please do!
define( 'DYNAMIC_OUTPUT_BUFFER_TAG', '' ); // CHANGE THIS!
This is the string you add to your theme where your dynamic content will appear. The plugin will replace this string with the code generated by your dynamic content function.
function dynamic_output_buffer_test( &$cachedata = 0 ) {
if ( defined( 'DYNAMIC_OB_TEXT' ) )
return str_replace( DYNAMIC_OUTPUT_BUFFER_TAG, DYNAMIC_OB_TEXT, $cachedata );
ob_start();
// call the sidebar function, do something dynamic
echo "<p>This is a test. The current time on the server is: " . date( 'H:i:s' ) . "</p>";
$text = ob_get_contents();
ob_end_clean();
if ( $cachedata === 0 ) // called directly from the theme so store the output
define( 'DYNAMIC_OB_TEXT', $text );
else // called via the wpsc_cachedata filter. We only get here in cached pages in wp-cache-phase1.php
return str_replace( DYNAMIC_OUTPUT_BUFFER_TAG, $text, $cachedata );
}
add_cacheaction( 'wpsc_cachedata', 'dynamic_output_buffer_test' );
- 1. dynamic_output_buffer_test() is the function that will generate the dynamic content inserted into the cached page.
- 2-3. DYNAMIC_OB_TEXT stores the previous output of this function. If it’s set that means we’re in the wpsc_cachedata filter and should insert it into the cached page and return it.
- 4-8. This creates the output buffer, echoes a string with the current time and copies the buffer into a variable called $text before closing the output buffer.
- 10-13. This is how we decide to return data. If $cachedata is 0 that means this function was called from the theme so we should define the constant DYNAMIC_OB_TEXT for later use. Otherwise, we must be dealing with an already cached page so insert the dynamic content into the page and return it.
- 16. Add the dynamic_output_buffer_test() function to the wpsc_cachedata action. “add_cacheaction” is used as it loads before the regular WordPress action code loads.
function dynamic_output_buffer_test_safety( $safety ) {
if ( defined( 'DYNAMIC_OB_TEXT' ) )
return 1; // ready to replace tag with dynamic content.
else
return 0; // tag cannot be replaced.
}
add_cacheaction( 'wpsc_cachedata_safety', 'dynamic_output_buffer_test_safety' );
- 1-6. dynamic_output_buffer_test_safety() is a function that checks if dynamic content was generated correctly. If that constant is not defined the output buffer will run within the callback function of the main WP Super Cache output buffer and generate a PHP error.
- 7. Add the wpsc_cachedata_safety() function to the dynamic_output_buffer_test_safety action.
sidebar.php
As an example, if I wanted to display my dynamic content in the sidebar of my blog I would load sidebar.php in my theme’s directory and add the following code.
if ( function_exists( 'dynamic_output_buffer_test' ) )
dynamic_output_buffer_test();
?>WORDPRESS ROCKS THE WORLD<?php
I had previously edited the example script, uncommented it and changed the appropriate tag:
define( 'DYNAMIC_OUTPUT_BUFFER_TAG', 'WORDPRESS ROCKS THE WORLD' ); // CHANGE THIS!
Final Note and Download Link
Please grab the development version of the plugin and try it on a staging server before you put it live. Feedback would be appreciated!
Warning! Keep the tags you use secret. You don’t want someone leaving a comment on your blog with that string! Do not use the same function names or constant names as in this post or example script. They’re in this very public post. Someone is bound to use them and cause you problems when you install their plugin.
Finally, barring any last minute major bugs this version of WP Super Cache will be released on Wednesday. Be careful upgrading. Pass the word around if you know someone is using mfunc as their site will stop working!