Lee Willis

October 17, 2016
by Lee

WordPress performance tracking with Time-stack

I maintain a number of WordPress plugins, and they get used on all manner of WordPress sites. One of my more popular plugins is the WooCommerce Google Product Feed extension. This queries all products, applies some logic, and user-definable mappings and outputs an XML feed that Google will import into their product ad system.

On small stores, this is pretty straightforward, but on larger stores, the effort to query all products (including all individual variations of products) can be significant.

I’ve recently been doing some work on performance-tuning the plugin. I started out with some really simple performance tracking outputting total time and memory usage at the end of the XML document. There were some quick wins as a result of that, but it didn’t really give me a feel for what was going on, or any big gains.

I’m normally a big fan of the Query Monitor plugin for reviewing what queries are run to generate a page, however in this instance it doesn’t help since there is no HTML output to the page for Query Monitor to add its results to. I needed something that wasn’t tied to logging its output to the generated page. I finally settled on Time-Stack by Joe Hoyle.

There are actually two things you need to get up and running – the timestack “app” (repo linked above), and the WordPress plugin that logs the data. Once you’ve got the app installed, and the WordPress plugin activated, then every request will be tracked, and visible in the app:


You get to see the total runtime, and memory usage, but more importantly you can drill into sections of the page request to see further information. You can right down to the actual queries being run and see exactly what’s going on. You can even instrument your code to markup useful sections for your profiling.

How did I get on? I’ll let the evidence speak for itself …

Probably not for every site, or every occasion, but an awesome tool to have in the locker – thanks Joe!

October 14, 2016
by Lee

Autotrack for Google Analytics

If you’re in the web industry, you’re pretty much guaranteed to have heard of Google Analytics. It’s the de-facto standard in analysing user behaviour on websites. On any site you put together – it’s likely that you’ll set it up.

When you set up a site in the Google Analytics web interface you get a copy and paste snippet of code which gets you going in no time. This snippet links your website to the account you’ve set up in Google Analytics, and tracks each page that’s viewed on your site.

For many people this is everything that’s needed.


However, Google Analytics can be used for so much more. You can use it to track anything you want using event tracking (user clicked on call-to-action button, user downloaded PDF etc.), or by providing richer context about page views (this was a logged in user etc.). Here’s some of the things I’ve used Google Analytics to track in past projects:

  • On a site with a multi-field search (E.g. country, market sector, and keyword) track which of the fields were provided for each search, e.g. “Country Search”, “Country & market search”, “Keyword only search” etc.
  • Track events according to which adverts users were shown
  • Track custom events when people follow certain on-page nav elements

Historically I’ve used custom javascript to do this. Google provide good API documentation and the amount of code required isn’t normally significant.

Being familiar with what you can do with Google Analytics, on my new hill-walk blogging service I had a list of things I wanted to track. One of the things I wanted to track was selected external links. This can always be a bit hit and miss as there’s no guarantee that the tracking will fire before the browser navigates on to the clicked page.

So off I went to do a bit of research on the best way to handle the issue.

Tip: Even if you *know* how to solve a problem, have a quick check. Technology moves fast and there might be a better / easier way today than there was yesterday…

In my travels I came across the “autotrack” library by the Google Analytics team.

The library describes its capabilities (my emphasis):

Provides default tracking for the interactions most people care about, and it provides several convenience features (e.g. declarative event tracking) to make it easier than ever to understand how people are using your site.

The interesting bit for me was the nod to “declarative event tracking”. This basically means that you can have Google Analytics track events without writing and javascript, just by marking up your HTML. Here’s some example markup:

<a href="#" ga-on="click" ga-event-category="AdClick"
   ga-event-action="Ad category 1" ga-event-label="Seller one">
    <img src="https://placehold.it/100x100">

With the autotrack library installed, this will automatically take care of tracking a click when the link is clicked. The library takes care of using the best API for the visitors browser to maximise the chances of outbound links getting tracked.


The even better news is that everything we’ve talked about here is just one of the features available (via the eventTracker plugin for autotrack). The library also includes a variety of other plugins covering tasks such as cleaning up tracked URLS, visibility tracking, media query tracking, and page visibility tracking plus more.

Next time you need custom analytics – be sure to check out the Autotrack library.

October 13, 2016
by Lee

Error tracking with Sentry

One of the projects I’ve worked on recently is a rebuild of workflow system for a large business. The system processes large volumes of data 24 hours a day. It’s important that any errors with the system are flagged, tracked and investigated as soon as possible.

Another of the projects is a personal project I’m launching for Hill Blogging. This service is now in beta release with a handful of beta testers. I’m keen to identify, and squash any bugs without relying on beta testers reporting them.

Both of these projects use the Laravel PHP Framework (although neither Sentry.io, nor this post are Laravel specific!). So, I set about looking for a solution that would automatically track, and alert me to errors with Laravel. Any solution had to give me enough information to identify and start fixing the error.

On both of these projects I settled on Sentry.io. It’s a SaaS product that describes itself as:

Real-time error tracking [that] gives you insight into production deployments and information to reproduce and fix crashes.

This is pretty much everything I was looking for.


Sentry offers a Laravel integration out of the box. Simply install it, attach it to your project, and set up your project key. It’s a really straightforward setup. Once it’s set up, then any exceptions thrown in your code will get logged to Sentry, together with a backtrace. You’ll also be alerted to the new error.

You can take things further if you want by logging additional information with the exceptions if you need to, but the basic setup is sufficient to get you going.

Beyond Laravel, Sentry has libraries for common frameworks, and client libraries for most mainstream libraries, so it should be relatively easy to get going with.

There’s a range of pricing options depending on your likely error volume (zero – right!?) and users. The free tier is a great way to get started and offers support for 5,000 events/day (~150,000/month) at time of writing.

For me, it’s already more than proved its worth, not only in production, but also during development / staging phases of projects, helping me get straight to the broken code without having to rely on vague bug reports from users.

It’s worth noting that there are other similar services. In my investigations, I also looked at Rollbar and Airbrake – they may work better for you depending on your own circumstances.

October 13, 2016
by Lee

Stuff I’ve used

I was chatting with some fellow tech industry types the other day, when the conversation inevitably turned to cool (“useful”) software components that we’d used on recent projects.  It struck me that I’ve worked on a couple of projects (both client projects, and personal projects) that have had me trialling and using a variety of useful little libraries / services and approaches.

It also struck me that beyond the odd pull-request / issue raising on GitHub I’d not had any contact with the authors of said software to say thanks, nor had I really shared the knowledge about what I’d found and how I’d used it. The result was the following “commitment”

So, now I have to have a blog series covering software components / services that I use on projects.

I’m going to start with a service I’ve found really useful on a couple of projects recently, check out the first post in the series “Error Tracking with Sentry

April 19, 2016
by Lee

Looking ahead

I’ve spent the last four and half years working with a great team, on some fascinating, large-scale (predominantly Drupal) website builds. I’ve balanced that with a “spare-time” job building and selling WordPress plugins.

Working on WordPress plugins in my spare-time gave me the flexibility to experiment with things that interested me. I built some fun plugins, some useful plugins, and some boring-but neatly functional plugins. I’ve also learnt a lot along the way.

Selling some of those plugins has given me the flexibility to give up the day-job, and go out on my own full-time. So – as of early April, this my new office:

It comes complete with personalised mug from my ever-supportive wife Claire, greenhouse-style window display, and Bella the code-reviewing cat.

Going forward, my main aims are to:

  • expand my range of plugins – both free and paid
  • take care of some housekeeping and feature development on existing plugins
  • explore some other technical arenas

I’ll also be taking on some contract work (WordPress, Drupal, Symfony or Laravel for starters) to keep things interesting.

So far, I’ve released Cart recovery for WordPress, as well as its pro add-on, added new features to a few free, and paid-for plugins, done some R&D with Laravel and Ionic for future projects, and got a few nice contracts lined up.

Not a bad start – here’s to the future!

December 4, 2015
by Lee
1 Comment

Festive Wapuus

The latest version (2.4) of Wapuuvatar includes some lovely new Wapuus, including an evil Wapuu, Swedish Wapuu, Swiss Wapuu and Edu-Wapuu

It also features a festive Wapuu. As it’s starting to feel a bit like Christmas, it also includes a handy little filter that can be used to modify the Wapuu that is picked for a particular user. That lets you come up with fun things like festive_wapuu_for_everyone – a handy little snippet that will swap all of your Wapuuvatars for festive Wapuus during December 🙂

function festive_wapuu_for_everyone( $wapuu, $id_or_email, $hash ) {
        if (date('n') == 12) {
                return 'wapmas-wapuu';
        } else {
                return $wapuu;
add_filter( 'wapuuvatar_chosen_wapuu', 'festive_wapuu_for_everyone', 10, 3 );

November 17, 2015
by Lee


Everyone needs a fun project every now and then, something that’s not serious, doesn’t have deadlines, or fixed set of requirements. Something that you can just play with.

I first came across Wapuu at WordCamp London, where Scott Evans had designed an awesome Punk Wapuu which covered posters, stickers – and even scarves! (You can see some of the artwork here: https://london.wordcamp.org/2015/). It turns out that the Wapuu character was original developed by the Japanese WordPress community, released under the GPL, and has since been modified by many people for many different events / purposes.

Every better – they’re maintaining an archive of publicly release Wapuu interpretations.

Coincidence struck when I was:

a) Looking for a just-for-fun project to soothe my soul

b) Stumbled upon a tweet by @NickHamze

Well, I couldn’t resist – the timing seemed just right 🙂

So if you want your WordPress avatars to be cute Wapuus in various poses – the wait is over – check out Wapuuvatar on GitHub – or download it from WordPress.org.

by Lee Willis

Uses Wapuus from the Wapuu archive as your site avatars.


  • Current version: 2.5
  • Rating: 100(3 ratings)
  • Downloaded 716 times

March 22, 2015
by Lee

WP-CLI import and export for Say What?

I’ve been at WordCamp London for the last two days (An excellent event, you should definitely consider it if you’re into WordPress and are in – or can get to – the UK). There were a fair few talks about making the admin area of WordPress better by customising according to the site architecture.

This is something I’ve always been an advocate of – particular on sites that go beyond simple posts and pages. One of my plugins provides some of the tools that can help with this. The “Say What?” string replacement plugin for WordPress allows you to override strings from WordPress core and/or plugins that you’re using so you can personalise the phrases that are used to your particular use case.

I took the opportunity to make some small updates to the plugin over the last few days. Particularly I’ve extended the plugin to have support for WP-CLI. This allows you to import and export string replacements – particularly useful if you have a standard set (or sets) of replacements that you use on sites you build. You can also use it to get a list of all replacements you currently have set up on your site.

Generating a list of replacements

$ wp say-what list
| string_id | orig_string | domain | replacement_string | context |
| 3         | Tools       |        | Lee's tools        |         |
| 9         | Dashboard   |        | The dashboard      |         |

Exporting your replacements

This will ‘export’ all of your replacements in CSV format to the file /tmp/my-replacements.csv. This file is in the same format you need for importing back into the site, or into another site.

$ wp say-what export --format=csv > /tmp/my-replacements.csv

Updating replacements

Sometimes you might want to export a set of replacements, edit them, and then re-import. You can do this with the ‘update’ command – this will update any items with a string_id provided, or insert any items without a string ID. The following command will read in the file /tmp/my-replacements-amended.csv and update the database.

$ wp say-what update /tmp/my-replacements-amended.csv

Importing replacements

If you just want to add the replacements in a file to the database, you can use the ‘import’ command. This will insert each item in the file as a new item in the database.

$ wp say-what import /tmp/my-replacements-new.csv

Trying it out?

You can grab the plugin from WordPress.org – or check it out on GitHub – thanks to WordCamp London for the inspiration!

October 30, 2014
by Lee

Default Lowest Shipping Choice on WP e-Commerce

The WP e-Commerce plugin no-longer defaults the cheapest shipping option at checkout. This can be great if you want customers to consider other shipping options that may be beneficial for them (For example quicker delivery, insurance etc.).

If you do want it to default to the cheapest option, try this simple plugin:

WP e-Commerce Default Lowest Shipping Choice
by Lee Willis

A straightforward plugin that makes WP e-Commerce checkout default to the lowest available rate when first populatingshipping choices.

The plugin’s available for forking and contribution over on GitHub


  • Current version: 1.2
  • Downloaded 188 times

October 28, 2014
by Lee

Change order of payment gateways in Easy Digital Downloads

Easy Digital Downloads lets you enable multiple payment gateways to give customers a choice about how they want to pay. The core plugin also lets you choose a default option, but it doesn’t let you choose the order that options are presented at checkout. That can lead to odd UX where the default selected option appears second, or third in the list:

Screenshot from 2014-10-28 22:10:46

Fortunately, it’s pretty easy to change this order – simply paste the following function into your theme’s functions.php file, or use a functionality plugin. Just change the $gateway_order array to the gateways you have enabled, in the order you want them, and you’re good to go.

function lw_edd_enabled_payment_gateways($gateways) {
	$gateway_order = array(
	$new_gateways = array();
	foreach ( $gateway_order as $gateway ) {
		if ( ! empty( $gateways[$gateway] ) ) {
			$new_gateways[$gateway] = $gateways[$gateway];
	return $new_gateways;

Here’s what our revised default checkout looks like – much neater.
Screenshot from 2014-10-28 22:15:48