WordPressで少し高度な検索をする

## 投稿タグ名のあいまい検索 or タイトル or カスタムフィールド
```php:functions.php
function post_content_to_meta_queries($where, $wp_query){
    global $wpdb;

    $meta_queries = $wp_query->get( 'meta_query' );
    if( !$meta_queries || $meta_queries == '' ) return $where;

    $where = str_replace($wpdb->postmeta . ".meta_key = 'post_title' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_title", $where);
    $where = str_replace($wpdb->postmeta . ".meta_key = 'post_content' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_content", $where);
    $where = str_replace($wpdb->postmeta . ".meta_key = 'post_excerpt' AND " . $wpdb->postmeta . ".meta_value", $wpdb->posts . ".post_excerpt", $where);

    $number_of_relations = count($meta_queries);
    $i = 1;
    while($i<=$number_of_relations && $number_of_relations > 0){
        $where = str_replace("mt".$i.".meta_key = 'post_title' AND mt".$i.".meta_value", $wpdb->posts . ".post_title", $where);
        $where = str_replace("mt".$i.".meta_key = 'post_content' AND mt".$i.".meta_value", $wpdb->posts . ".post_content", $where);
        $where = str_replace("mt".$i.".meta_key = 'post_excerpt' AND mt".$i.".meta_value", $wpdb->posts . ".post_excerpt", $where);
        $i++;
    }

    return $where;
}

add_filter('posts_where','post_content_to_meta_queries',10,2);
```

```php:test.php
<?php
$s = get_search_query();
$term_ids = array();
$cat_Args = "SELECT * FROM $wpdb->terms WHERE name LIKE '%".$s."%' ";
$cats = $wpdb->get_results($cat_Args, OBJECT);

if(!empty($cats)){
  foreach($cats as $cat){
    array_push($term_ids,$cat->term_id);
  }
}


$tax_tag[] = array(
  'relation' => 'AND',
  array(
    'taxonomy' => 'test-tag',
    'terms' => $term_ids,
  ),
);
?>
<?php
$args = array(
    'posts_per_page' => -1,
    //'s' => $s,
    'relation' => 'OR', //ANDかOR
    'post_type' => 'test',
    'meta_key' => 'acfnum', //カスタムフィールド名
    'orderby' => 'meta_value_num',
    'order' => 'DESC',
    'meta_query' => array(
      'relation' => 'AND',
      array(
        'relation' => 'OR',
        array(
          'key'     => 'private_post',
          'value'   => true,
          'compare' => 'NOT EXISTS'//カスタムフィールド作成前の投稿の場合を想定して指定、チェックがついていないもののみ取得
        ),
        array(
          'key'     => 'private_post',
          'value'   => true,
          'compare' => '!='
        ),
      ),
      array(
        'relation' => 'or',
        array(
          'key' => 'testname',
          'value' => $s,
          'compare' => 'LIKE'
        ),
        array(
          'key' => 'post_title',
          'value' => $s,
          'compare' => 'LIKE'
        ),
        array(
          'key' => 'post_content',
          'value' => $s,
          'compare' => 'LIKE'
        )
      )
      )
  );
  $args2 = array(
    'posts_per_page' => -1,
    'tax_query' => $tax_tag,
    'relation' => 'OR', //ANDかOR
    'post_type' => 'test',
    'meta_key' => 'acfnum', //カスタムフィールド名
    'orderby' => 'meta_value_num',
    'order' => 'DESC',
    'meta_query'  => array(
      'relation' => 'or',
      array(
          'key'     => 'private_post',
          'compare' => 'NOT EXISTS'
      ),
      array(
        'key'     => 'private_post',
        'value'   => true,
        'compare' => '!='
      )
      )
  );

$p1 = new WP_Query($args);
$p2 = new WP_Query($args2);
$test_posts = [];

$post_ids = array();
$test_posts = array_unique(array_merge($p1->posts,$p2->posts),SORT_REGULAR);

if(!empty($test_posts)){
    //合体させた後、もう一度ソート
    foreach($test_posts as $test_post){
      array_push($post_ids,$test_post->ID);
    }
    $args = array(
        'posts_per_page' => -1,
        'post_type' => 'test',
        'meta_key' => 'acfnum', //カスタムフィールド名
        'orderby' => 'meta_value_num',
        'order' => 'DESC',
        'post__in' => $post_ids
    );
    $test_posts = new WP_Query($args);
  }
?>
```

### やっていること
1.カテゴリー自体をライクであいまい検索してからidを配列で格納
2.配列で格納したidを指定したWP_Queryを実行
3.普通のタイトル等のWP_Queryを実行
(タイトルとカスタムフィールドをor検索するためにadd_filterでpost_titleを許可するようにしている)
4.array_uniqueで重複の配列を削除「SORT_REGULAR」を指定しないとエラーになるので注意
5.もう一回合体した記事のidを格納する
6.post__inで合体した記事のみを指定、orderbyで「meta_value_num」を指定して並び替えてWP_Queryを実行


https://stackoverflow.com/questions/43316457/how-to-search-posts-using-like-for-category-name-in-wordpress

※参考のstakoverflowの回答にも書いてあるが配列を合体させるのに3回WP_Queryを使うのであまりいいやり方ではない



## ACF繰り返しフィールドのあいまい検索
これずっと無理だと思ってましたがやり方あったのでメモ
以下acfのドキュメントを引用

```php:test.php
<?php 

// filter
function my_posts_where( $where ) {
	
	$where = str_replace("meta_key = 'locations_$", "meta_key LIKE 'locations_%", $where);

	return $where;
}

add_filter('posts_where', 'my_posts_where');

// vars
$city = 'Melbourne';

// args
$args = array(
	'numberposts'	=> -1,
	'post_type'		=> 'event',
	'meta_query'	=> array(
		'relation'		=> 'OR',
		array(
			'key'		=> 'locations_$_city',
			'compare'	=> '=',
			'value'		=> 'Melbourne',
		),
		array(
			'key'		=> 'locations_$_city',
			'compare'	=> '=',
			'value'		=> 'Sydney',
		)
	)
);


// query
$the_query = new WP_Query( $args );
```

### やっていること
locationsという親の繰り返しフィールドが合った場合、サブフィールドcityのmetakeyは下記のように格納される
0、1、2がループ番号
locations_0_city
locations_1_city
locations_2_city

なのでmetakeyの値「locations_$」を置換してから後方一致でlike検索させた上でkeyの値を取得してきて、valueの値を検索させているっぽい？(ちょっとよくわかってない)
なぜ、そのまま「%」で後方一致させずに一回置換しているかというとesc_sql関数の内部コードが4.8.3バージョンで変わってそのまま使えなくなったので一回置換しているらしい
↓詳しくはドキュメントのセッション4を参照

https://www.advancedcustomfields.com/resources/query-posts-custom-fields/


## メモ
そもそも「meta_query」処理が重いので、どちらも投稿が多くなると検索が遅すぎて死ぬ気がするので、あまり使わないほうが良い気はする
繰り返しフィールドは検索に使わないものの場合使うとか、カテゴリーのあいまい検索はいいやり方が思いつかないですが...

繰り返しフィールドのあいまい検索調べている時に見つけたプラグイン「ACF: Better Search」
https://ja.wordpress.org/plugins/acf-better-search/

自動的に機能して検索エンジンの動作を改善してくれるらしい、本当かよって感じですが時間があれば内部コードを見て理解してスキルアップしたい。