lyncd

Minify for WordPress and WP Super Cache

I’ve integrated Minify and all its bandwidth-saving goodness into WP Super Cache, everyone’s favorite way of sending WordPress pages as super-fast static HTML, thereby saving visitors having to hit up the PHP interpreter (ugh!) or WordPress itself (double ugh!).

What does this mean? Well, it means your HTML (and gzipped HTML) pages can be 5-20% smaller with just a few minutes’ setup. If that sounds good, skip to the install instructions. If you want to hear more blabber first, read on.

What this does, pros and cons

Minify strips unnecessary whitespace and comments to reduce the size of CSS, Javascript and HTML files, most often to shrink and combine multiple CSS and JS files to reduce HTTP connections and save bandwidth, important optimizations for high-performance websites. This is the same longstanding technique that, for instance, Googles uses on its famously simple www.google.com homepage to squeeze out every last byte.

Minify can also use PHP to do on-the-fly compression of CSS/JS (So convenient! But a drag because it touches PHP!) and send HTTP headers to enable aggressive browser-caching of components (Awesome! Especially with an upstream accelerator like Varnish or Squid! But not as useful a technique for HTML, especially with time-sensitive content like on a blog, and where permalinks matter).

HTML only … for now

So what my plugin mod WPSCMinify does, it does only for HTML pages — not for CSS/JS. Why? Because I prefer to pre-Minify these helper files as part of a build process so they’re fast, small and static, instead of being relayed through the big slow PHP interpreter (Minify foresees something like this in current project goal #3). So, if you’re looking for seamless static-served CSS/JS minification with WordPress, sorry. That’s not what my mod does. I suppose I might be persuaded to tackle that in future. :)

If you’re reading this, then hopefully you’re familiar with WP Super Cache. What it does is save complete WordPress pages to the filesystem as both HTML and gzipped HTML, so that the web server can serve them directly and not have to touch PHP or (god forbid) initialize WordPress (authenticated visitors still get dynamic pages).

All my modification does is to run these pages through Minify first, so they wind up a bit smaller. How much smaller? Well, it depends what’s in your pages. In my testing I found the gzipped versions to end up 5-10% smaller, and the plain HTML versions to end up 10-20% smaller. So, we’re not talking miracles here, we’re talking 10%. If your site isn’t under the kind of load where that matters to you then, by all means, adhere to the KISS principle and don’t Minify your HTML.

The tradeoff: file size for CPU

The cost associated here is the CPU used to run Minify through your page the first time it is rendered before it is saved to the filesystem — and Minify is basically just a lot of regex, so this cost isn’t negligible.

Imagine an alternative scenario, with no WP Super Cache: You could implement WordPress+Minify much more simply, in about 3 lines of code — just turn PHP output buffering on at the beginning and end of your WordPress template, and Minify the result. That way all of your pages, even the dynamic ones, would be minified (this is basically what the minify-html plugin does). Sounds great! But it isn’t, because it would be robbing Peter to pay Paul, churning your CPU on every request a lot more than the 10% in bandwidth you’d save.

In my testing, the CPU cost of running Minify on HTML was about 0.05 seconds of execution time on a medium-slow desktop machine running idle, with very little variance (+/- 0.002) due to page size. 1/20th of a second may not sound like much, but that number translated to a busy web server under load (even a powerful one) equals something you don’t want to be doing on every request (render delay due to minification will be 5-10x the transfer time saved). But never fear, it’s perfectly within reason in concert with something like WP Super Cache, where Minify only runs once to generate each static page, and never on dynamic pages.

The whole point is to make things faster for users. We’ve all seen the Yahoo! exceptional performance team’s presentations, with its CEO takeaways that Amazon loses 1% of customers for every 100ms and Google 20% for every 500ms. Must make more faster!

Installation

Updated 8/11/10: My mod is now a plugin (no patches needed!) to WP Super Cache. There’s now a project page with updated info and install instructions. Go there now!

Everything that follows on this page is old and should only be used if you absolutely must run an older version of Super Cache for some reason. These instructions are for version 0.3 of my mod, which is compatible with WP Super Cache 0.9.1. Version 0.2 is compatible with Super Cache 0.9. These versions work, and there are no known issues, but are now unsupported. For more information on older versions, see below.

Requirement: You must be running PHP5. Minify is written in PHP5, and my class is written in PHP5.

I’ve tried to keep hacking of Super Cache to a bare minimum, so nearly all of my modifications are in a separate class I’ve implemented as a singleton. However, there is a patch that must be applied that adds hooks into Super Cache, to perform the minification at the correct time and to insert an “on/off” control onto the Super Cache admin settings screen.

If this talk of patches makes you nervous and you’d rather just download a tarball, here it is: wp-super-cache-with-WPSCMin-0.3.tar.gz. Just untar it into your WordPress plugins directory (move any existing wp-super-cache directory out of the way first), and you’re done. (Follow the standard Super Cache install instructions if it isn’t already installed.)

Otherwise, I’d recommend you follow these instructions instead — my patch should preserve any of your own custom mods.

  1. Download WP Super Cache (if you aren’t already running it) and follow its installation instructions.
  2. Download Minify. Unzip and move the min/ directory into the main wp-super-cache directory.
  3. Download my mod, WPSCMinify v0.3 and untar. Apply the patch wp-super-cache.diff to the wp-super-cache directory and move WPSCMin.php into that directory.
  4. Log into WordPress, go to the Settings/WP Super Cache page, scroll down to the HTML Minify section, and enable!

That’s it! Here’s the shortcut version with commands to paste into your shell:

# WP Super Cache
# (Skip and cd to the wp-super-cache directory if already installed)
# Read http://wordpress.org/extend/plugins/wp-super-cache/installation/
cd [your WordPress install]/wp-content/plugins # OK, from here just paste
wget http://downloads.wordpress.org/plugin/wp-super-cache.0.9.1.zip
unzip wp-super-cache.0.9.1.zip && rm wp-super-cache.0.9.1.zip
cd wp-super-cache

# Minify
mkdir tmp && cd tmp
wget http://minify.googlecode.com/files/minify_2.1.2.zip
unzip minify_2.1.2.zip
mv min ../

# WPSCMinify
wget http://lyncd.com/files/WPSCMin-0.3.tar.gz
tar -xzf WPSCMin-0.3.tar.gz
patch -p1 -d ../ < WPSCMin/wp-super-cache.diff
mv WPSCMin/WPSCMin.php ../

# Clean up
cd ..
rm -fr ./tmp

# Now you just need to log into WordPress and enable!

Versions

With a couple of exceptions (see changelog) the only changes from one version to the next are that they patch against newer versions of WP Super Cache -- my code hasn't changed. Since my patch only makes a few surgical edits, you can always just download the latest version and apply these edits manually.

  • 0.3 (current) tested against WP Super Cache 0.9.1 and packaged with Minify 2.1.2. Will not patch against older versions of WP Super Cache.
  • 0.2 patches WP Super Cache 0.9 only and packaged with Minify 2.1.1.
  • 0.1 patches WP Super Cache 0.8.4 (may also patch similar versions, this is untested) and packaged with Minify 2.1.1.

Suggestions, bug reports

Yes, I know it's only like 100 lines of code! Still, I welcome any suggestions and bug reports. Just add a comment here.

Filed under: Code.  Tagged: , , , .

15 comments »

  • This looks really cool but I’d prefer it was built into WP Super Cache or was a Super Cache plugin

    Also I think you need to minify CSS/JS – maybe have this optional in case someone has pre-minified those files like you do

    • Yeah, I hear where you’re coming from. Well, if you download my tarball, that’s a version of the plugin with minify integrated. My code is released without restriction, so if Donncha wanted to merge it into WP Super Cache, that would be great and he’s totally free to do that — feel free to suggest it to him! If this isn’t a hugely requested feature, then I can see why he might not want to do it, because he’d have to merge upstream changes from Minify. And, it’d break compatibility with PHP4 so he’d either have to orphan all PHP4 users or start maintaining two separate forks. IMHO not really worth it for the 10% size reduction.

      I dunno if you’ve read through the WP Super Cache code, but it’s just a bunch of hacks piled onto the original ugly spaghetti code of WP Cache (a bunch of horrendously long “functions” with no design and very little code reuse) — there’s not really a plugin system per se, just a couple of places where Donncha has added callbacks, so packaging my little piece as a plugin rather than a patch just isn’t possible.

      If you want to minify css/js automatically, you should just install Minify on its own. Take a closer looks at its docs — it already includes an index.php that you can use with mod_rewrite or whatever to send all CSS/JS through and have these files minified on-the-fly (including caching to the filesystem).

      As far as a WP plugin to gzip-compress and minify JS/CSS goes, the way WP Super Cache is written it doesn’t really make any sense to try to modify/reuse it for this purpose (either a separate second plugin or a new integrated does-it-all caching plugin would make more sense). I used to admin a really busy (top-10 technorati) blog, and wrote/used a custom WP plugin to cache using any/all of upstream reverse proxy (Squid), memcached and filesystem (like WP Super Cache) for storage. I would probably reimplement some of those ideas and do my own totally separate plugin if I wanted to integrate CSS/JS gzipping and minification. But that’s a couple-day project and pretty low on my priority list right now, sadly. :(

  • Awesome. You saved me from having to make this myself :) Let me know if you have any questions about Minify. BTW I’m a WP Super Cache fan!

  • […] WordPress users, lyncd has integrated Minify_HTML into the WP Super Cache plugin. (Minifying WP theme CSS/JS files is already pretty […]

  • This works really well, but requires manual modification of the files (the patch is out of date) and is erased when you upgrade WP Super Cache (which is expected). It is a nuisance to have to manually change the files each time WP Super Cache is updated, although it may be worth it for some sites.

    • Yeah, agreed re: nuisance. See my comments to Ghosttie — almost everything I’ve done is in a standalone class, but I couldn’t find any other way to hook this into WP Super Cache without hacking the code.

      Fortunately, the patch is just a couple of lines (I tried to keep hacks to bare minimum), so it’s pretty simple to just go in and make the edits manually, if applying it automatically fails. I totally agree that this isn’t ideal — if you can figure out a better way to do it, please let me know! Thanks for the interest.

  • FYI all, I’ve updated the mod to work with the current version of WP Super Cache, 0.9, and updated the install instructions and download links accordingly. The original files for use with Super Cache 0.8.x are still there, too.

    I wrote up a quick post with more info so there’d be some kind of notification in the feed — check it out for a little more info on what’s changed.

  • One user is experiencing an issue where JSMin seems to be returning " " rather than the adsense code.

    This might be due to your "JSMin::minify" callback syntax, which only became valid in PHP 5.2.3. Using array("JSMin", "minify") wouldn’t cost anything and would gain compatibility.

    • Nice timing, I think this is him on the update post.

      It looks like you’ve got it figured out already, thank you! I’m happy to change this to the old syntax to save everyone headaches.

      As a sysadmin I would be remiss not to mention that it is generally a seriously bad idea security-wise to be running outdated versions of PHP, as there are pretty regular security problems/exploits discovered, including some nasty ones since 5.2.3. Of course, I realize this is totally beyond many people’s control, but it is what they should demand of their hosting providers, too. There are some things (2.4 kernel!) where running old and stable on your servers is good, but running old releases of PHP5 is very bad!

      /end offtopic editorial

  • FYI, new release 0.3 to patch with WP Super Cache 0.9.1. Scroll back up to the updated install and versions sections! This release also makes the change suggested by MrClay for compatibility with pre-5.2.3 versions of PHP.

    No other/real changes made, so unless you want to update to Super Cache 0.9.1 or are running pre-5.2.3 PHP, the old “version” is the same as this one.

  • Thanx for this great plugin, but if i upgrade Super-cache minify doesn’t work anymore ; not bad i stay with the 0.91 version but in the future will you patch your great plugin ? Thx.

    • Yes, after a bit of a layoff I’m back in the WordPress game and will ping you when it’s updated. Parts of WP Super Cache where the patch inserts its hooks have been reorganized, so once I’m done tracing the new code and testing, I’ll have a new version.

    • OK, it’s done! My code is now a plugin to WP Super Cache, so no patches necessary, and it should not break in the future when Super Cache changes.

      The new version is on this separate project page. I’ll add an announcement post soon.

  • I have tried using minify only but the theme seems to break away when I use minify.. Does the plugin have any options to debug why the the CSS / JS breaks? Additionally how does the plugin compare against the W3 total cache?

    • This is just a plugin to WP Super Cache that runs Minify on HTML pages — including any inline style rules and JS. It does include an on/off button that it adds to the Super Cache options page in the WordPress backend, so if there’s a problem you can use that to debug whether it’s Super Cache causing the problem or the minification in particular.

      If you’re using it and you suspect your browser is computing style rules or script differently as a result of Minify, I’d suggest using your browser’s debugger. You can inspect the DOM, look at computed styles, and obviously there’s the JS console. i.e. Firebug for Firefox or Safari’s built-in debugger.

      If you think you find a real bug, report it to the Minify project … my plugin is just using the standard Minify lib and running it on page contents.

      I won’t get into comparing WP Super Cache to Batcache or W3 Total Cache, sorry.