WordPress Deployments: Example of Database Changes in Code

How do you update the database of a WordPress site that's already in production without a lengthy content freeze or losing your client's data? If you've searched the Metal Toad blog, and who among us hasn't, you know from an earlier post by Chris Svajlenka that you should make any changes to the WordPress database via code; code that you can version control, code that you can deploy, code that you can reproduce.

That sounds like great advice, but what if you don't know how? There's a plugin for that, but it's not what you think. It's not an official WordPress hosted plugin that you download. It's an example of a plugin written by Andy Mantell that you write and modify to deploy your database changes in code. Why write a blog post about somebody else's plugin? Because it worked on the first try, it's easy to modify, and it wasn't easy to find.

Here's a reprint of Andy's code that just worked.

/*
Plugin Name: Deployment routines
Description: Runs update routines allowing code based database updates.
Author: Andy Mantell
Version: 1.0
*/
add_action( 'admin_init', 'deployment_admin_init' );
 
/**
 * Attached to init. Runs any necessary update routines
 */
function deployment_admin_init() {
 
  // What is the current version of this plugin?
  $deployment_version = 1;
 
  // What is the current version in the db
  $db_version = get_option( 'deployment_version', 0 );
 
  // Is the db out of date?
  if ( $db_version < $deployment_version ) {
 
    // If so, loop over all subsequent version numbers and attempt to run corresponding deployment_update_N functions
    for ( $version = $db_version + 1; $version <= $deployment_version; $version ++ ) {
      if ( function_exists( 'deployment_update_' . $version ) ) {
        $success = call_user_func( 'deployment_update_' . $version );
 
        // If the function returns a boolean false, log an error and bail out. Subsequent updates may rely on this update
        // so we shouldn't proceed any further.
        if ( $success === FALSE ) {
          // @TODO: log error here
          break;
        }
      }
 
      // If we've reached this far without error, update the db version
      update_option( 'deployment_version', $version );
    }
 
    // @TODO: output update summary on success
  }
}
 
/**
 * Update functions.
 */
 
/**
 * Disable the wordpress-meta-description plugin.
 * Enable and configure the add-meta-tags plugin
 */
function deployment_update_1() {
 
  // Include the plugin.php file so you have access to the activate_plugin() function
  require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
 
  deactivate_plugins( WP_PLUGIN_DIR . '/wordpress-meta-description/wp-meta-description.php' );
  activate_plugins( WP_PLUGIN_DIR . '/add-meta-tags/add-meta-tags.php' );
 
  update_option( 'add_meta_tags_opts', array(
    'settings_version' => 2,
    'site_description' => 'Site description here',
    'site_keywords' => 'site, keywords, here',
    'global_keywords' => 'global, keywords, here',
    'site_wide_meta' => '',
    'auto_description' => '1',
    'auto_keywords' => '1',
    'auto_opengraph' => '0',
    'auto_dublincore' => '0',
    'noodp_description' => '0',
    'noindex_search_results' => '1',
    'noindex_date_archives' => '0',
    'noindex_category_archives' => '0',
    'noindex_tag_archives' => '0',
    'noindex_author_archives' => '0',
    'copyright_url' => '',
    'default_image_url' => '',
    'i_have_donated' => '0',
  ) );
 
  return TRUE;
}

Modify Options

To demonstrate the ease of modifying this plugin, I'll use my plugin to change a couple options, add a new user, and create a table.

/*
Plugin Name: MTM WordPress Deployment Updates
Description: Runs update routines allowing code based database updates.
Author: Metal Toad Media
Version: 1.0
*/
add_action( 'admin_init', 'deployment_admin_init' );
 
/**
 * Attached to init. Runs any necessary update routines
 */
function deployment_admin_init() {
 
  // What is the current version of this plugin?
  $deployment_version = 3;
 
  // What is the current version in the db
  $db_version = get_option( 'deployment_version', 0 );
 
  // Is the db out of date?
  if ( $db_version < $deployment_version ) {
 
    // If so, loop over all subsequent version numbers and attempt to run corresponding deployment_update_N functions
    for ( $version = $db_version + 1; $version <= $deployment_version; $version ++ ) {
      if ( function_exists( 'deployment_update_' . $version ) ) {
        $success = call_user_func( 'deployment_update_' . $version );
 
        // If the function returns a boolean false, log an error and bail out. Subsequent updates may rely on this update
        // so we shouldn't proceed any further.
        if ( $success === FALSE ) {
          // @TODO: log error here
          break;
        }
      }
 
      // If we've reached this far without error, update the db version
      update_option( 'deployment_version', $version );
    }
 
    // @TODO: output update summary on success
  }
}
 
/**
 * Update functions.
 */
 
/**
 * Disable the wordpress-meta-description plugin.
 * Enable and configure the add-meta-tags plugin
 */
function deployment_update_1() {
 
  // Include the plugin.php file so you have access to the activate_plugin() function
  require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
 
  deactivate_plugins( WP_PLUGIN_DIR . '/wordpress-meta-description/wp-meta-description.php' );
  activate_plugins( WP_PLUGIN_DIR . '/add-meta-tags/add-meta-tags.php' );
 
  update_option( 'add_meta_tags_opts', array(
    'settings_version' => 2,
    'site_description' => 'Metal Toad Media',
    'site_keywords' => 'Phylum‎: ‎Chordata, Kingdom‎: ‎Animalia, Class‎: ‎Amphibia',
    'global_keywords' => 'boreal, arroyo, amargosa',
    'site_wide_meta' => '',
    'auto_description' => '1',
    'auto_keywords' => '1',
    'auto_opengraph' => '0',
    'auto_dublincore' => '0',
    'noodp_description' => '0',
    'noindex_search_results' => '1',
    'noindex_date_archives' => '0',
    'noindex_category_archives' => '0',
    'noindex_tag_archives' => '0',
    'noindex_author_archives' => '0',
    'copyright_url' => '',
    'default_image_url' => '',
    'i_have_donated' => '0',
  ) );
 
  return TRUE;
}
 
// Add another user
function deployment_update_2() {
 
  wp_create_user( 'trevor', 'thefr0g', 'trevor@nospam.dev' );
 
  return TRUE;
}
 
// Add table to the database
// https://codex.wordpress.org/Creating_Tables_with_Plugins
function deployment_update_3() {
 
  global $mtm_db_version;
  $mtm_db_version = '1.0';
 
    global $wpdb;
    global $mtm_db_version;
 
    $table_name = $wpdb->prefix . 'mtm_toads';
 
    $charset_collate = $wpdb->get_charset_collate();
 
    $sql = "CREATE TABLE $table_name (
      id mediumint(9) NOT NULL AUTO_INCREMENT,
      time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
      name tinytext NOT NULL,
      text text NOT NULL,
      url varchar(55) DEFAULT '' NOT NULL,
      UNIQUE KEY id (id)
    ) $charset_collate;";
 
    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );
 
    add_option( 'mtm_db_version', $mtm_db_version );
}

Now it's your turn. What WordPress databases changes will you write in code?

Comments

Great post, Monika!

Inspired me to implement a command line interface (through wp-cli) for my plugin project, Add-Meta-Tags, in the hope that it could be useful in cases of remote deployment/maintenance of WordPress web sites.

Thanks for writing it!

George

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Ready for transformation?