WordPressでEC機能や予約機能と言った複雑な仕組みを新規で構築する場合、標準の構造では中々難しい事があるでしょう。データを保存する表(テーブル)を別に用意する事でその問題が少し解決しやすくなるケースは多いです。この記事ではそんな新規にテーブルを作る仕組みや基礎について解説します。
WordPressの標準テーブル構造を見てみよう
上のテーブル一覧を見ながら実際のデータベースを開いて確認してみよう。wp_posts
テーブルが一番メインで使われているって感じがするよね。
投稿や固定ページの記事データ以外にメニューやカスタマイズ情報の一部とかを記録している汎用的なテーブルみたいな使われ方をしてる印象を持つかも?wp_options
テーブルも情報を保持してるけど、プラグインとかサイトの全体的な情報しか記録していないような気もするよ。

そうですね。カスタム投稿タイプを追加した場合は、通常であれば標準のテーブルであるwp_posts
テーブルのpost_type
カラムにカスタム投稿のslug
名で保存されます。また、リビジョンや下書きと言った公開されていないデータもwp_postsテーブルに保存されますので、wp_posts
テーブルは非常に大きくデータを保持しますね。

新規でテーブルを作る意味など
データベースを見て思ったかもしれないけど、複雑なシステムを作る場合ってそう言った多くのデータに影響を与えちゃいそうだよね。
場合によっては、運営しているWebサイトに深刻な不具合を作っちゃう原因にもなっちゃいそうって感じなかったかな…?

その問題を解決する為にも、新規にテーブルを用意すると言うのが大きな理由の1つですね。標準のテーブルとは別にデータを読み書きする事で、標準のデータを守る、またサイトのパフォーマンスを大きく低下させない事が可能です。
それに、新しく追加したい機能の用途に合わせてテーブル設計を行う事で、それに合わせたシステムを構築しやすくするのも大きな理由でしょう。

新規にテーブルを用意するのはプラグインで
カスタムテーブルは、標準で存在するテーブルと違ってプラグインで新規に生成するのが基本です。場合によってはテーマで用意される場合もありますが、推奨はされていないようですね。

テーブルを生成するタイミング、削除するタイミング
プラグインで新規にテーブルを作るから、プラグインが有効になった時にテーブルを生成するのが基本だよ。
プラグインが削除された時にはテーブルは使わなくなるから削除する感じだね!

メンテナンス時やアップデートなどの場合によって、プラグインを停止する事があります。なので、停止時にはテーブルは削除してはいけません。そのままの状態にしておく必要があります。
良く間違って停止時にも削除するように実装されているケースがありますが、それが理由でアップデートするとデータが消えたとか言う問題に繋がっています。

有効時と削除時の仕組みについて
プラグインを有効にした時に処理を行うようにするにはどうすれば良いのかな?

プラグインが有効化された際に実行する関数を登録する為の仕組みとしてregister_activation_hook
関数が存在しています。register_activation_hook
関数で、テーブルを新規生成する処理を実行させる関数を設定し、プラグインが有効化された際に実行させる形になります。

プラグインが削除(アンインストール)される際に実行する関数を登録する為の仕組みとしてregister_uninstall_hook
関数が存在しています。register_uninstall_hook
関数で、テーブルを削除する処理を実行させる関数を設定し、プラグインが削除される際に実行させる形になります。

データベースを操作する wpdbクラス
WordPressでデータベース操作を行う為に用意された仕組みとしてwpdbクラスが存在します。

カスタムテーブルもデータベースの中のテーブルの1つなので、wpdbクラスで操作するって事だね!

テーブルを追加してみよう
追加するテーブルの構造は、wp_options
テーブルと同じ構造のwp_customtable_sample
と言うテーブル名で例にしたよ。
wp_
の部分は、WordPressをインストールする際に設定したデータベースのプレフィックスとなるので、インストール設定によってwp_
の部分は異なる場合もあるよ。その場合は置き換えて確認してね!

動作する全体のサンプルコードファイルは、記事の最後からダウンロードできるようにしています。
動作確認の場合は、そちらをどうぞ。

// プラグインが有効化された場合に_activation関数を実行するように登録
register_activation_hook( __FILE__, '_activation' );
// _activation関数
function _activation() {
// プラグインの現在のバージョンを設定
$_this_version = '0.1.0';
// プラグインのインストールされているバージョンを取得
$_installed_version = get_option( 'customtable_sample_version', '' );
// インストールされているバージョンと現在のバージョンを比較し、異なっている場合に処理を行う
if ( $_installed_version !== $_this_version ) {
// グローバル変数 wpdbクラスを宣言
global $wpdb;
// テーブル名の設定
$_table_name = $wpdb->prefix . 'customtable_sample';
// 文字コードの設定
$_collate = '';
if ( $wpdb->has_cap( 'collation' ) ) {
$_collate = $wpdb->get_charset_collate();
}
// クエリの設定
$_query = "CREATE TABLE $_table_name (
option_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
option_name varchar(191) NOT NULL DEFAULT '',
option_value longtext NOT NULL,
PRIMARY KEY (option_id),
UNIQUE KEY option_name (option_name)
) $_collate;";
// dbDelta関数を使用する為のPHPファイルをロード
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
// データベースを操作
dbDelta( $_query );
// プラグインのインストールされているバージョン情報の更新
update_option( 'customtable_sample_version', $_this_version );
}
}
順番に解説していきます。
まず、register_activation_hook
関数により、_activation
関数をプラグイン有効時に実行されるように登録しています。_activation
関数では、プラグインの現在インストールされているバージョンと現在のバージョンを最初に比較しています。

何故、比較を行うんだろうね?考えてみよう!

まず、比較する大きな理由として停止した後に再度有効した場合の動作対応です。
必ず、違うバージョン時だけに有効化された際の処理が実行されるとは限りません。
停止後に同じバージョンで有効化される場合もあります。しかし、同一のバージョン時であればプラグインに変更は無いのですから、テーブル構造は変更する必要はありません。その為、テーブル操作処理は行わないようにする必要があります。

データを守る為にも、操作する必要が無い場合は必要ない処理を実行しないようにするのも大事なんだね!

処理の解説に戻ります。
比較を行った後、データベース操作が必要な場合にはデータベース操作をする為にwpdb
クラスを関数内で使用する為にglobal
で宣言しています。
テーブル名であるwp_customtable_sample
を設定する際に$wpdb->prefix
をテーブル名の先頭に付与してcustomtable_sample
と記述していますが、これは$wpdb->prefix
がWordPressをインストールする際に設定したデータベースのプレフィックスとなる為です。

プレフィックスは、デフォルトでインストールしている場合はwp_
の部分。違う場合は、確認の時に置き換えて確認してもらった部分だよ!
なので、wp_customtable_sample
と言うテーブル名からwp_
を抜いた部分と$wpdb->prefix
で変数を設定してるんだね!

次に文字コードの設定です。
WordPressではバージョンやインストール時の言語や設定方法によってデータベースの文字コードが異なる場合がありますので、wpdb
クラスを用いて設定されている文字コードを取得しています。

ちょっと前まではutf8
だったみたいだけど、現在のWordPress日本語版だと、大体CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci;
が定義されているのかな?collate
が設定されていない場合は文字コードは省略出来るから、ここは文字コードの設定にはこの書き方をするって覚えておくだけで良いかも。

次に行うのはクエリの設定ですね。
ここのクエリでは制約されたSQL文を設定します。

制約されたSQL文?

はい。動作確認を行う際にクエリ文のコードを1行にまとめたりしてみてください。

エラーが出るか、正常にテーブル生成が行われないようになっちゃうね。

はい。実はデータベース操作のクエリ実行を行うdbDelta
関数はクエリをそのまま実行する関数ではありません。

dbDelta
関数は現在のテーブル構造を走査し、作成予定のテーブル構造と比較します。そして、必要に応じてテーブルを追加・変更してくれるので、更新にはとても便利な関数です注意:
WordPress Codex – テーブルの作成または更新dbDelta
関数はやや融通がききません。
色々な制約が存在しますので、制約については上記のサイトでご確認ください。
テスト時には制約で動作エラーにならないかをテーブルの生成だけではなく構造の変更も正しく試してみる必要があります。

ちょっと難しいけど、テーブル内のデータを安全に更新する為には必要な事だよね!
プラグインの有効時のテーブル生成やアップデート時のテーブル構造の更新を正しく行ってくれるので、きちんとクエリを書くようにしよう!

最後の処理では、インストールされたバージョンの値をwp_options
テーブルにcustomtable_sample_version
と言う名前で保存します。
再度有効化した際は、前述の比較処理時にこの値を基に判定されるようになります!

テーブルを削除してみよう
削除の際のコード例は下記の通りです。

// プラグインが削除される場合に_uninstall関数を実行するように登録
register_uninstall_hook( __FILE__, '_uninstall' );
// _uninstall関数
function _uninstall() {
global $wpdb;
$_table_name = $wpdb->prefix . 'customtable_sample';
// SQLクエリの設定
$_query = sprintf(
'DROP TABLE IF EXISTS %1$s',
$_table_name
);
// SQLクエリの実行
$wpdb->query( $_query );
// バージョン情報の削除
delete_option( 'customtable_sample_version' );
}
生成処理とほぼ同様ですが、テーブルの生成や更新でない限りは現在のテーブル構造を走査する必要が無いですので、クエリの実行ではdbDelta
関数を使用しません。
クエリの実行にはwpdb
クラスのquery
関数を使用してSQLクエリを実行します。
SQLクエリはDROP文で、テーブルの削除を行うSQLを指定してあげます。
クエリ実行後に、比較をする為のバージョン情報であるcustomtable_sample_version
の値を削除します。

DROPなどと言ったSQL構文についてはデータベースの勉強が必要なので、ここでは割愛してるよ!query
関数の戻り値などでテーブル削除が失敗した場合にはアンインストールを中断させるとか作るとより安全になるのかな?
それもこの処理を基に作ってみると良いかも!

サンプルコードのダウンロード
次回予告!
長くなりましたので、データの書き換えについては、次回の記事で説明いたします。
プラグインを有効化してみたり、削除してみたりしてテーブルが正しく生成や削除される事をまずは確認してみてください!

次回記事を公開しました。