こんにちは。WordPressの深淵へようこそ。
今日は、WordPress開発者が必ず一度は直面する「深淵」、そう、`wp_posts` テーブルの `post_parent` による階層構造と、それに伴うパフォーマンスの悪夢についてお話しします。
多くの初心者が「親投稿IDを指定すればいいだけだよね?」と考えますが、その先には「N+1問題」という名の地獄が待っています。今日は、それをスマートに解決する「階層パス(Materialized Path)」という設計術を伝授しましょう。
—
1. なぜ `post_parent` だけではいけないのか?
WordPressのデフォルトでは、階層構造は `post_parent` カラムに親のIDを格納することで表現されます。
- 何が起きるのか?
- ある投稿の「全祖先」を取得したいとき、ループの中でクエリを何度も投げる必要があります(再帰的クエリ)。
- 階層が深くなればなるほど、データベースへの往復回数が増え、表示速度は目に見えて低下します。
例えば、`A > B > C > D` という階層で `D` の祖先を知るために、ループで親を遡る……これではスケールしませんよね。
—
2. 解決策:階層パス(Materialized Path)という設計
データベースの負荷を劇的に減らす手法として、「全祖先のIDを文字列として一つのカラムに持たせる」という戦略があります。
これを実装するために、独自のカスタムテーブル、あるいは `wp_postmeta` を利用しますが、今回は最もパフォーマンスが良い「カスタムカラム(wp_postsに追加)」を想定します。
階層パスの構造イメージ
`post_id: 4` が `1 > 2 > 3` という階層の下にある場合、`hierarchy_path` カラムには `1/2/3/` という文字列を保存します。
- 利点: 「特定の親配下の全投稿」を取得する際、`LIKE ‘1/2/%’` という単一のクエリで一発取得できます。再帰処理は不要です。
—
3. 実践:同期ロジックの設計
投稿が保存されるたびに、この `hierarchy_path` を自動更新するフックを仕込みます。
/
- 投稿保存時に階層パスを自動生成する
/
function update_post_hierarchy_path($post_ID, $post, $update) {
// 自身が親を持たない場合はルート
if ($post->post_parent == 0) {
$path = ”;
} else {
// 親のパスを取得し、そこに親のIDを連結
$parent_path = get_post_meta($post->post_parent, ‘_hierarchy_path’, true);
$path = $parent_path . $post->post_parent . ‘/’;
}
// パフォーマンスのためにpostmetaへ保存(本来はwp_postsにカラム追加が理想)
update_post_meta($post_ID, ‘_hierarchy_path’, $path);
}
// 投稿保存のタイミングで実行
add_action(‘save_post’, ‘update_post_hierarchy_path’, 10, 3);
ここがポイント!
- フックの優先順位: `save_post` は投稿データが確定した直後に走ります。このタイミングでメタデータを更新することで、常に最新のパスを保持できます。
- 注意点: 投稿が移動(親の変更)された場合、子孫のパスも再帰的に更新する必要があります。これを怠ると整合性が取れなくなるので注意してくださいね。
—
4. 陥りやすい罠:再帰的クエリと「SQLの迷宮」
よくあるエラーとして、`get_posts` 内での再帰的な呼び出しがあります。
// 悪い例:ループの中で何度もデータベースを叩く
foreach ($items as $item) {
$parent = get_post($item->post_parent); // これが毎回クエリを発行する!
}
データベースを叩く回数を減らすのが、WordPress高速化の黄金律です。もし階層パスを使わないのであれば、`get_posts` で一度に全階層のデータを取得し、PHP側で配列として再構築する「メモリ内処理」に切り替えるのが、中級者へのステップアップとなります。
—
まとめ:WordPressを掌握するために
1. 物理構造を知る: `post_parent` は便利だが、大規模データには向かない。
2. 先回りして計算する: 読み込み時に再帰計算せず、書き込み時にパスを計算して保存しておく(これがスケーラビリティの極意です)。
3. クエリを減らす: `LIKE` 検索を使える状態にすることで、データベースの負荷を最小限に抑える。
この階層パスの考え方は、WordPressに限らず、どんなデータベース設計でも使える一生モノの知識です。
「ここをクリアすれば、WordPressの基本はバッチリマスターできますよ」。
次は、このパスを使った「高速なパンくずリスト生成」や「階層別権限チェック」に挑戦してみましょうか。またいつでも聞きに来てくださいね。応援しています。