Wordpress Headway Theme: Page cache not working with W3TC and WP Super Cache
UPDATE - Headway developers are currently looking into this issue and are working on a patched version of Headway fixed this in Headway version 3.8.3.
Having trouble with page caching not working when using Headway Theme framework for Wordpress? Tried both W3TC and WP Super Cache and still getting weird problems? I've got good and bad news for you...
This won't be a particularly short post because the problem is a little convoluted, but it does contain some answers and a workaround which should allow you to take an informed decision on how you wish to proceed.
The good news is there are workarounds to the problem. The bad news is that these are only workarounds and by default there are big problems with Headway and page caching.
W3TC + WP SuperCache Page Caching Problem with Headway Theme
To understand the problem first it's essential to know a couple of things about how W3TC, WP Super Cache and Headway Theme for Wordpress handle page caching.
To begin, lets look at how Headway itself handles it CSS and JavaScript.
How Headway generates it's CSS and JavaScript
Headway stores it's CSS and JS (JavaScript) information in the same database that powers your Wordpress site. Just like any plugin or theme, it uses the database to store persistent information that can then be generated dynamically upon a page load or other action.
In an effort to speed up the operation of the theme, reduce overall page load time and reduce the amount of resources it requires, Headway will cache the generated CSS and JS to its cache folder in the following location:
/wp-content/uploads/headway/cache
Fire up your favourite FTP application or SSH into your server and view the content of this folder. As an example, here is a screenshot showing the output of the Headway cache folder from another site I manage.
As you can see, Headway caches CSS stylesheets and JS files for each template or page layout, as well as a 'general' stylesheet covering styles valid across all pages.
Rebuilding Headway's cache
First, make a note of the names of the cached files, just so you can see what is happening. Now, open up Headway's Visual Editor, click on 'Tools' on the top bar and then click 'Clear Cache'.
If you go back to your FTP or terminal and refresh the content of the cache folder, you'll see that the cached files have now gone.
To regenerate them, simply visit a page on your site and Headway will automatically regenerate the cached files.
Try it now and look again at the content of the cache folder...
See the files being regenerated?
NOTE - If you have a busy site, some of your visitors loading your pages might have caused a few files to be recreated straight after you cleared the cache, so you might not have seen a totally empty cache folder after refreshing the folder contents. This is normal.
What does page caching actually do?
Page caching is concerned with taking the HTML generated by Wordpress and all the installed plugins and themes and saving (caching) that output to a location from which is can be quickly served.
As you can imagine, generating the page with hundreds or perhaps thousands of calls to the database can take time and resources. In contrast, simply handing some pre-existing (cached) HTML and text back to a visitor on request is super fast and super simple.
Page Cache benefits
That's the big trick to page caching, it simply caches the output and stores it for an amount of time (that you set) and will keep handing copies of this out to visitors.
Page Cache pitfalls
You can probably see the downside here too: every visitor is handed the exact same HTML (not good if you have a site that relies on being dynamic) and crucially it also means that if a link or resource (like a CSS or JS file) is deleted or has it's name changed, then that link will lead to a 404 resource not found error.
This is where it becomes critical to know if one of those files has changed or been deleted so that your site knows to flush the page cache and regenerate itself, recreating the HTML with the new correct links to the various resources.
Here be dragons...
So with that out of the way - what's the problem? Spoken simply it's this:
Headway deletes its cached CSS and JS files for a whole myriad of reasons, deleting the files that your page cache is linking too.
That's the crux of it, but it's a bit more complex than that. Here goes...
Headway cache purging
Headway purges it's cache based on the following function
public static function init() {
add_action('headway_visual_editor_save', array(__CLASS__, 'flush_cache'));
add_action('headway_visual_editor_reset_layout', array(__CLASS__, 'flush_cache'));
add_action('headway_visual_editor_delete_template', array(__CLASS__, 'flush_cache'));
add_action('headway_visual_editor_assign_template', array(__CLASS__, 'flush_cache'));
add_action('headway_visual_editor_unassign_template', array(__CLASS__, 'flush_cache'));
add_action('publish_post', array(__CLASS__, 'flush_cache'));
add_action('edit_post', array(__CLASS__, 'flush_cache'));
add_action('delete_post', array(__CLASS__, 'flush_cache'));
add_action('headway_switch_skin', array(__CLASS__, 'flush_cache'));
add_action('activate_plugin', array(__CLASS__, 'flush_cache_hard'));
add_action('deactivate_plugin', array(__CLASS__, 'flush_cache_hard'));
add_action('switch_theme', array(__CLASS__, 'flush_cache_hard'));
add_action('headway_db_upgrade', array(__CLASS__, 'flush_cache_hard'));
add_action('headway_activation', array(__CLASS__, 'flush_cache_hard'));
add_action('headway_global_reset', array(__CLASS__, 'flush_cache_hard'));
add_action('headway_snapshot_rollback', array(__CLASS__, 'flush_cache_hard'));
}
If you go through all that with a fine toothed comb you'll see it has a lot of theme specific things it flushes it's cache for. No problem there.
But, look at these actions:
add_action('publish_post', array(__CLASS__, 'flush_cache'));
add_action('edit_post', array(__CLASS__, 'flush_cache'));
add_action('delete_post', array(__CLASS__, 'flush_cache'));
add_action('activate_plugin', array(__CLASS__, 'flush_cache_hard'));
add_action('deactivate_plugin', array(__CLASS__, 'flush_cache_hard'));
Those actions are incredibly common - publishing, editing and deleting a post/page triggers a cache flush by Headway, deleting the files from the cache folder. The same thing happens when moderating comments, or activating, deactivating or updating plugins.
This means that Headway clears its cache for most of the basic functions you might perform as a Wordpress user, and if you don't moderate comments, it'll flush it every time a user leaves one which is completely outside of your control and could happen very regularly with a busy site.
What's wrong with Headway purging it's cache so often?
The first thing to know is that Headway clears its cache in isolation, it doesn't 'tell' any of the rest of your site that it has done so. Plugins like W3TC or WP Super Cache have no way of knowing that the files have been deleted in order to purge their (now incorrect) page caches.
There are also performance penalties of having to constantly regenerate the data and recache those files.
But lets imagine that you do have a page cache active...
If Headway deletes it's files, the cached HTML will now point to resources that aren't there any more and your site will display incorrectly.
Effectively, Headway deleting those files in isolation and not telling W3TC or WP Super Cache 'breaks' your page cache.
But that's fine, just visit the page and regenerate the files like we did before.
Not going to work I'm afraid. Remember that with page caching we're simply handing back pre-cached HTML. We aren't loading the page, we're handing back something we already saved earlier without touching the 'normal' page generation process.
Because of this, a visitor loading a page doesn't trigger Headway to regenerate it's cache files. To get them to regenerate Headway's files we'd need to flush our page cache and have a visitor hit the 'naked' page, trigger the full generation and cache process and get Headway to regenerate its files at the same time.
That's still not a problem, W3TC and WP Super Cache can purge their cache...
They can and they do do this based on certain actions. I don't have the full function that W3TC or WP Super Cache uses but from testing it's not done automatically for the same ones.
Also, whilst W3TC and WP Super Cache do purge their caches, they do so for a subset pages by default. The default is not to flush every single part of the cache but to flush the cache for certain types of pages.
For W3TC this might include the Home page, the Blog page (if you have separate Home and Blog pages), the post page itself and the feeds or author overview pages. I believe a similar thing is done by WP Super Cache.
Neither appear to clear actual normal pages though, so some parts of the site might get flushed and others won't. I've also noticed that sometimes Custom Post Types aren't cleared either, though as a type of 'post' I thought they would be.
This leads to parts of your site displaying correctly and others without and CSS or JavaScript!
Can't I just turn Headway's caching off?
You can but this is fragile in that any changes to your CSS will need a complete page cache purge (just like if you had caching active) and with the performance lag it causes you might as well turn page caching off anyway!
Fixing Headway Theme and Page Caching
So, without modification, page caching with W3TC or WP Super Cache whilst using Headway Theme is currently in large part 'broken'.
There are a couple of things you could do to try and workaround this, but these are manual interventions and you need to understand why you are doing them.
Manually clear all pages
This works for both W3TC and WP Super Cache but is an intensive process and are you going to be around for every event that flushes the Headway cache?
If you allow trusted commenters to leave a comment for example or if you update a plugin or any of those many actions, you'd need to be there ready to purge the cache straight away.
Automatically clear all pages
This will only work for W3TC as WP Super Cache doesn't seem to provide this functionality (correct if wrong - contact details in footer).
W3TC allows you to set which parts of the site are to be cleared upon a particular action like publishing or editing a post.
This input allow you to manually specify pages. Unfortunately, it doesn't seem to allow the use of Regular Expressions (not when I tried anyway) so you must specify each pages URL (correct if wrong - contact details in footer).
This is time consuming and fragile, particularly if you have a lot of pages.
Disabling Headway's functions to prevent cache purging
This is the most powerful option, but also requires care as you are altering the default behaviour of the theme. It also relies on creating a Child Theme, which is simple enough in itself but is again something you should understand before undertaking.
You can find out how to create a Child Theme for Headway in 7 easy steps here:
http://docs.headwaythemes.com/article/84-child-themes-and-headway
Make note of step 7 - just create a blank file called functions.php as it says and we'll add code to it soon.
Once you've done all that we need to go about disabling those actions above that are the most common causes of Headway clearing it's cache. Those were:
add_action('publish_post', array(__CLASS__, 'flush_cache'));
add_action('edit_post', array(__CLASS__, 'flush_cache'));
add_action('delete_post', array(__CLASS__, 'flush_cache'));
add_action('activate_plugin', array(__CLASS__, 'flush_cache_hard'));
add_action('deactivate_plugin', array(__CLASS__, 'flush_cache_hard'));
EDIT - The remove_action
code I was using as an example in this guide is not currently working and is awaiting feedback from Headway support staff. in the meantime, this alternative approach will neutralise the code...
To disable all of these actions simply comment out the actions in the relevant file like so:
/*
remove_action('publish_post', array(__CLASS__, 'flush_cache'));
remove_action('edit_post', array(__CLASS__, 'flush_cache'));
remove_action('delete_post', array(__CLASS__, 'flush_cache'));
remove_action('activate_plugin', array(__CLASS__, 'flush_cache_hard'));
remove_action('deactivate_plugin', array(__CLASS__, 'flush_cache_hard'));
*/
This will prevent the code from running but won't be retained if you update Headway as the compiler.php
file will be overwritten. As mentioned above, I'm looking into on a proper workaround using the child theme but the code I used wasn't working and so this post will be updated once it's operational.
Caveats and behaviour changes
To adjust to this alteration of Headway's core operation, I simply remember to purge all caches after an update to or installation of a plugin that integrates with Headway - like the Features or Swiss Army Blocks.
When other plugins that have nothing to do with Headway or the display of the site are updated (like Backupbuddy) there is no need for me to clear Headway's cache or to clear the page cache.
I also refrain from using the Headway options in the post editor (hiding titles etc) and if I do use these I remember to clear the Headway and page cache afterwards.
With these changes in place, I am able to leave the cache in place for many days and only intervene manually when I am doing something intentional, not when something has happened without my knowledge and I'm having to take action to correct a problem.
This is a much more stable arrangement, even if it does require manual input, because that manual input it controlled and infrequent.
A few final words
Headway is a great theme, don't take the above as a bash against it. It's got an extraordinary amount of functionality and it's behaviour in regards to page caching is really the result of wanting to be as compatible as possible across the huge breadth of things it helps you as a user to do.
Everything in web development is a compromise, either in terms of cost or ease of use or speed or interoperability or a million other factors.
I've been happily using Headway for several years because it has big benefits and it is often worth the compromises.
Hopefully with one of these workaround you'll be able to continue to use it effectively with page caching too.