Programmatically Update Settings in Staging

When developing WordPress sites I generally have three environments: live, staging, and local. Since I like my staging environment to be a very close replica of production, I frequently overwrite the database and files in staging. This is especially true when working with a host like WP Engine that has one-click staging environments.

However, when the database is overwritten in staging, there’s a generally a few settings that still need to be different from production. For instance, with WooCommerce sites, I may need to deactivate SSL and put Stripe into testing mode.

Occasionally I’ll also need to deactivate certain analytics plugins or third-party API integrations like MailChimp.

After making these updates manually for months, I finally moved to a programmatic update routine for many of my sites. The code basically just checks which environment we’re in. If it’s one of the staging environments and the update script hasn’t been run already, it runs it.

Update Routine Code

Here’s example code for the update routine, which I’ll explain in more detail underneath:

<?php
/**
* Update site to use test mode in local and staging environments
*/
function prefix_env_settings() {
// If settings have already been updated, return early
if ( 1 == get_transient( 'staging-settings-updated' ) ) {
return;
}
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
// Define test environments
$test_envs = array(
'https://example.dev', // Local
'https://example.staging.wpengine.com', // Staging
);
// If site is a test environment
if ( in_array( site_url(), $test_envs ) ) {
// Use Stripe in test mode
$woocommerce_stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
if ( 'yes' != $woocommerce_stripe_settings['testmode'] ) {
$woocommerce_stripe_settings['testmode'] = 'yes';
update_option( 'woocommerce_stripe_settings', $woocommerce_stripe_settings );
}
// Disable outbound emails
deactivate_plugins( '/sendgrid-email-delivery-simplified/wpsendgrid.php' );
activate_plugins( '/disable-emails/disable-emails.php' );
// Transient is set for 24 hours
set_transient( 'staging-settings-updated', 1, ( 60 * 60 * 24 ) );
error_log( 'staging-settings-updated' );
}
}
add_action( 'init', 'prefix_env_settings' );

Check Environment

I used to have the script always run unless it detected it was in production, i.e.:

if ( 'https://example.com' == site_url() )

But I realized this could be dangerous if the site_url ever got updated on production by mistake. Explicitly setting the stage and local environments where the script should run seemed safer.

Use Transient to Check if Settings Updated

We don’t need the update routine to run constantly, just once after the database has been overwritten. We may even want to re-enable some of those plugins or change a setting back in order to test something specific in staging.

This is where the transient comes into play: get_transient( ‘staging-settings-updated’ ). A transient is basically an option that expires after a specific amount of time. In this case, if the transient has already been set, it means the update routine has run and we don’t need to run it again. For this example, I have the transient expire after a day- but you could set this as long as you like.

About Devin

I'm a WordPress developer based in Austin, Texas. I run a little theme shop called DevPress and work for a startup called Nano. Find me on twitter @devinsays.

5 Responses

  1. Funny, I’ve just started thinking this week about how to automate stuff like this and it was great to see in the “Call for features” for WP4.4 on the Make blog lots of people suggest some kind of environment system.

    It occurs to me that there’s a number of ways to achieve this:

    1) Actual environment variables on the server
    2) Constants in wp-config.php
    3) The options table

    But what I think would be REALLY hand is two things in core. No! Actually, they can be one thing. (I’m thinking on my feet!):

    Environment-specific settings.

    I don’t know how this would work out. Maybe an extra column in wp_options would be best. But I envisage that there is a default environment, and all settings in this default environment take effect unless they are overridden. And then there are specific environments; so if an options entry has an environment specific option then it takes precedence over the default.

    Then you just have a simple constant in wp_config.php that sets the environment.

    I’m sure this isn’t thought through and there will be things like serialised data to take into account, and there will be some kind of UI, but something like this seems like a great concept.

  2. Thanks for sharing your setup, Devin. Automating something like this is a great plan.

    I know there are often lots of ways of solving a problem. It seems the WordPress Pre Option Filter might be another choice and might eliminate the need for a transient.

    Of course a working solution is better than any theoretical idea :)

    Thanks again for sharing.

Leave a Reply