Optimizing WordPress Websites
22 Oct
Website Speed
Recently a web client asked me if I could figure out why their page was loading so slowly. Simple enough question on the surface. Like any sensible web engineer I immediately opened Firefox enabled the Firebug plug-in and went to Net Panel. It was clearly evident after poking around for a few minutes that the WordPress site in question, which I built but didn’t do the design and image work for, was sized at just over a megabyte of which ~50% was images. In the scramble to get the site up and running I just took the images the designer handed me and plugged them in without any further thought then “Hey, those do look very good!” I informed the client that the images were hogging up a good bit of bandwidth and they should have a graphics expert put the images on a diet via PhotoShop. However, that other 50% of overall slowness that was not related to the images nagged at me.
Within the hour I had mentally resolved to figure out why the rest of the site was slow and apply anything learned to improving current and future site builds. My basic game plan after googling for a few hours and discovering YSlow was as follows:
- Serve the HTML gzip’ed and cached
- Serve the CSS/JS gzip’ed and cached
- Reduce the number of overall requests by combining CSS/JS files where possible
- Add Expires Headers
- Move as many images as possible externally
I know YSlow has some other recommendations, but the above are the really low fruit. With WordPress SuperCache enabled the first one is a no brainer.
The second one also seems like a no brainer – just enable apache’s mod_deflate and be done with it. Ah, but wait a minute. What if your host doesn’t have mod_deflate enabled? Even if they do have mod_deflate enabled you could just be pushing your servers CPU and memory to the limit by gziping everything on every request. Some argue to use a PHP script in conjunction with .htaccess to gzip on the fly. Again, your just straining the server needlessly all the time. The solution I settled on is to minify and gzip the CSS/JS files on the webserver into psuedo .gz extensions (e.g., *.css = *.css.cgz and *.js = *.js.jgz) with the following script:
#!/bin/sh
# minify and gzip css and js files, Apache .htaccess
# will deliver them to the client encoded
# WP core css files are not minified. All WP core css files and theme files
# are minified and then gziped. WP core js files are all already minified. Some of
# the theme files are also minified, but a few are not. Experiments show that
# minifying theme files caused rendering problems and gave very little
# optimization, so we don't bother to minify them.
yuicomp='yuicompressor-2.4.2'
# gzip all css files
for i in `find . -type f -name "*.css"`; do
echo "minifying and gziping $i"
java -jar $HOME/java/${yuicomp}/build/${yuicomp}.jar --nomunge $i > ${i%.*}.min.css
gzip -c ${i%.*}.min.css > ${i}.cgz
rm -f ${i%.*}.min.css
done
# gzip all js files
for i in `find . -type f -name "*.js"`; do
echo "gziping $i"
gzip -c $i > ${i}.jgz
done
Note, WordPress core JS files are already minified so you only need to gzip. Further, be careful minifying JS files as there are sometimes unintended consequences. Given the performance and headache trade-off I only gzip JS and don’t bother to minify.
Then add the following to .htaccess file:
RewriteCond %{HTTP:Accept-Encoding} gzip # serve gzipped css RewriteCond %{REQUEST_FILENAME}.cgz -f RewriteRule (.*)\.css$ $1\.css.cgz [L] AddType "text/css" .css.cgz AddEncoding gzip .cgz # serve gzipped js RewriteCond %{REQUEST_FILENAME}.jgz -f RewriteRule (.*)\.js$ $1\.js.jgz [L] AddType "text/javascript" .js.jgz AddEncoding gzip .jgz
Third item turns out to be a real hassle in WordPress. WordPress is a great CMS that offers a great environment for themes and a diverse selection of plugins. But the price is an architecture where components are spread about a large file tree in a fashion that makes it nearly impossible to combine CSS/JS files without threatening to break when WordPress core, plugin, and theme upgrades roll in which is frequently. I didn’t bother as it just seemed too dangerous to even think about touching with the proverbial ten foot pole.
Number four is another apache related issue. Either you have, or can have via your host, mod_expire enabled or you don’t. If you do then it’s just as easy as the following .htaccess line to get the ball rolling:
ExpiresActive On ExpiresDefault "access plus 1 week"
Remember, though, this assumes your server controls the request. If you have a large image file on your site that loads frequently and you moved it to Amazon S3 to reduce you load time and bandwidth (IMHO – probably a good move most of time) chances are the external host will not expire the image at all.
Lastly, try to move your big images to an external host like PhotoBucket. Let PhotoBucket deal with the overhead and if you need to pay them for a Pro account. It’s worth a mislay $20/year so that your loyal online readers don’t have to suffer through frequent slow page loads.
Speaking of loyal readers I have applied the lessons from this post to the site and it’s definitively faster!






No comments yet