The W3 Total Cache plugin changes the URL of various files in /w3-total-cache/lib/W3/Plugin/Cdn.php in the function *ob_callback*. It uses a series of callbacks to modify an output buffer. The code runs like this:
- w3_total_cache.php calls
$root->run();
- W3_Root::run calls
$plugin->run()
for each plugin in$this->_loaded_plugins
- W3_Plugin_TotalCache::run starts an output buffer which calls W3_Plugin_TotalCache::ob_callback
- W3_Plugin_TotalCache::ob_callback calls w3tc_do_ob_callbacks() which runs any callback stored in
$GLOBALS['_w3tc_ob_callbacks']
- The CDN adds it’s own callback to that global in W3_Plugin_Cdn::run. That callback is W3_Plugin_Cdn::ob_callback
Which callbacks then run is unfortunately hard coded in this line:
$buffer = w3tc_do_ob_callbacks(array('minify', 'newrelic', 'cdn', 'browsercache', 'pagecache'), $buffer);
Because this is hard coded, if you ever need to modify what is included and what isn’t, you’ll have to change their callback.
Example:
I have a plugin that exports JSON, and the CDN aspect of W3 Total Cache wasn’t changing any URLs for JSON requests. It turns out that my output was failing the w3_is_xml($buffer)
test.
I fixed it by turning their single CDN callback into multiples, like this:
// Modify the output buffer callbacks of W3 Total Cache to work with the JSON API
if (!empty($GLOBALS['_w3tc_ob_callbacks']) && isset($GLOBALS['_w3tc_ob_callbacks']['cdn'])) {
// Back-up the original value of $GLOBALS['_w3tc_ob_callbacks']['cdn']
// This should be W3_Plugin_Cdn::ob_callback
$this->cdn_ob_callback = $GLOBALS['_w3tc_ob_callbacks']['cdn'];
// Replace $GLOBALS['_w3tc_ob_callbacks']['cdn'] with out own method
// which will call the original callback in between two of our own
$GLOBALS['_w3tc_ob_callbacks']['cdn'] = array($this, 'do_multiple_cdn_ob_callbacks');
}
Then doing the changes I need, making sure to call their original callback in the middle.
public function do_multiple_cdn_ob_callbacks(&$buffer) {
// Frist run our own callback to add an XML string to the buffer
// so that the content passes the w3_is_xml($buffer) test
$buffer = $this->w3_total_cache_ob_callback_start($buffer);
// Next run the original callback, which will replace the asset URLs
$buffer = call_user_func($this->cdn_ob_callback, $buffer);
// Finally, run another callback of our own to remove the XML string
$buffer = $this->w3_total_cache_ob_callback_end($buffer);
return $buffer;
}