WordPressの検索で検索結果が表示されなくて困った

WordPressの検索をいじっている最中に検索結果が出なくて困った。

pre_get_posts (にフックした関数)をいじっていたんだけれど、全然思ったような結果にならずに結構困っていた。

原因は色々あったんだけれど、二箇所で困ったのでメモしておく。

検索結果がでない、ということはSQLに問題がある。

なのでSQLの中身を確認してなぜ出ないかを検討することに。

以下のダンプをpre_get_postではなく、利用したいテンプレート側に記載。

$wp_query->requestは実行されたSQL文なんだけど、これはpre_get_postsの後に実行されたSQL文なので該当するテンプレートに記載しないと読み出せない。

<span style="line-height: 1.5;">var_dump($wp_query->request);</span>

まず一つはpost_typeが’post’にしかなっていない点。これはpre_get_postsの関数内で

$query->set('post_type', 'post');

を記載すること。これが実は結構やっかいで、他の条件文、例えばtax_queryなどと組み合わす際には無くても何とかなったりするので、条件文を組み立てている最中のデバッグと完成したカタチではpost_typeの指定が必要か不要か、結構迷うことになる。

post_typeに何も指定されていない場合に実際に中身を決定づけているのはwp-includes/query.phpのget_posts内でpost_type = ‘any’として処理していき、状況に応じていろんなのが入る。例えばattachmentとかpostなど。

このget_postsは結構大きなメソッドでこれまた結構読みづらいんだけど、詰まるたんびに読んでいればそのうち読めるようになるかも。

さて次いで検索結果がでない状況に当たったんだけど、これはSQL内に 0 = 1 なんていう文が。例えば下記のような感じに。

string(250) "SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND 0 = 1 AND wp_posts.post_type = 'custom_post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 5"

where句の二つ目にばっちり0 = 1の条件が。おかげさまで検索結果はゼロに。

wp-includes/query.phpのget_postsを丁寧に調べていくと下記の部分で付け加えられていた。

// Taxonomies
 if ( !$this->is_singular ) {
 $this->parse_tax_query( $q );

$clauses = $this->tax_query->get_sql( $wpdb->posts, 'ID' );

$join .= $clauses['join'];
 $where .= $clauses['where'];
 }

ここのtax_query->get_sql() の部分。

今回このpre_get_postsではtax_queryを使用していなかったのでどうやらそれが原因らしい。

結果としては今回対象となるページが http://www.example.com/search/ なんていう検索用のURLだったんだけど、searchを普通のpostのcategoryとして見做していたようで、get_posts内の$this->tax_queryという$qを元に作られたタクソノミクエリでは

object(WP_Tax_Query)#9 (2) {
 ["queries"]=>
 array(1) {
 [0]=>
 array(5) {
 ["taxonomy"]=>
 string(8) "category"
 ["terms"]=>
 array(1) {
 [0]=>
 string(6) "search"
 }
 ["include_children"]=>
 bool(true)
 ["field"]=>
 string(4) "slug"
 ["operator"]=>
 string(2) "IN"
 }
 }
 ["relation"]=>
 string(3) "AND"
}

という状態に。

$qや$parsed_query、$wp_queryを調べてみると’category_name’に’search’が設定されていた。

これはパーマリンク設定で記事名を/%category%/%postname%/のようにしていたことで、最初のスラッシュからスラッシュの間をカテゴリ名として認識していたから、のようだ。

なのでpre_get_postsの中で

$query->set('category_name', '');

としてやることで不必要なtax_queryを省くことができた。

コメントを残す