WordPress のカスタムテーブルに関する基礎

本記事では、WordPress のデータベースにテーブルを新規生成する仕組みや、その基礎について解説します。

最初に

WordPress で EC機能や予約機能と言った複雑な仕組みを新しく構築する場合に、標準のデータベース構造では仕様的に難しくなる問題が多いでしょう。その問題を少し解決しやすくする為の1つのアプローチとしても、データを保存するテーブル(表のようなもの)を別に用意する方法があります。

WordPress の標準テーブル構造を見てみよう

テーブル一覧 – WordPress Codex
ブリエ

上のテーブル一覧を見ながら実際のデータベースを開いて確認してみると、wp_posts テーブルは投稿や固定ページの記事データ以外にメニューやカスタマイズ情報の一部なども記録している汎用的なテーブルみたいな使われ方もしているのかな。最も重要な情報を持っているテーブルな感じがしますね。wp_options テーブルも情報を保存するテーブルだけど、有効化されているプラグインやウェブサイトの全体的な情報などしか保存されていない感じです。

テネーブル

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

カスタムテーブルとは

テネーブル

カスタムテーブルとは、WordPress が標準で用意している以外の独自テーブルを指します。

カスタムテーブルを作る意味は?

ブリエ

新しくテーブルを作る理由って何だろう?

テネーブル

複雑なシステムを作る場合には、複雑なデータを取り扱う必要がありますよね。そう言った複雑なデータを、他の多くの重要なデータと同じ場所に保存するのは、ちょっと怖いですよね?影響を与えちゃいそうですよね。標準のテーブルにデータを保存していた場合、データを削除する際にも標準のデータを削除しないように気をつけて作らなければなりません。そう言った機能が正しく作れていない場合、運営しているウェブサイトに深刻な不具合を作ってしまう原因にもなっちゃいそうって感じなかったでしょうか?

テネーブル

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

ルミェール

他にも、その機能のデータがいらなくなった時は、追加したテーブルを削除するだけでデータを削除できる便利な利点も。個人情報のデータを守る・正しく削除すると言う点でも、テーブルを別にすると言うことは重要なんだ。

カスタムテーブルを用意するのは、プラグインで

テネーブル

カスタムテーブルを新しく作る(新規生成)場合は、すべてプラグインで行うのが基本です。場合によってはテーマで用意される場合もありますが、推奨はされていない方法です。

ルミェール

テーマで新しくテーブルを作らない方が良い理由は、テーマを変更した場合にそのデータをどう取り扱うかの問題になるから。テーマ独自の機能でもデータを残したままにするのは無駄だよね!

テーブルを新規生成するタイミングと削除するタイミング

テネーブル

プラグインで新しくテーブルを新規生成するタイミングは、プラグインが有効になった時が基本です。また、その場合、テーブルを使わなくなるのは、プラグインが削除される時になりますので、その時が削除するタイミングとなります。

ルミェール

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

プラグインを有効化する時と削除する時の関数について

ブリエ

プラグインを有効化した時や削除する時に処理を行うようにするにはどうすれば良いの?

テネーブル

WordPress はプラグインを有効化する時にもフックが実行されるようになっています。しかし、この場合は専用の関数が用意されています。プラグインを有効化する時のフックを登録するための register_activation_hook 関数です。register_activation_hook 関数で、テーブルを新規生成する処理を実行させる関数を設定すれば、プラグインを有効化する時にテーブルを新規生成することができます。

参考ウェブページ: 関数リファレンス / register activation hook
テネーブル

同様に、WordPress はプラグインを削除(アンインストール)する時にもフックが実行するようになっています。プラグインを削除(アンインストール)する時のフックを登録するための関数は、WordPress 本体で専用にregister_uninstall_hook 関数が用意されています。register_uninstall_hook 関数で、テーブルを削除する処理を実行させる関数を設定すれば、プラグインを削除する時にテーブルを削除することができます。

参考ウェブページ: register_uninstall_hook / WordPress私的マニュアル

データベースを操作する wpdb クラスについて

ブリエ

プラグインを有効化した時や削除する時に処理を行うようにするのは解ったけど、テーブルを新規作成や削除はどのようにやるんだろう?

テネーブル

テーブルはデータベースに存在するものです。その為、データベース操作が必要となります。WordPress では、データベース操作を簡単に行う為の仕組みとして、wpdb と言うクラスが用意されています。

参考ウェブページ: 関数リファレンス/wpdb Class
ルミェール

実際にデータベース操作をする為には、SQL と言うデータベース言語を使う必要があるんだ。wpdb クラスは、その SQL を少し簡単にしてくれる便利なクラス。より簡単に、安全にデータベースに接続からデータ操作を処理してくれるよ。

テーブルを追加してみよう

テネーブル

実際に、テーブルを新規生成してみましょう。

ルミェール

ここで解説するのは、wp_options テーブルと同じ構造を wp_customtable_sample と言うテーブル名で新規生成する例にしたよ。

wp_ の部分は、WordPress をインストールする際に設定したデータベースのプレフィックスとなるので、インストール設定によって wp_ の部分は異なる場合もあるので、その場合は文章やコードを置き換えながら確認してね。

サンプルコードについて

解説したソースコード全体を動作するかたちで記述しているファイルは、記事の最後からダウンロードできるようにしています。動作確認される場合は、そちらをダウンロードしてご確認ください。

// プラグインが有効化された場合に、activation関数を実行するように登録
register_activation_hook( __FILE__, 'activation' );

// activation関数
function activation() {
	// プラグインの現在のバージョンを設定
	$plugin_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 をインストールする際に設定したデータベースのプレフィックスとなる為です。

ルミェール

プレフィックス(prefix)は、「接頭辞」という意味。先頭に一意の特別な文字列を付けるんだ。プレフィックスは、WordPress を標準でインストールしている場合には wp_ の部分になるよ。もし wp_ と異なる場合は、置き換えて確認してね!

wp_ 以外のプレフィックスが使われる場合があるのは、テーブル名を特定されたくない場合のセキュリティ対策や、 WordPress を1つのデータベースに複数インストールする場合などが理由だよ。

ブリエ

サンプルのコードでは、プレフィックスの wp_$wpdb->prefix で定義されるので、wp_customtable_sample と言うテーブル名から wp_ を抜いた文字列を合わせたのを、変数で設定してるんですね。解りました。

テネーブル

続いていきましょうか。次は、文字コードの設定です。

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

ルミェール

少し前までの WordPressではデータベースの文字列にはutf8が使われていたみたいだけど、現在の WordPress だと、utf8mb4utf8mb4_unicode_520_ci が定義されているんだよ。

ブリエ

文字コードの違いとか詳しくないと、何だか難しいことですね。

テネーブル

collate が設定されていない場合は、文字コードは設定しません。サンプルコードでは $wpdb->has_cap( 'collation' ) で比較しているところです。条件が負の場合、文字コードは設定されません。そう言う場合もあるので、文字コードについては、あまり難しく考える必要はなく、ここは文字コードの設定にはこの書き方をするって覚えておくだけでも良いです。

テネーブル

次に行っているのは、クエリ文字列の設定です。ここのクエリ文字列は、制約された SQL を設定します。

ブリエ

制約された SQL って、何ですか?普通の SQL と違うんでしょうか?

テネーブル

試しに、クエリ文字列のコードを1行にして動作を確認してください。

ブリエ

あれ?エラーが出ちゃっています?または正常にテーブルが新規生成がされないようになっちゃってます。

テネーブル

はい。実は、データベース操作のクエリ実行を行うdbDelta 関数は SQL のクエリ文字列をそのまま実行する関数ではないからです。WordPress Codex を参照してみましょうか。

dbDelta 関数は現在のテーブル構造を走査し、作成予定のテーブル構造と比較します。そして、必要に応じてテーブルを追加・変更してくれるので、更新にはとても便利な関数です

注意dbDelta 関数はやや融通がききません。

WordPress Codex – テーブルの作成または更新
テネーブル

現在のテーブル構造を走査する為に、色々な制約が存在しています。その制約については、WordPress Codex などのウェブサイトでご確認ください。

ルミェール

データベースを操作する SQL を正しく書いても、WordPressではdbDelta 関数の制約が理由で動作エラーになる場合もあるよ。制約でエラーにならないか、テーブルの新規生成の時だけではなく、構造の変更などの時もテストする必要があるよ!

テネーブル

すこし難しいことですが、テーブル内のデータを安全に更新する為には必要なことです。dbDelta 関数のテーブル構造を走査によって、テーブル新規生成やテーブル構造の変更・更新を正しく行ってくれるようになります。

葉月

データベースを操作する為に SQL を理解している人の方が、WordPress のデータベース操作を教える時には何故かエラーが出る、難しいと相談されることがあります。その詳細を聞くと、普段の SQL を使用するように1行などで記述している場合が多いからでした。dbDelta 関数の制約によって普段のように SQL を書いた場合でも、SQL は正しいけれどエラーとなってしまうと言う問題になってしまいますので、注意です。

テネーブル

最後の処理では、現在実行しているプラグインのバージョンの値をwp_optionsテーブルにcustomtable_sample_versionと言う名前で update_option 関数を利用して保存します。

再度有効化した時などには、その値をインストールされたバージョンの値として前述の比較処理の判定に利用されます。

テーブルを削除してみよう

テネーブル

作ったものは必要なくなった時に消す必要があるかもしれません。テーブルを削除するサンプルコードも見ていきましょう。

// プラグインが削除される場合に、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 を実行します。query 関数は指定した SQL 構文をクエリ操作する関数です。今回の場合であれば、指定する SQL 構文は、 テーブルの削除を行う DROP 文となります。

ケミ

DROP などと言った SQL の構文についてはデータベースの勉強が必要です。ここでは割愛します。

ルミェール

query 関数の戻り値などでテーブル削除が失敗した場合にはアンインストールを中断させるとか作るとより安全になるかも?それもこの処理を基に作ってみると良いかもね!(この記事の解説ではそう言った処理は割愛しています)

テネーブル

処理の最後には、再度プラグインが有効化された時に再度テーブルを新規生成されるようにする為に、比較をする時に使用しているインストールされているプラグインのバージョン情報の値として wp_options テーブルに保存していた customtable_sample_version の値を delete_option 関数を使用して削除しています。

サンプルコードのダウンロード

ケミ

解説したサンプルコードを実際にプラグインで動作するようにしているファイルです。勉強される時以外にはプラグインを有効化していたとしても意味ありませんので、勉強後はアンインストールと削除を忘れないようにしてください。

まとめ

ケミ

記事が長くなったこともあるので、データの書き換えについては、別の記事で説明することになりました。

データの書き換えを読む前に、まずは、ここまでの解説を通してプラグインを有効化してみたり、削除してみたりして、テーブルが正しく生成や削除される事を確認してみてください。

データの書き換えについての記事は、次の記事です。

この記事の筆者

Kmix39(ケミ)

電子の妖精。当ウェブサイトの記事制作などを行なっています。
金融・不動産・医療・教育などの数々の業種のシステム開発を経験を積み、スマートフォンアプリケーションと WordPress などのウェブアプリケーションを日々勉強中。