Updating WooCommerce: Our Safe & Thorough Guide

We’ve had a lot going on at Delicious Brains HQ recently; releasing this and that, planning new products, and generally pushing the envelope. However, that has meant some things have slipped behind and we haven’t updated WooCommerce on deliciousbrains.com for a while! 😱

As the site is now my main priority, it came to me to update it from 3.1.2 to 3.3.5. WooCommerce is a big ‘ol ecommerce plugin that is integral to our business (along with a big subscriptions addon, custom API, and lots of bespoke code), so doing any kind of update to it is a scary, cold sweat inducing task.

So let me take you through my guide to updating WooCommerce which will hopefully help you in the future and will be a resource I will use myself next time an update is needed.

A Strong Foundation

Step one, log in to your live site and press update. Joking!

The ‘never update important plugins directly on live’ is a commonly espoused mantra that is worth repeating here:

Do not update plugins on live before testing them out.

Always use a copy of the site to test them – so you can perform updates to it, test, and ultimately don’t care if things go south.

We develop on a local copy of the site and also have a staging copy for user testing, which is pretty simple to set up because we have the site version controlled with git and managed with Composer, so to spin up a new version of the site is as simple as git clone ... and composer install. Well, not quite that simple, as with all WordPress sites you need to consider the database and the media library. Luckily for us, we know a couple of plugins that handle that for us!

WP Migrate DB Pro makes it a cinch to pull down a fresh copy of the live database so we can work on an exact copy of live before making updates. Even a simple export using the plugin is handy as a starting point for a local install. We also use WP Offload S3 for offloading our media library to S3, which means all the images are served from CloudFront even on our local site and we don’t need to worry about FTP’ing our wp-content/uploads directory or using the WP Migrate DB Pro Media Files addon to get the files locally.

When working on an ecommerce site there are a couple of other important things to take into consideration.


In the past I’ve used the value WP_DEBUG constant to determine which environment the site is running on, but this is too simple as we have it turned on for our live site so we can proactively catch errors happening and fix them. Each of our three environments need separate configuration (e.g. database name and credentials), so we load the correct environment config in wp-config.php (keeping database credentials out of git), and we can use the conditional to set up some useful environment constants:

if ( file_exists( dirname( __FILE__ ) . '/live-config.php' ) ) {
    define( 'WP_LOCAL_DEV', false );
    define( 'DBI_STAGING_SITE', false );
    include dirname( __FILE__ ) . '/live-config.php';
elseif ( file_exists( dirname( __FILE__ ) . '/staging-config.php' ) ) {
    define( 'WP_LOCAL_DEV', false );
    define( 'DBI_STAGING_SITE', true );
    include dirname( __FILE__ ) . '/staging-config.php';
else {
    define( 'WP_LOCAL_DEV', true );
    define( 'DBI_STAGING_SITE', false );
    include dirname( __FILE__ ) . '/local-config.php';

This means that we can only load some code for specific environments. For example, we add the test credit card numbers for Stripe to our checkout form only on development or staging sites:

<?php if ( WP_LOCAL_DEV || DBI_STAGING_SITE ) : ?>
    <div class="test-credit-cards">
        4242424242424242<br />
        5555555555554444<br />
        378282246310005<br />
<?php endif; ?>


When testing aspects of WooCommerce and our ecommerce processes, for example, license auto renewals, new orders are generated for customers and emails are sent. We want to test the emails and check the content, but we don’t want them to actually be sent to the customers. We’ve used a couple of approaches in the past, but the simplest is probably a local filter to hijack the email To address:

function my_site_hijack_all_mail( $args ) {
    $args['to'] = ‘[email protected]’;

    return $args;
add_filter( 'wp_mail', my_site_hijack_all_mail, 100 );

The downside to this approach is that emails are still getting sent using Mailgun, which is a waste of our monthly email limit just for local testing. A better approach is to use a free service like Mailtrap, and then add this to an mu-plugin on the testing site:

add_action( 'phpmailer_init', 'mailtrap' );
function mailtrap( $phpmailer ) {
    $phpmailer->Host     = 'smtp.mailtrap.io';
    $phpmailer->SMTPAuth = true;
    $phpmailer->Port     = 2525;
    $phpmailer->Username = '{mailtrap username}';
    $phpmailer->Password = '{mailtrap password}';

Mailtrap gives you an online inbox for checking the emails:

Mailtrap inbox

Payment Gateways

We use both PayPal Express and Stripe payment gateways on the site and routinely put through test orders, upgrades and renewals as part of any testing of new features to the site. Of course we don’t want them going through the live gateway so we have configured our PayPal Sandbox credentials and Stripe test keys in the WooCommerce settings.

We also have some extra code in a mu-plugin that ensures the correct payment gateway mode is used for the environment of the site:

// Always use PayPal Express test mode when on dev or staging
add_filter( 'option_woocommerce_paypal_express_settings', function( $value ) {
    if ( ! WP_LOCAL_DEV && ! DBI_STAGING_SITE ) {
        return $value;

    $value['environment'] = 'test';

    return $value;

// Always use PayPal test mode when on dev or staging
// The standard PayPal gateway controls IPN and other URLs even if using PayPal Express gateway.
add_filter( 'option_woocommerce_paypal_settings', function( $value ) {
    if ( ! WP_LOCAL_DEV && ! DBI_STAGING_SITE ) {
        return $value;

    $value['testmode'] = 'yes';

    return $value;

// Always use Stripe test mode when on dev or staging
add_filter( 'option_woocommerce_stripe_settings', function( $value ) {
    if ( ! WP_LOCAL_DEV && ! DBI_STAGING_SITE ) {
        return $value;

    $value['testmode'] = 'yes';

    return $value;

What’s Changed

Before upgrading WooCommerce locally it’s a good idea to have a read through the changelog and any other posts from the team to try and understand what has changed and how it might affect your site.

WooCommerce also has a great guide themselves for updating the plugin.

Because we manage WooCommerce with Composer and don’t store it in git, it’s harder to see an actual diff of the plugin files when updating. So it can be helpful to download the plugin zip of the version you have currently, unzip and git init && git add . && git commit -m “Initial”. Then download and unzip on top of that directory the most recent version of the plugin and use a diff tool to inspect exactly what has changed in the files. For the most part this is overkill, but a good option to know of.


The next step is to update the plugin on your NON-PRODUCTION site. Once you’ve updated there are some other things to consider.


If your theme is built by another developer then hopefully an update is available for it. Or, if like us, you have overridden some of the core template files in your theme then you should check if they are out of date via the settings screen wp-admin/admin.php?page=wc-status:

WooCommerce template status panel

If any templates are flagged as outdated you will need to inspect the core template files to see what has changed and then apply those same changes to your theme’s template files where appropriate.


Most sites running WooCommerce will have installed some addons to enhance its functionality. We run a number of other plugins to add functionality such as payment gateways, managing software license keys, and printing invoices. These plugins are dependent on WooCommerce core and therefore need to be updated where necessary to keep compatibility with WooCommerce itself. The same status page lets you know which plugins aren’t compatible so you can update where necessary.


Most releases of WooCommerce require an update to the database and this will be prompted after updating the plugin. Test this out to make sure it runs successfully on your test database, and ensure any custom code that accesses the WooCommerce data still runs as expected. We certainly had some fun updating our custom API and other bits of code to cater for the change to how product parent/child relationshsips are stored in the database introduced in version 3.0.


After all the updates have been made we need to test that things haven’t been broken by one of the many moving parts involved in a WooCommerce update. The testing approach will be specific to the site you are running so it’s best to write down a list of scenarios that need to be tested that emulate the majority if not all of the actions customers will run on your site. For us, that includes:

  • Purchase with PayPal
  • Upgrade of that order with a credit card via Stripe
  • New purchase with a credit card via Stripe
  • Auto renewal of a license
  • Downloading plugin zips from order screens and customer area

That’s pretty much the main important functions of the site, but other aspects to test can include:

  • Applying coupons
  • Testing cross-sell coupons
  • Managing coupons in the admin
  • Refunding orders
  • Adding new products

Make sure you have your wp-config.php set up to log errors to wp-content/debug.log:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);

While you are testing the site, monitor the log and watch for fatal errors, notices, warnings and deprecated notices, which will help you identify areas of code that need updating, or other plugins that need fixing.

One of the jobs on my rather large to-do list is to set up some automated tests for this to save time in the future and probably have them running continuously on staging. I might dive into that further in another post.

Pulling the Trigger

Once you are happy everything is working as expected on your test site, ideally locally and on staging, then it’s time to perform the update on live. Before doing so it’s always a good idea to take a backup of the live database (and site files if they aren’t managed in version control) before starting out so you have a restore point if things go wrong.

Press update, composer update wpackagist-plugin/woocommerce, or deploy in your usual way. Then login and kick off the database upgrade, when required, from the dashboard. Clear any caches and then visit your site from the frontend and poke around. Test a customer journey from pricing page to adding products to the cart. Better still, use a 100% coupon to make a test purchase (or refund it later) to just double check everything is working as expected.

We generally let the whole team know an update has just been deployed so they can be on the lookout for any support tickets related to orders that can’t be processed or other strange behavior on the site.

Wrapping Up

Who said managing a WordPress site was easy?! It’s no joke, especially when you add plugins like WooCommerce to the mix. But I hope this guide gives you some confidence in the update process for next time, I know I’ll be re-reading!

What processes do you use for making updates less stressful? Do you perform any automated testing of your WooCommerce sites? Let us know in the comments.

About the Author

Iain Poulson Product Manager

Iain is a product manager based in the south of England. He also runs multiple WordPress products. He helps people buy and sell WordPress businesses and writes a monthly newsletter about WordPress trends.