gzip + WordPress + 💫 = 😎

Ok, so what does the blog title actually mean? Well it’s my conclusion to some of today’s research, it means the following:

gzip compression with a WordPress install and a sprinkle of magic equals… put your feet up, you’ve just made your pages load faster, and you’re in google’s good books

Quick pointers on using gzip with WordPress

This post is a quick summary with some code to accompany my presentation for Cardiff WordPress MeetUp (I may come back and add to it at a later date).

Below I’ll run through the following:

  • Using a WordPress plugin for compressing css and js.
  • Speed improvements and PageSpeed Insights Results
  • Using a task manager like gulp with a gzip task

Use a plugin to gzip your css and js files

I found a plugin that worked well for gzipping assets, it’s called Merge + Minify + Refresh and can be installed through the plugin install page at your WordPress dashboard.

Once installed and activated, be sure to click the enable gzip option, copy the code snippet from the docs into your .htaccess or grab it from below.

#Serve gzip compressed CSS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]

#Serve gzip compressed JS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]

#Serve correct content types, and prevent mod_deflate double gzip.
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=is_gzip:1]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=is_gzip:1]
Header set Content-Encoding "gzip" env=is_gzip

Using this plugin for gzipping and minifying assets, I saw PageSpeed Insights for my test website soar from 73 (Needs work) to 85 (Good). Not bad for 5 mins work!

We can go a step further, and instruct our server to gzip files on the fly if they’re not already available in the gzip format, e.g. svg’s or even the text/html. Paste the following into your .htaccess to compress the files types that are listed (don’t worry , this won’t interfere with files that are currently gzipped).

<IfModule mod_deflate.c>
 # Set compression for: html,txt,xml,js,css
 AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css application/javascript application/x-javascript image/svg+xml
 # Deactivate compression for buggy browsers
 BrowserMatch ^Mozilla/4 gzip-only-text/html
 BrowserMatch ^Mozilla/4.0[678] no-gzip
 BrowserMatch bMSIE !no-gzip !gzip-only-text/html
 # Set header information for proxies
 Header append Vary User-Agent
</IfModule>

Before and after, meaningful numbers

For the fairly modest test site, I saw the following gains when using the Merge + Minify + Refresh plugin.

Fibre – fast connection results – before and after gzipping assets


3G slow connection results – before and after gzipping assets

Visitors on fast connections might not notice a page loading ~150ms faster, but I’m sure mobile visitors would appreciate 3 second decrease in page load time.

For any site that were resource heavy (more plugins, more styles / custom scripts) I would expect the improvement of compressing to be more significant.

Gzip for theme builders and developers

/* 
** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
** Build task
** Compile sass to css, then minify, then gzip
** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
*/

gulp.task('build', ['sass', 'minify-css', 'compress-css'] );

gulp.task('minify-css', ['sass'], function(){
  return gulp.src(['css/*.css', '!css/*.min.css'])
    .pipe($.uglifycss({
      "maxLineLen": 80,
      "uglyComments": true
    }))
    .pipe($.rename({
        suffix: '.min'
    }))
    .pipe(gulp.dest('css'));
});

// Compress css, define minify css as a dependant task
gulp.task('compress-css', ['minify-css'], function(){
  return gulp.src('css/*.min.css')
    .pipe($.gzip())
    .pipe(gulp.dest('css'));
});

Theme developers will probably prefer a solution that’s easy to integrate into their build process. Above is part of my typical gulp build process, an example of how I minify and gzip css.

  • The build task runs sass (but you don’t necessarily have to).
  • Then the minify-css task  minifies the css files and adds the suffix .min
  • Then the compress-css task gzips all *.min.css files, and leaves the .min.css files intact for browsers that don’t accept gzip encoding. Simples.

This build process can be replicated for building javascript, or other gzippable assets.

Similarly to the author of Merge + Minify + Refresh, I use the following in my .htaccess file.

#Serve gzip compressed CSS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.css $1\.css\.gz [QSA]

#Serve gzip compressed JS files if they exist and the client accepts gzip.
RewriteCond %{HTTP:Accept-encoding} gzip
RewriteCond %{REQUEST_FILENAME}\.gz -s
RewriteRule ^(.*)\.js $1\.js\.gz [QSA]

#Serve correct content types, and prevent mod_deflate double gzip.
RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1,E=is_gzip:1]
RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1,E=is_gzip:1]

<FilesMatch "(\.js\.gz|\.css\.gz)$">
  # Serve correct encoding type.
  Header append Content-Encoding gzip

  # Force proxies to cache gzipped & 
  # non-gzipped css/js files separately.
  Header append Vary Accept-Encoding
</FilesMatch>

Plugin vs gzip at build

I found that both using a WordPress plugin, and gzipping  at theme build time to work reasonably well.

I’ve been using gzip with gulp for some time now, over the past 6 months I’ve have had zero problems.

I’ve spent only a few hours today with Merge + Minify + Refresh (other asset compression plugins are probably available) and it has performed well! I noticed one minor issue with the way that it concatenated (merged) files, this is no fault of the plugin author, just the nature of easy to use plugins.

<link rel='stylesheet' id='css-0-css' href='http://lab.web-shed.com/optimise-wordpress/wp-content/mmr/45320728-1478359714.min.css' type='text/css' media='all' />
<link rel='stylesheet' id='twentyseventeen-fonts-css' href='https://fonts.googleapis.com/css?family=Libre+Franklin' type='text/css' media='all' />
<link rel='stylesheet' id='css-1-css' href='http://lab.web-shed.com/optimise-wordpress/wp-content/mmr/631f08d7-1492503758.min.css' type='text/css' media='all' />

Above, is a snippet of the source that the plugin gives us. It’s not ideal to have some of our merged and minified css before and after the google font css. This is related to the order in which they are enqueued.

One group of css files has been enqueued before the google font, and another group after. The result is 2 minified .css files, where ideally we would only need to serve 1. This could be fixed by tweaking the enqueue priorities, but probably would never be an issue if we were to concatenate css at build time using a task manager like gulp instead of the WordPress plugin.