Database Schema Changes

If you’ve ever had to create custom tables in WordPress, you probably know how frustrating it can be to get the syntax exactly right. It’s much easier now with AI, but it’s still difficult to review.

You’re probably looking at something like this:

  /**
   * Create audit log table on plugin activation.
   */
  function myplugin_create_audit_log_table() {
      global $wpdb;

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

      $sql = "CREATE TABLE $table_name (
          id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
          user_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
          event_type VARCHAR(50) NOT NULL,
          message TEXT NOT NULL,=
          created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
          PRIMARY KEY  (id),
          KEY user_id (user_id),
          KEY event_type (event_type),
          KEY created_at (created_at)
      ) $charset_collate;";

      require_once ABSPATH . 'wp-admin/includes/upgrade.php';
      dbDelta( $sql );

      update_option( 'myplugin_audit_log_db_version', '1.0.0' );
  }
  register_activation_hook( __FILE__, 'myplugin_create_audit_log_table' );

Even when you get this figured out and your tables are created correctly, you still have to deal with a lack of database update support in WordPress.

How do you go about updating your tables, what happens when you change the name of a column for users, how do you provide backward compatibility or recover from a failed update?

Laravel solves most, if not all, of these questions with migrations.

Have artisan spin up a new migration class for you:

php artisan make:migration

Fill out your database schema changes with a fluent syntax that reads like English and if you want to, you can provide a rollback with the down method it scaffolds for you.

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddAuditLogTable extends Migration {
    public function up(): void
    {
        Schema::create('audit_log', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedBigInteger('user_id')->default(0);
            $table->string('event_type', 50);
            $table->dateTime('created_at')->useCurrent();

            $table->index('user_id');
            $table->index('event_type');
            $table->index('created_at');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('audit_log');
    }
};

With Laravel, you own the stack, so database changes are naturally less risky—you can ensure the code adapts to the new schema before you migrate.

WordPress is great at so many things, but database changes are hard, and Laravel makes the process much easier.