WordPress Minify – Best Practices
Everyone wants their pages to load fast because that makes visitors and search engines happy. WordPress itself is lightweight and optimized for speed, but when plugins and themes come into play, performance can suffer a lot.
As I have pointed out in a previous article, speeding up WordPress is firstly a developer’s duty. The thing is, if a huge number of plugins are loaded on a single page, it’s nearly impossible for anyone to speed up a WordPress site simply by optimizing codes.
One of the most significant components of the World Wide Web that affects page load time is HTTP request. The number of HTTP requests, the time they take to get responses from a server, as well as the size of responses all contribute to your site’s sluggish performance.
WordPress Minify to our rescue
To do that a method called “Minifying” can be used, which consists of two consecutive steps:
Step 1: Minify files contents. Definition from Wikipedia:
Minification is the process of removing all unnecessary characters from source code without changing its functionality. These unnecessary characters usually include white space characters, new line characters, comments, and sometimes block delimiters, which are used to add readability to the code but are not required for it to execute.
Step 2: Combine minified files (concatenation). It is the process of joining several files into one so that they can be served using just one HTTP request.
WordPress users often use an on-the-fly minifying solution as it provides the most dynamic approach: plugins or themes can be activated/deactivated whenever needed and minified contents are updated automatically. For that reason, minifying in this article is understood as on-the-fly minifying.
Best Practices: Minify with care
Many users activate a minify plugin and expect it to just work. This is simply wrong on many levels.
Not all files can be minified, i.e. they simply break when minified. Some are minifiable but break as soon as they are combined with other files (see BWP Minify’s compatibility report for more info).
Problematic files can be detected by excluding files one by one in the minification list. If you are using BWP Minify, navigate to BWP Minify > Manage Enqueued Files and try excluding (i.e. ignoring) files there. It is recommended that you ignore 3-5 files at a time to make this process a little bit faster.
Files that are already minified should not be minified again, to save processing time and in turn improve server response time. Typical examples are files enqueued internally by WordPress, such as
If you’re using BWP Minify, there’s a trick to not minify pre-minified files but still combine them: simply put ‘min‘ in the files’ names, e.g.
For filenames that you don’t have control over, you have to again navigate to BWP Minify > Manage Enqueued Files and ignore them entirely. Note that ignored files are handled by WordPress and will not be combined with other files for now.
Less is more
On-the-fly minifying means the minifying script must locate, minify, and combine each enqueued file every time it is requested. For that reason, an initial load (mostly without cache) can spike up to 9-12 seconds, or even higher, in processing time. It’s like opening several files on your computer and then trying to replace all linebreaks with blank spaces in all opened files at once (you know how slow that could be).
An easy solution is to reduce the number of files that are combined in one go. So instead of minifying 40 files in one single request, you should have four requests with 10 files combined each. This makes use of parallel download capability of browsers, like using a download manager. 4 smaller requests that are downloaded at the same time is much better than one heavy request that could result in timeout.
See Connections per Hostname column on this page to know the parallel download limit for some major browsers.
More Best Practices – Minify the Jedi-Master way
Minifying without cache-expiry headers is like (again) driving a racing car without a brake.
If you have no idea what a cache-expiry header means, check out this useful article for a brief introduction.
For minifying to work best, you will need either the
Cache-Control header or the
Expires header. With these headers properly set, a HTTP request for minified contents is only needed when cached contents has expired.
Setting the value of a cache-expiry header to a far future date is highly recommended, especially on live environments. It’s enough to use just
Cache-Control, but it’s safe to use both. Note that
Cache-Control will take precedence in modern browsers.
Dynamic to static
Instead of serving minified contents directly via PHP, let the server does the job. That sounds easy and obvious, but how do you keep the dynamic nature of plugins/themes at the same time?
The answer is to generate minified contents normally, but cache them somewhere and then make them publicly accessible for all future requests. PHP is only needed when the cache is invalid (not found or expired) or a forceful request is issued.
Such approach not only eliminates the needs to make a roundtrip to PHP every time, but also allows you to use nice names for minified contents, such as
On a side note, the best place to put minified contents for WordPress is inside
wp-content. If you use a cache plugin, chances are there’s already a
cache directory there, ready to be utilized.
Most minifying plugins provide this feature, but since I’m biased, check out BWP Minify’s Friendly Minify Url feature, which has the same implementation as described above.
Use different caching mechanisms
When you first hear about caching, the most likely presented mechanism is file caching where contents are cached by storing them as files on disks. If your site has a fairly high number of visitors per day, this caching mechanism can be inefficient (it’s disk I/O after all, and it’s slow).
It’s much better to use memory caching mechanism to store and serve cached contents. Just think of your server as a regular PC, and your softwares will obviously run faster when they read data from memory instead of disks.
There are many ways to serve minified contents using memory caching. If Minify is the PHP library you’re using, you can customize its config file to use a specific PHP accelerator such as APC or XCache. You must of course properly configure the desired accelerator on your server prior to modifying the config file.
If you’re new to memory caching, APC’s documentation can be a good start.
Pre-minify for the win
Whatever approach you take to serve minified contents, an initial load can still be an issue. Any visitor that views your site when cache is invalid will surely notice a slowdown in page load time. To save that poor soul, you need to find something else to carry such burden, and cron job is the way to go.
The idea is to use a cron job to periodically visits a few unique pages on your site to force a refresh and cache on minified contents, so that when a visitor pays a visit it’s the cached version that he/she sees. Your site’s homepage, a post, a page or any other special ones can be considered unique.
If you want to refresh minified contents every time you activate/deactivate a plugin, simply call your refresh function every time
upgrader_process_complete action hook is fired, using
“With great power comes great responsibility”. To fully enjoy the benefits of Minifying, you need to understand common pitfalls and make sure that you follow best practices whenever possible.
I hope you find this article useful, and as always, comments and feedbacks are welcomed!
If you want to know more about HTTP requests and how they affect site performance, check out this classic: Steve Souders’ High Performance Web Sites.
- http://www.php.net/manual/en/function.header.php [↩]
- http://httpd.apache.org/docs/2.2/mod/mod_headers.html [↩]
- http://nginx.org/en/docs/http/ngx_http_headers_module.h ... odule.html [↩]
- http://www.centos.org/docs/5/html/Deployment_Guide-en-U ... tasks.html [↩]
- http://codex.wordpress.org/Function_Reference/wp_schedu ... dule_event [↩]
- http://codex.wordpress.org/Function_Reference/add_actio ... add_action [↩]