posts_* 系フィルター8選と実用的なカスタマイズ例
WordPress の WP_Query
は便利なAPIですが、標準機能だけでは対応できない場面が少なくありません。
たとえば:
- カスタムフィールドの値で並べ替えたい
- 投稿タイトルとカスタムフィールドの両方を検索対象にしたい
- JOINによる重複投稿を排除したい
- 完成するSQLを確認・編集したい
こういったニーズを実現するには、posts_*
系のフィルターフックを使ったSQLレベルの制御が非常に効果的です。
この記事では、代表的な8つの posts_*
フィルターの用途・使い方・実行されるSQL・注意点を解説し、実用的なカスタマイズパターンまでご紹介します。
フィルター一覧と概要
フィルター名 | 操作対象 | 主な用途 |
---|---|---|
posts_fields | SELECT句 | 取得するカラムの制御 |
posts_join | JOIN句 | postmeta などとの結合 |
posts_where | WHERE句 | 検索条件の追加 |
posts_groupby | GROUP BY句 | 投稿単位での集約 |
posts_orderby | ORDER BY句 | 並び順の制御 |
posts_distinct | SELECTのDISTINCT | 重複の除去 |
posts_clauses | 全体まとめて | 一括でJOIN/WHERE/ORDERを制御 |
posts_request | 最終SQL全体 | デバッグ・ログ出力用 |
各フィルターの用途と実行されるSQL
1. posts_fields
add_filter('posts_fields', function($fields, $query) {
if ($query->is_main_query() && $query->is_search()) {
// 必要なカラムだけ取得(最小化)
return 'DISTINCT wp_posts.ID, wp_posts.post_title';
}
return $fields;
}, 10, 2);
SQL例:
SELECT DISTINCT wp_posts.ID, wp_posts.post_title
2. posts_join
add_filter('posts_join', function($join) {
global $wpdb;
if (is_search()) {
// 全てのカスタムフィールドをJOIN
$join .= " LEFT JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id ";
// 並び順用に kana フィールドを別名でJOIN(エイリアス)
$join .= " LEFT JOIN {$wpdb->postmeta} AS kana_meta
ON {$wpdb->posts}.ID = kana_meta.post_id
AND kana_meta.meta_key = 'kana' ";
}
return $join;
});
SQL例:
LEFT JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
LEFT JOIN wp_postmeta AS kana_meta ON wp_posts.ID = kana_meta.post_id AND kana_meta.meta_key = 'kana'
3. posts_where
add_filter('posts_where', function($where) {
global $wpdb;
if (is_search()) {
$where = preg_replace(
"/\(\s*{$wpdb->posts}\.post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
"({$wpdb->posts}.post_title LIKE $1) OR ({$wpdb->postmeta}.meta_value LIKE $1)",
$where
);
}
return $where;
});
SQL例:
WHERE (wp_posts.post_title LIKE '%検索語%')
OR (wp_postmeta.meta_value LIKE '%検索語%')
4. posts_groupby
add_filter('posts_groupby', function($groupby, $query) {
global $wpdb;
if ($query->is_main_query() && $query->is_search()) {
return "{$wpdb->posts}.ID";
}
return $groupby;
}, 10, 2);
SQL例:
GROUP BY wp_posts.ID
5. posts_orderby
add_filter('posts_orderby', function($orderby, $query) {
global $wpdb;
if ($query->is_main_query() && $query->is_search()) {
// kana_meta は JOIN 時に定義したエイリアス
return "kana_meta.meta_value ASC, {$wpdb->posts}.post_date DESC";
}
return $orderby;
}, 10, 2);
SQL例:
ORDER BY kana_meta.meta_value ASC, wp_posts.post_date DESC
6. posts_distinct
add_filter('posts_distinct', function($distinct) {
if (is_search()) {
return 'DISTINCT';
}
return $distinct;
});
SQL例:
SELECT DISTINCT wp_posts.*
7. posts_clauses
add_filter('posts_clauses', function($clauses, $query) {
global $wpdb;
if ($query->is_main_query() && $query->is_search()) {
$clauses['join'] .= " LEFT JOIN {$wpdb->postmeta} AS kana_meta
ON {$wpdb->posts}.ID = kana_meta.post_id
AND kana_meta.meta_key = 'kana'";
$clauses['orderby'] = "kana_meta.meta_value ASC";
}
return $clauses;
}, 10, 2);
8. posts_request
add_filter('posts_request', function($sql, $query) {
if ($query->is_main_query() && $query->is_search()) {
error_log('[SQL LOG] ' . $sql); // ログファイルへ出力
}
return $sql;
}, 10, 2);
応用的な実装パターン
パターン1:投稿タイトル+カスタムフィールドで検索し、kana で並び替える
posts_join
:postmeta
+kana_meta
をJOINposts_where
:meta_value
も検索対象にposts_orderby
:kana_meta.meta_value
でソートposts_distinct
:重複排除posts_groupby
:ID
でまとめる(必要に応じて)
このように複数のフックを組み合わせて制御することがベストプラクティスです。
パターン2:meta_queryを使った検索とはどう違う?
WordPress標準の meta_query
を使うと、AND/OR 条件を指定してカスタムフィールドを検索できますが、
「検索キーワードとカスタムフィールドの両方を対象にする」「meta_keyを柔軟に制御する」といったケースにはposts_where
のようなSQLレベルの調整が適しています。
おわりに
WordPressの WP_Query
は、柔軟性が高い一方で、標準APIだけでは限界があるシナリオも多く存在します。
今回ご紹介した posts_*
系のフィルターを活用することで、SQLの構造を理解しながら、本格的な検索・並び順のカスタマイズが実現可能になります。
コメント