Help us understand the problem. What is going on with this article?

WordPressで検索機能を自作する

ワードプレスのテーマtwentytwentyoneを基盤に、検索機能を自作する実装を行ったので、備忘録的にこの記事を残す。

環境情報

PHP:version 7.3.12
WordPress:version 5.6
WPテーマ:twentytwentyone

仕様

・検索対象の投稿タイプは search のみとする。

・フリーワードの検索対象は、タイトルと(本文と備考と)繰り返しフィールドの search_other_value の値の二つ

・「さらに条件を絞り込む」に指定があればキーワード検索と AND で繋ぎ絞り込む

・「さらに条件を絞り込む」の項目は、一つのブロック内は OR で繋ぎ、異なるブロック同士は AND で繋ぐ。

・地域の設定はカスタムタクソノミーでカテゴリーを作っているため、選択した地域名に該当するカテゴリーに属する会社名を検索に引っ掛ける。

・車種の登録はそれぞれ車種ごとに入力フィールド分かれており、台数が値として入っているため、「さらに条件を絞り込む」で任意の車種にチェックが入っていた場合には、その車種の台数が1以上の会社名を検索に引っ掛ける。

・対応言語の登録は、一つの入力フィールドでラジオボタンで登録する言語を選択しているため、配列の形で値が格納されている。そのため、「さらに条件を絞り込む」で任意の言語にチェックが入っていた場合には、その言語を配列に含む会社名を検索に引っ掛ける。

実装

検索ページ

今回は検索で表示させたい投稿の投稿タイプ名が search というもの一つだけだったので、検索ページを search のアーカイブページに設置しました。

archive-search.php
<div class="search-box">
  <form role="search" method="get" id="searchform" action="/" >
    <input type="text" name="s" id="search-input" placeholder="○○内を検索" />
    <div>
      <label>さらに条件を絞り込む</label>
      <div>
        <label>エリア</label>
        <select name="category" style="margin-top:20px;">
          <option value="" selected>地域を選択</option>
          <?php
            $terms = get_terms( 'search_category',
              array(
                'parent' => 0,
                'orderby' => 'id',
                'order' => 'ASC'
              )
            );
            foreach ( $terms as $term ) :
          ?>
          <option value="<?php echo $term->slug; ?>"><?php echo $term->name; ?></option>
          <?php endforeach; ?>
        </select>
      </div>

      <div>
        <label>こだわり</label><br>
        <label><input type="checkbox" name="carmodel[]" value="general">一般タクシー</label><br>
        <label><input type="checkbox" name="carmodel[]" value="higher">ハイヤー</label><br>
        <label><input type="checkbox" name="carmodel[]" value="jumbo">ジャンボ</label><br>
        <label><input type="checkbox" name="carmodel[]" value="welfare">福祉</label><br>
      </div>

      <div>
        <label>外国語対応</label><br>
        <label><input type="checkbox" name="language[]" value="english">英語</label><br>
        <label><input type="checkbox" name="language[]" value="chinese">中国語</label><br>
        <label><input type="checkbox" name="language[]" value="korean">韓国語</label><br>
      </div>
    </div>

    <input type="hidden" name="post_type" value="search">
    <button type="submit" accesskey="f" class="search-btn">検索</button>
  </form>
</div>

functions.php での処理

functions.php
//======================================================================
// 検索機能
//======================================================================

// 検索時の表示ファイルの設定
function custom_search_template( $template ) {
  if ( is_search() ) {
    $post_types = get_query_var( 'post_type' );
    foreach ( ( array ) $post_types as $post_type )
      $templates[] = "search-{$post_type}.php";
      $templates[] = 'search.php';
      $template = get_query_template( 'search', $templates );
     }
  return $template;
}
add_filter( 'template_include', 'custom_search_template' );

// キーワード検索に特定のカスタムフィールドを追加
function custom_search($search, $wp_query) {
    global $wpdb;

    if (!$wp_query->is_search) return $search;
    if (!isset($wp_query->query_vars)) return $search;

    $search_words = explode(' ', isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : '');
    if ( count($search_words) > 0 ) {
        $search = '';
        $search .= "AND post_type = 'search'"; // 投稿タイプ名を設定
        for ( $i = 0; $i <= 9; $i++ ) {
            $custom_field_array[] = '"search_other_' . $i . '_search_other_value"';
        }
        $custom_field_list = implode( ', ', $custom_field_array );
        foreach ( $search_words as $word ) {
            if ( !empty($word) ) {
                $search_word = '%' . esc_sql( $word ) . '%';
                $search .= " AND (
                    {$wpdb->posts}.post_title LIKE '{$search_word}'
                    OR {$wpdb->posts}.post_content LIKE '{$search_word}'
                    OR {$wpdb->posts}.ID IN (
                        SELECT distinct post_id
                        FROM {$wpdb->postmeta}
                        WHERE {$wpdb->postmeta}.meta_key IN ( 
                            {$custom_field_list}
                        ) AND meta_value LIKE '{$search_word}'
                    )
                ) "; // INのカッコ内に対象としたいフィールド名をコンマ区切りで追加
            }
        }
    }
    return $search;
}
add_filter('posts_search','custom_search', 10, 2);

// 検索結果ページのメインクエリを変更
function change_search_main_query( $query ) {
    // 指定したページとメインクエリの場合に限定
    if ( $query->is_main_query() && ( $query->is_search() || isset( $_GET['category'] ) || isset( $_GET['carmodel'] ) || isset( $_GET['language'] ) ) ) {
        $s = $_GET['s'];
        $category = $_GET['category'];
        $carmodel = $_GET['carmodel'];
        $language = $_GET['language'];
        // 地域
        if ( $category ) {
            $taxquerysp[] = array(
                'taxonomy'         => 'search_category',
                'terms'            => $category,
                'include_children' => false,
                'field'            => 'slug',
                'operator'         => 'AND'
            );
        }

        $metaquerysp = [
            'relation' => 'AND',
        ];
        // 車種
        if ( $carmodel ) {
            $sub_metaquerysp = [
                'relation' => 'OR',
            ];
            foreach ( $carmodel as $val ) {
                $sub_metaquerysp[] = array(
                    'key'     => 'search_' . $val,
                    'value'   => 0,
                    'compare' => '>'
                );
            }
        }
        // 言語
        if ( $language ) {
            $sub_metaquerysp = [
                'relation' => 'OR',
            ];
            foreach ( $language as $val ) {
                $sub_metaquerysp[] = array(
                    'key'     => 'search_language',
                    'value'   => $val,
                    'compare' => 'LIKE',
                );
            }
        }
        $metaquerysp[] = $sub_metaquerysp;

        $query->set( 'post_type', 'search' );
        $query->set( 'tax_query', $taxquerysp );
        $query->set( 'meta_query', $metaquerysp );
        $query->set( 's', $s );
    }
}
add_action( 'pre_get_posts', 'change_search_main_query' );

検索結果ページ

search-search.php
<?php
if ( have_posts() ) :
    while ( have_posts() ) : the_post();
?>
    <!-- ループ内の処理を記述 -->
<?php
    endwhile;
else :
?>
    該当なし
<?php
endif;
?>
takumi19
PHPをメインとしているプログラミング初学者です。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away