Posted on Leave a comment

Caching Dynamic CSS in WordPress with URL Rewriting

Lately, I’ve been focusing a lot on improving website performance – getting sites to load as quickly as possible – sometimes in less than a second. W3 Total Cache handles just about every aspect of website performance. Page caching alone is a huge benefit to website load time on the first visit, and when you optimize browser caching for static resources, that makes navigating to other pages even faster. Add a CDN, and your static resources such as images, css files, and js files get downloaded at blazing speeds and take the load off your web server. Minification and file combining can help, but this can be tedious if you need to do it manually.

The Problem

One problem I have come across, though is some plugins and even themes that use dynamic css referenced as a separate file using a query string. A few culprits that use this method are the jQuery Accordion Menu Widget, the jQuery Mega Menu Widget, and even the latest version of PageLines.

Dynamic CSS?

Dynamic CSS does have some advantages – for one, it allows for a more user-friendly interface to configure various styling options without having to include lots of different css files for each option and as a result, can be a lot easier to maintain. The problem is that since the stylesheet doesn’t actually exist (it’s just the output of a php file based on a template css file), it never gets cached, so every time someone visits your site, it has to be generated and downloaded again. This means your visitors are going to be waiting longer for your pages to load. Not to mention, if you’re using a CDN, it won’t get processed properly.

So, how do we fix this?

One option is to just view the source and copy the stylesheet path including the variables into your address bar, copy the generated css, paste it into your theme’s stylesheet (or a separate one, if you like), and either set the widget to not use a skin (you’ll also have to copy the image resources into the proper location on your theme) or comment out the section where the dynamic php is referenced in the plugin/theme. I haven’t looked at how this is handled in Pagelines, but in the jQuery Mega Menu plugin, the stylesheet is simply echoed, so you can’t just dequeue and re-enqueue outside of the plugin, unfortunately.

URL Rewriting

We can handle this with a bit of URL rewriting. The first step is to get Apache to point our fancy url to the actual URL. The method used is one I found in an article  on Terminally Incherent. Of course, I had to modify it a tad to get it to work for my purposes, but this is was the end result:

[code]

<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine on
RewriteBase /wp-content/plugins/jquery-mega-menu

RewriteRule ^([^/]+)-([^/]+)\.css$ skin.php?widget_id=$1&skin=$2 [NC]
</ifmodule>

[/code]

This will actually work for both jQuery Accordion Menu Widget and jQuery Mega Menu Widget, as they both use the same filename and query string (of course, you’ll need to change the rewrite base accordingly). This file goes inside the specific plugin folder, not the root or your site.

This will let us reference the dynamic stylesheet with a url that looks like an actual file. For example, if I’m using widget_id 2 with the “white” skin, the original url would have been:

http://somesite.com/wp-content/plugins/jquery-mega-menu/skin.php?widget_id=2&skin=white

but now, we can use:

http://somesite.com/wp-content/plugins/jquery-mega-menu/2-white.css

The second half is actually making the plugin reference the stylesheet using the fancy url, and we’ll need to modify the plugin to make this happen.

This file doesn’t actually exist, but since it looks like a file and doesn’t have any query strings, it can be cached, and it can also be mirrored by your CDN.

[code language=”php”]

change

.”/skin.php?widget_id=”.$key.”&amp;skin=”.strtolower($skin).”\”

to

.”/”.$key.”-“.strtolower($skin).”.css\”

[/code]

And that’s it! your css will now be cached and/or mirrored by your CDN, which should cut at least 200ms off your load time.

The Proof

Before:

 

 

 

 

After: