LoginSignup
4

More than 3 years have passed since last update.

posted at

WordPressでタイトル・内容・カスタムフィールドをOR条件で検索したい

はじめに

WordPressでタイトル・内容・カスタムフィールドをOR条件で検索したいことがあったんです。
get_postsでもWP_Queryでもいいんですけど、パラメーターで、

  • タイトル・内容は「s」
  • カスタムフィールドは「meta_query」

を設定すればいいんですけど、これだとAND条件でつながるんですよね。(普通はこれでいい)
今回は、上記をOR条件でつなぎたかったので、それをどうするかというお話。

パラメーター「s」のSQL

AND (((wp_posts.post_title LIKE '%テスト%') 
 OR (wp_posts.post_excerpt LIKE '%テスト%') 
 OR (wp_posts.post_content LIKE '%テスト%')))

パラメーター「meta_query」のSQL

 AND ( ( ( wp_postmeta.meta_key = 'prefecture' AND wp_postmeta.meta_value LIKE '%テスト%' ) 
 OR ( wp_postmeta.meta_key = 'area_detail' AND wp_postmeta.meta_value LIKE '%テスト%' ) 
 OR ( wp_postmeta.meta_key = 'genre' AND wp_postmeta.meta_value LIKE '%テスト%' ) 
 OR ( wp_postmeta.meta_key = 'practice_time' AND wp_postmeta.meta_value LIKE '%テスト%' ) 
 OR ( wp_postmeta.meta_key = 'experience' AND wp_postmeta.meta_value LIKE '%テスト%' ) ) ) 

この2つをORでつなげばOK

やり方

WordPressには、標準で出力されるSQLのwhere句を追加できるフィルターがあるらしい
posts_whereフィルター

ちなみに、どのページのときに使うかなどを設定しないと、全部のSQLにフィルターかかるので注意!!

このSQLでタイトル・内容・カスタムフィールドをすべてOR条件でくっつけます。

add_filter('posts_where', 'add_my_query');

function add_my_query($where) {
    //テストの固定ページのときだけ
    if(is_page('test')) {
        isset($_GET['freeword']) ? $freeword = $_GET['freeword'] : $freeword = '';

        if($freeword) {
            $where .= <<<EOM
            AND (wp_posts.post_title LIKE '%{$freeword}%'
                OR wp_posts.post_content LIKE '%{$freeword}%'
                OR ( wp_postmeta2.meta_key = 'prefecture' AND wp_postmeta2.meta_value LIKE '%{$freeword}%' )
                OR ( wp_postmeta2.meta_key = 'area_detail' AND wp_postmeta2.meta_value LIKE '%{$freeword}%' )
                OR ( wp_postmeta2.meta_key = 'genre' AND wp_postmeta2.meta_value LIKE '%{$freeword}%' )
            )
EOM;
        }

    }

    return $where;
}

wp_postmeta2というのはwp_postmetaのエイリアスです。名前はなんでもいいんだけど。
条件にmeta_queryが入っている場合は、名前が重複して怒られたり、逆にmeta_queryが入っていないと、テーブルないやんって怒られます。

だから、joinのときもフィルターを使って、wp_postmetaテーブルをくっつけてあげます。
posts_joinフィルター

add_filter('posts_join', 'add_my_join');

function add_my_join($join) {
    //テストの固定ページのときだけ
    if(is_page('test')) {
        $join .= 'INNER JOIN wp_postmeta as wp_postmeta2 ON ( wp_posts.ID = wp_postmeta2.post_id )';
    }

    return $join;
}

まとめ

普通に検索ページなどで使いたいのであれば、それようのプラグインもあったような気がします。

余談

meta_queryパラメーター

WP_Queryget_postsで、meta_queryのパラメーター使うときにはまるのが、「meta_query はクエリがひとつだけでも入れ子の配列を指定しなければなりません。」というところかな。
自分もはまるし、他の人もはまってます。
まぁ、relationがANDORを設定できると知っていれば、はまることはなさそうですが...

WordPressのページネーション

基本、get_postsを使いますが、アーカイブとかタクソノミーページでないのに、記事一覧を取得してページャーを作りたいときは、WP_Queryを使用します。

なんかプラグイン使ったり、長々と独自関数書いている記事もよく見かけますが、
関数リファレンス/paginate linksの「カスタムクエリを使用した例」をコピペすれば十分なんじゃないかと思ってます。

アーカイブページなどの場合は、ほぼpaginate_links()で事足りますね。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
4