Wordpressのカスタム投稿をキーワード検索に含める処理

:::note warn
※この投稿は、
Wordpress、ACF（Advanced Custom Fields）、カスタムフィールド、カスタム投稿、pre_get_posts
この辺りのキーワードに関する記事です。
:::

＜やりたいこと＞
WordpressのACFで作成した病院の施設情報の（施設名、住所、診療科）を、カスタム投稿で何件か作成して、pre_get_postsの書き方で表示する。
チェックボックスと、フリーのキーワード検索の機能を追加して、検索結果も表示する。
例えば、、、
キーワード検索の欄に、"長崎県"と入力→住所が長崎県の施設を取得
チェックボックスに”消化器内科”、キーワード検索の欄に"長崎県"と入力→長崎県にある消化器内科がある施設を取得

ACFの参考サイト
https://usagicode.com/wordpress/how-to-use-advanced-custom-fields/


＜環境＞
wordpressのプラグインACFを使用

post_type：hospitals
病院名：投稿のタイトル
住所：カスタムフィールドの名前（hospital_address)
診療科：カスタムフィールドの名前（hospital_medical)
![スクリーンショット 2024-02-28 16.11.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657766/fa2dc39b-8b03-b364-8dc0-694fa879cc34.png)



＜挙動＞
Index.phpで検索の画面 
![スクリーンショット 2024-02-28 16.12.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657766/16908996-f3b5-a27a-0fe2-d93337ae1934.png)

↓
functions.phpを通してarchive.phpへ
↓
archive.phpで
病院名、住所、診療科目の表示
↓"クリニック"とキーワード検索したときの画面
![スクリーンショット 2024-02-28 16.13.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657766/4203acc4-bb91-0329-6049-04234058cd1c.png)


ちなみに、、、、
初めは、archive.phpで検索画面と検索結果のどちらも表示していた。
(archive.phpで検索して、結果もarchive.phpで表示)
検索した時に、該当のデータの数は取れるが、中身がちゃんと表示されていない状況
↓
検索画面と検索結果の画面を分けた　→ うまく表示されるようになった。


＜コード一覧＞
・index.php
```
<h2>診療科目選択</h2>

<!-- 検索フォーム -->
<form role="search" method="get" id="searchform" class="searchform" action="<?php echo esc_url(home_url('/hospitals')); ?>">
  <?php
  // 全ての施設情報を取得
  $posts = get_posts(
    array(
    'post_type' => 'hospitals',
    'posts_per_page' => -1,
  )
);
  $specialities = array(); // 診療科目を保存する配列

  foreach ($posts as $post) {  // 取得した投稿をループ処理
    $specialities_array = get_field('hospital_medical', $post->ID); //診療科目を取得

    if (is_array($specialities_array)) {
      foreach ($specialities_array as $item) {
        if (!in_array($item, $specialities)) { // 診療科目がまだ配列に追加されていなければ追加
          $specialities[] = $item;
        }
      }
    }
  }

  // 診療科目のチェックボックスを表示
foreach ($specialities as $item) {
  // チェックされた値を取得
  $checked = '';
  if (isset($_GET['specialities_array']) && in_array($item, $_GET['specialities_array'])) {
      $checked = ' checked="checked"';
  }
    echo '<input type="checkbox" name="specialities_array[]" value="' . esc_attr($item) . '">' . esc_html($item) . '<br>';
  }
  ?>
  <div>
    <label class="screen-reader-text" for="s"><?php _x('Search for:', 'label'); ?></label>
    <input type="text" value="<?php echo get_search_query(); ?>" name="s" id="s" placeholder="キーワード検索">
    <input type="submit" id="searchsubmit" value="検索">
    <a href="<?php echo esc_url(home_url('hospitals/')); ?>">リセット</a>
  </div>
</form>
<!-- 検索フォームここまで -->
```

・archive.php
```
<h2>検索結果</h2><br>
<!-- アーカイブ表示 -->
<?php
// アーカイブページのメインループ
  if(have_posts()){
    while ( have_posts() ) : the_post();?>
        <!-- // タイトル表示 -->
        <h2><?php the_title(); ?></h2>
        <p>住所：<?php the_field('hospital_address'); ?></p>
        <p>診療科目：<?php the_field('hospital_medical'); ?></p>
        <?php echo '<hr>';
    endwhile;
    echo paginate_links();
  } else {
    echo "記事なし";
  }
?>
<br>
<a href="<?php echo esc_url(home_url('/')); ?>">検索画面へ</a>
```

・functions.php
```
<?php
//サイト内検索の設定
add_filter('pre_get_posts', 'filter_search');
function filter_search($query)
{
    if ( is_admin() && !$query->is_main_query() ){
        return;
    }
    if ($query->is_search()) {
        $query->set('post_type', 'hospitals');
        $page = get_query_var('paged') ? get_query_var('paged') : 1;
        
        $query->set('paged', $page);
        $query->set( 'posts_per_page', -1 );
    }
}

// 検索
add_filter('posts_search', 'custom_search', 10, 2);
function custom_search($search, $wp_query)
{
    global $wpdb;
    if (!$wp_query->is_archive) {
        return $search;
    }
    if (!isset($wp_query->query_vars)) {
        return $search;
    }

    $search_words =  isset($wp_query->query_vars['s']) ? $wp_query->query_vars['s'] : "";
    
    $search_words = explode(' ', $search_words);
    // タイトル検索用のSQLを構築
    if (count($search_words) > 0) {
        $search = '';
            $search .= " AND post_type = 'hospitals' ";
            foreach($search_words as $search_word ) {
                if (!empty($search_word)){
                    $search_word = '%'. esc_sql($search_word) .'%';
                    // var_dump($search_word);

                    $search .= " AND ({$wpdb->posts}.post_title LIKE '{$search_word}' 
                    OR {$wpdb->posts}.ID IN ( 
                        SELECT distinct post_id 
                        FROM {$wpdb->postmeta} 
                        WHERE meta_value LIKE '{$search_word}') 
                    )";
                }
            }
        }
    return $search;
}
?>

<?php
function filter_hospital_query( $query ) {

    //is_admin() をチェックして管理画面のクエリには影響ないようにする
    //$query->is_main_query() でメインクエリであることをチェック
    if ( is_admin() && !$query->is_main_query() ){
        return;
    }
    if ($query->is_archive) {

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

        $page = get_query_var('paged') ? get_query_var('paged') : 1;

        $meta_query = array();
        // var_dump($meta_query);

        $selected_specialities = isset( $_GET['specialities_array'] ) ? $_GET['specialities_array'] : array();
            // var_dump($selected_specialities);
        
            // チェックボックスのみの時
        if ( $selected_specialities && empty($search_term) ) {
            foreach ( $selected_specialities as $selected ) {

                $meta_query[] = array(
                    'key'     => 'hospital_medical',
                    'value'   => $selected,
                    'compare' => 'LIKE',
                );
            }
            $query->set('paged', $page);
            $query->set( 'posts_per_page', -1 );
            $query->set( 'meta_query', $meta_query );
        }
    }
}
add_action( 'pre_get_posts', 'filter_hospital_query' );
?>
```

参考サイト

https://rishuntrading.co.jp/blog/wordpress/freeword-search/