Managing wp_options in Git

Hi everyone,

I’m new to roots/bedrock and wish I had found it before trying to hack out something similar with shell scripts… glad to see someone is doing it right. I’m now in the process of migrating to bedrock.

One thing that I’m trying to figure out is the pain of keeping the WP DB in sync across environments, especially wp_options. It seems like in WP-land a complete DB sync is the only popular option. In modern development of course your config settings are as vital as code to track, stage and test, and older stacks like WP make a mess of this.

The way I’m trying to manage this is to store important wp_option values in text files in source control. In my Wordpress git repo I have a folder like the following:

etc/wp-options/
  current_theme.txt
  easy-social-share-buttons.json
  permalink_structure.txt
  tantan_wordpress_s3.json
  thisismyurl_custom_media_fields.json

The .txt files are simple key-value pairs, and the .json files are complex option objects. The name of the file == the option_name field in the wp_options table.

I have a shell script that uses wp-cli to update a WP db with the contents of this folder:

function wp_option_update {
  for path in `find etc/wp-options -name \*.json`
  do
    filename=$(basename $path)
    wp option update ${filename%.*} --format=json < $path
  done

  for path in `find etc/wp-options -name \*.txt`
  do
    filename=$(basename $path)
    wp option update ${filename%.*} "$(cat $path)"
  done
}

This way I can rev the site options like I would any other code. It is a bit painstaking in that any time I change an option I have to dump it to a file, but on the other hand it makes it easy to ensure option parity across environments. When I deploy to staging or prod, the deployment script clobbers whatever options are set in the database with whatever is in this folder, so I know that things are up to date. Also it’s a workflow that’s more friendly to continuous integration/deployment in that I test out a setting locally, commit/push it and my work is done - I know that any CI tests I run will be accurate against that change, and that all environments will be in sync when deployment is complete (I use Travis CI and each commit is automatically deployed to prod). If something goes wrong I can roll back the change with another commit.

Just wondering how others are handling this, and if there’s a better way. Also wondering if the roots/bedrock team is considering some kind of solution to this problem.

1 Like

I like this idea overall. In terms of Bedrock’s organization, I’d probably store these files under config/ somewhere. Especially if they happen to vary by environment since you could create folders for each one.

I’m not sure we’ve ever really discussed syncing options specifically so I don’t have much of an idea on other solution and I’m not even sure what other method there is. We’ve done full DB syncs as well because usually it’s more than just options you want consistent as well. Usually there’s also some base pages.

For the current roots.io site we actually used a Grunt based Markdown workflow so all the content is in version control but it get’s messy.

Did you consider using Grunt? I wrote a post on synching databases with it: http://cfxdesign.com/wordpress-database-sync-with-grunt/

With some tweaks, and removing the cleanup tasks, it may be a more streamlined way to accomplish what you’re aiming for.

1 Like

@swalkinshaw yes it seems like syncing the prod DB down to local/dev/staging is unavoidable for the reasons you give. I guess using config files like I am doing is more for going the opposite direction. I am making changes to settings in my local dev environment, how do I propagate them in a managed way to staging and prod? Before I was testing out the option/settings change locally, maybe deploying some code, and then manually repeating the option change on prod… which seems so error prone and fragile, in the same way that doing deployments manually over FTP was.

@cfx thanks for your post! when i’ve done this in the past I’ve just used ssh and bash. I have one script that pulls the db like:

ssh server "mysqldump dbname --opt > db.sql"
scp server:db.sql .
mysql dbname < db.sql
mysql dbname < local-overrides.sql

and another that pulls down wp-uploads:

rsync -av --update --delete server:wp-content/uploads/ wp-content/uploads/

I have used Grunt extensively to manage front-end builds… recently switched to using Gulp which also very nice.

Another step that happens at deployment time is activating plugins. I use WP-CLI to activate all installed plugins with every deployment, so that if any plugins were added by a commit, they are automatically activated. Just removing another source of potential error and inconsistency.

An option is to just use mu-plugins if they 100% always need to be activated. Bedrock has an mu-plugin autoloader which lets you use regular plugins in there as well.

I recently came across this plugin, which takes a similar approach for saving options, by writing a file that can be placed in version control and imported across server environments:

2 Likes