WP_Queryで「タイトルもしくはカスタムフィールドに一致したら」という条件で検索

WP_Queryでループの検索条件を文字列で絞り込むとき、だいたい以下のように書くと思います。

<?php
$wp_query = new WP_Query();
$param = array(
  'posts_per_page' => '5',
  'post_type' => 'post',
  's' => '検索用テキスト',
  'post_status' => 'publish',
);
$wp_query->query($param); if($wp_query->have_posts()):
// ここに出力を書く
endwhile; endif; wp_reset_query();
?>

普通は’s’のところに、検索のための文字列を入れますよね。

ただ、これはデフォルトだとタイトルと投稿内容しか対象にならない。「カスタムフィールドも検索対象にしたいんじゃ!」ってこと、あると思います。

ここで’s’も’meta_query’も普通に使っちゃうと、AND検索になります。なので、例えば「東京駅」で検索かけたときに、カスタムフィールドには入ってるけどタイトルには入ってないから検索結果に出ないということになっちゃうんですよね。それじゃ困る。

「タイトルか、もしくはカスタムフィールドにあれば表示する」というOR検索にしたいわけです。

そんなときは、こうしましょう。




実装

以下コードをfunctions.phpに記述

add_action( 'pre_get_posts', function( $q )
{
    if( $title = $q->get( '_meta_or_title' ) )
    {
        add_filter( 'get_meta_sql', function( $sql ) use ( $title )
        {
            global $wpdb;

            // Only run once:
            static $nr = 0; 
            if( 0 != $nr++ ) return $sql;

            // Modify WHERE part:
            $sql['where'] = sprintf(
                " AND ( %s OR %s ) ",
                $wpdb->prepare( "{$wpdb->posts}.post_title = '%s'", $title ),
                mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
            );
            return $sql;
        });
    }
});

そしてループの条件を以下のようにします。これは、カスタムフィールド「station」もしくはタイトルで、「東京駅」という単語でOR検索をかけるときの例。

<?php
$wp_query = new WP_Query();
$param = array(
  'posts_per_page' => '5',
  'post_type' => 'post',
  'post_status' => 'publish',
  '_meta_or_title' => '東京駅',
  'meta_query' => array(
    array(
      'key' => 'station', // 検索をかけるカスタムフィールドのkey
      'value' => '東京駅',
      'compare' => 'LIKE'
    )
  )
);
$wp_query->query($param); if($wp_query->have_posts()):
// ここに出力を書く
endwhile; endif; wp_reset_query();
?>

これでヨシ!

以上、現場からでした。

コメント

“WP_Queryで「タイトルもしくはカスタムフィールドに一致したら」という条件で検索” への1件のフィードバック

  1. @num_psychedelicのアバター
    @num_psychedelic

    本当に助かります。転職してからもこのサイトにお世話になるとは。。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です