Back to Blog
Lesson 31 of the WordPress Plugin Development: Foundations (PHP & MVC) course
WordPressJune 25, 20263 min read

Handling Plugin Updates: Database Schema and Migration Strategies

Learn to manage plugin updates effectively by tracking version numbers, implementing dbDelta for schema changes, and running one-time migration scripts.

WordPressPHPDatabaseUpdatesMigrationSchemaVersioningplugin-development

Previously in this course, we built a robust Model Layer for Data to abstract our database interactions. Now that our plugin is growing, we need a reliable way to evolve our database structure as we add features.

Software is never finished. When you release a new version of your plugin, you often need to change the database schema or reorganize existing data. Unlike Laravel migrations which are highly structured, WordPress requires us to manually manage the plugin version and trigger the necessary updates.

Tracking Plugin Versioning

The first step in managing updates is knowing which version of your plugin is currently installed. WordPress stores the plugin version in the header of your main plugin file, but that doesn't help your code know if it needs to run an update.

We store the "installed version" in the wp_options table. This allows us to compare the version in our code against the version saved in the database.

PHP
#6A9955">// Inside your main plugin class or activation/upgrade handler
public function check_for_updates() {
    $installed_version = get_option('my_kb_plugin_version', '0.0.0');
    $current_version = '1.1.0';

    if (version_compare($installed_version, $current_version, '<')) {
        $this->run_upgrades($installed_version);
        update_option('my_kb_plugin_version', $current_version);
    }
}

Implementing Schema Updates with dbDelta

When you need to add a column or create a new table, you shouldn't run raw CREATE TABLE queries directly. Instead, use dbDelta(). This function parses your SQL and compares it against the existing database schema, only applying the necessary changes.

It is strict about formatting:

  • You must put each field on its own line.
  • You must include the PRIMARY KEY definition.
  • You must use two spaces for keywords like BIGINT or NOT NULL.
PHP
function my_kb_update_schema() {
    global $wpdb;
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');

    $table_name = $wpdb->prefix . 'kb_articles';
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE $table_name (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        title varchar(255) NOT NULL,
        content text NOT NULL,
        version_added varchar(10) DEFAULT '1.0.0',
        PRIMARY KEY(id)
    ) $charset_collate;";

    dbDelta($sql);
}

Running One-Time Upgrade Scripts

Sometimes a schema change isn't enough; you might need to move data from a legacy format to a new structure. We handle this by checking the installed version and executing specific migration methods.

PHP
private function run_upgrades($installed_version) {
    #6A9955">// If the user is upgrading from a version older than 1.1.0
    if (version_compare($installed_version, '1.1.0', '<')) {
        #6A9955">// Run migration logic: e.g., move data from post_meta to custom table
        global $wpdb;
        $wpdb->query("UPDATE {$wpdb->prefix}kb_articles SET version_added = '1.1.0'");
    }
}

Hands-on Exercise

  1. Locate your main plugin class.
  2. Add a check_for_updates() method that compares your plugin's current version constant against an option in wp_options.
  3. Hook this method into the admin_init action so it runs when an administrator visits the dashboard.
  4. Create a run_upgrades() method that adds a new column to your Knowledge Base table using dbDelta.

Common Pitfalls

  • Forgetting dbDelta formatting: If you don't use the exact spacing requirements (like two spaces before PRIMARY KEY), dbDelta will fail silently or recreate tables unnecessarily.
  • Running migrations on every request: Always use version_compare to ensure your migration logic only runs once during the upgrade process.
  • Not using require_once: dbDelta is defined in wp-admin/includes/upgrade.php, which is not loaded by default on the frontend. You must include it manually.

Managing updates is a foundational skill for any professional WordPress plugin architecture. By versioning your database changes, you ensure that your users have a seamless transition between plugin releases without losing their data.

Up next: Internationalization (i18n) — preparing your plugin for global audiences.

Similar Posts