こんにちは。WordPressの深淵へようこそ。
多くの開発者は、`wp_posts`や`wp_postmeta`を「WordPressが勝手に使うテーブル」と捉えてブラックボックス化しがちです。しかし、真のフルスタックエンジニアは、データベースを「アプリケーションの魂」として扱い、そのスキーマを自在に操ります。
今日は、場当たり的な `dbDelta` の実行から脱却し、「バージョン管理可能なマイグレーションフレームワーク」を構築する極意を伝授します。これさえ理解すれば、あなたはもう「プラグインをアップデートしたらサイトが真っ白になった」という悪夢に悩まされることはありません。
—
1. なぜデータベース管理が「鬼門」なのか?
WordPressのプラグイン開発で最も恐ろしいのは、一度変更したDB構造を元に戻せないことです。
- `dbDelta` の癖: テーブルの構造を自動更新してくれる便利な関数ですが、インデックスの削除やカラムの型変更など、複雑な要件には非常に弱い側面があります。
- ロールバックの欠如: 失敗したときに「昨日の状態」へ物理的に戻す仕組みがなければ、本番環境でのデプロイは常にギャンブルです。
これを解決するには、「現在どのバージョンまで適用済みか」を `wp_options` に保存し、番号順にマイグレーションファイルを実行する仕組みが必要です。
—
2. マイグレーション管理のアーキテクチャ
イメージしてください。あなたのプラグインの中に `migrations/` というフォルダを作り、そこに `v1_add_custom_table.php` や `v2_add_column_to_table.php` といった連番ファイルを並べるのです。
基本的なディレクトリ構造
my-plugin/
├── migrations/
│ ├── 001_create_log_table.php
│ └── 002_add_status_column.php
└── includes/
└── class-migration-manager.php
—
3. 実装の極意:マイグレーション・マネージャー
まずは、現在適用されているスキーマバージョンを保持する仕組みを作ります。
class MigrationManager {
private $option_name = ‘my_plugin_db_version’;
public function run() {
$current_version = get_option($this->option_name, 0);
$migrations = glob(plugin_dir_path(__FILE__) . ‘migrations/.php’);
sort($migrations); // ファイル名順に実行を保証する
foreach ($migrations as $file) {
$version = (int) basename($file, ‘.php’);
if ($version > $current_version) {
// ここでファイル内の処理を実行
require_once $file;
// 成功したらバージョンを更新
update_option($this->option_name, $version);
}
}
}
}
ここで陥りやすい罠
1. `require_once`の落とし穴: `require` ではなく `include` を使うと、同一リクエスト内で複数回実行されるリスクがあります。必ず `require_once` です。
2. トランザクション: WordPressのMyISAMテーブル(古い環境)ではトランザクションが使えません。インフラ側の制約を意識してください。
3. `dbDelta` の要件: `dbDelta` を使う際は、SQL文の直前に改行を入れ、キーの定義には必ずスペースを含めるなど、独特の構文ルールを守らないと無視されます。
—
4. マイグレーションファイルの書き方(例)
`migrations/001_create_log_table.php` の中身は、このようにシンプルに保ちます。
global $wpdb;
$table_name = $wpdb->prefix . ‘my_custom_logs’;
// dbDelta を使うための準備
require_once(ABSPATH . ‘wp-admin/includes/upgrade.php’);
$sql = “CREATE TABLE $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
log_message text NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id)
) $wpdb->charset_collate;”;
dbDelta($sql);
—
5. ロールバック戦略:破壊的な変更への備え
もしバージョン 002 で追加したカラムを削除したくなったら?
「元に戻すためのマイグレーション」を書くのが定石です。
- `002_add_status_column.php` (UP: カラム追加)
- `003_remove_status_column.php` (DOWN: カラム削除)
もし自動ロールバックを実装するなら、各マイグレーションファイルに `up()` と `down()` メソッドを持たせるクラス構造に拡張しましょう。失敗時に `catch` ブロックで `down()` を呼び出す構造にするだけで、あなたのプラグインの信頼性は飛躍的に向上します。
—
先輩からのアドバイス
「データベースをいじる」ということは、ユーザーの資産を預かるということです。
- バックアップを忘れない: `dbDelta` を実行する前に、必ず `wpdb` で直接テーブルをダンプする処理を組むか、ユーザーに警告を出してください。
- クエリの負荷: `ALTER TABLE` はテーブルサイズが大きいとサイトを数秒間ロックさせます。大規模サイト向けのプラグインなら、`WP-CLI` コマンドとしてマイグレーションを実行できるようにしておくのが、玄人の流儀です。
ここをクリアすれば、あなたはもうWordPressの「利用者」ではなく、WordPressの「設計者」です。次はREST APIと連携して、このデータをどうフロントエンドに届けるか……一緒に深掘りしていきましょう。
迷ったら、いつでも聞いてくださいね。応援しています!