Advance Custom fields(ACF)で作成した項目を検索する方法

Advance Custom fields(ACF)で作成したカスタムフィールドの内容は、通常のWordpressの検索では引っかかりません。
今回は、Advance Custom fieldsで作成した内容を検索する方法をご紹介いたします。

「Advance Custom fieldsって何?」、「出力方法が知りたい」という方は、下記記事をご確認ください。

Advance Custom fieldsで入力したデータはどこにあるの?

管理画面から作成・編集した記事やカテゴリなどの情報は、データベースに保存されています。

記事や固定ページの場合
wp_posts
カテゴリやタグの場合
wp_term_taxonomy
登録ユーザー情報
wp_users

通常の検索フォームでは、「wp_posts」の記事本文にあたるpost_content、タイトルにあたるpost_titleの欄の値が検索されています。
テーマによってまたプラグインを導入することで、カスタム投稿やカテゴリによる絞り込みなどができるものもあります。

Advance Custom fieldsで入力したカスタムフィールドの値は下記のデータベースに保存されています。

記事や固定ページの場合
wp_postmeta
カテゴリやタグの場合
wp_termmeta
登録ユーザー情報
wp_usermeta

SQLとPHPを用いて、上記のデータベースから指定したワードを検索し、出力させるようにします。

検索フォームのカスタマイズ

まずは、通常のWordpressの検索機能が記載されているファイルを探します。
下記テンプレートのファイルに記載されています。
通常では、記事タイトル・記事本文の部分が検索対象となります。

searchform.php
キーワードを入力する検索窓
search.php
検索結果を表示するテンプレート

テーマフォルダに上記の名前のテンプレートが無い場合は、上記名前で作成したファイルをテーマフォルダにアップすることでそちらが使用されます。

検索フォーム(serchform.php)

使用しているテーマにより異なりますが、最低限の検索フォームのタグ例は下記となります。

<form role="search" method="get" id="searchform" class="searchform" action="<?php echo esc_url( home_url( '/' ) ); ?>">
	<input type="text" id="serchtext" value="<?php echo get_search_query(); ?>" name="s" id="s" placeholder="サイト内検索" />
	<input type="submit" id="searchsubmit" value="<?php echo esc_attr_x( 'Search', 'submit button' ); ?>" />
</form>

ACFに対応させるために特にカスタマイズさせる必要はありませんが、入力欄を複数作って絞り込みさせたいなどの場合はこちらを編集します。

検索結果(search.php)

検索結果を表示させるためのテンプレートです。
もしテーマファイル内になければ、
カテゴリ(archive.php、category.php)などのテンプレートをコピーしてタイトルなどを書き換えるなどすると楽かと思います。

下記は最低限の検索結果表示サンプルです

<?php get_header(); ?>

<?php
//検索キーワード取得
$serchword = get_search_query();
?>

<h1>「<?php echo $serchword; ?>」検索結果</h1>

<?php if(have_posts()): ?>
	<div class="search_result">
	<?php
	while(have_posts()): the_post();
		//アーカイブ表示用テンプレート読み込み(ファイル名content.phpの場合)
		get_template_part( 'content', get_post_type() );
	endwhile;
	?>
	</div>
<?php else: //検索結果0件だった場合の処理 ?>
	<div>
		<p>「<?php echo $serchword; ?>」の記事はありません</p>
	</div>
<?php endif; ?>

<?php get_footer(); ?>

検索結果をACFに対応させる

今回は使いまわせるように、検索する対象のACFキーを指定せず、データベース上にある全キーを取得するようにしています。

  1. 最初にACFのキーを取得
  2. 取得したキーと対応する値に検索のキーワードが含まれるかチェック
  3. タイトル・本文に検索のキーワードが含まれるかチェック
  4. 2・3のデータを結合、整理
  5. 出力

となります。
検索したいACFで作成したカスタムフィールドが限られる場合は、1を省略、タイトルや本文を含めない場合は3の項目を省略するなどカスタマイズします。

<?php get_header(); ?>

<?php
//検索ワードを取得
$serchword = get_search_query();
global $wpdb;

/* ------------------------------
1. ACFフィールドの全フィールド名取得
複数ある・名称がわからない前提で個別に振られるField Keys(field_XXX(ID)からフィールド名を取得
※特定のフィールドのみ検索する場合はこの項目はスキップ
------------------------------ */
$acf_fields = $wpdb->get_results($wpdb->prepare(
	"
	SELECT *
	FROM wp_postmeta
	WHERE meta_value LIKE %s",
	$wpdb->esc_like('field_') . '%'
),ARRAY_A);

//取得した情報を整理する
$acf_keys = array();
foreach($acf_fields as $acf_field){
	$acf_field_name = $acf_field['meta_key'];
	
	//そのままだとフィールド名の前にアンダーバーがついているので削除
	$acf_field_name = ltrim($acf_field_name, '_');
	
	//綺麗にしたものを配列に格納
	array_push($acf_keys, $acf_field_name);
}
//複数ページで使用しているフィールド名は重複して配列に格納されているため、重複削除
$acf_keys = array_unique($acf_keys);
$acf_keys = array_values($acf_keys); //配列番号を振り直し

/* ------------------------------
2. ACFの項目に検索キーワードが含まれるかチェック
------------------------------ */
$i = '0'; //最初の配列番号
$acf_keynum = count($acf_keys); //取得したACFのフィールド名の数 計算
$acf_check = array();
while($acf_keynum > $i){
	//FROMに検索したいデータベーステーブル
	//meta_key に 検索したいフィールド
	//meta_value に検索したいキーワードを設定
	$check = $wpdb->get_results($wpdb->prepare(
		"
		SELECT *
		FROM wp_postmeta
		WHERE
		meta_key = '".esc_sql($acf_keys[$i])."'
		AND
		meta_value = '".esc_sql($serchword)."'
		"
	),ARRAY_A);
	
	//検索結果を$acf_checkに格納
	foreach($check as $checkpost){
		//投稿IDを取得
		$post_id = $checkpost['post_id'];

		//値を取得
		$meta_value = $checkpost['meta_value'];

		//公開済みのページのみに絞り込み
		if(get_post_status($post_id) == 'publish'){
			if(!empty($meta_value)){
			//値が空のものは除外する
			array_push($acf_check, $post_id);
			}
		}
	}
$i++; //次の配列へ
}

//重複削除(複数フィールドで同じ投稿IDがHITした場合を考慮)
$result_acf = array_unique($acf_check);
$result_acf = array_values($result_acf); //配列番号を振り直し


/* ------------------------------
3. 通常の検索(タイトル・本文)の項目に検索キーワードが含まれるかチェック
※不要の場合はスキップ
------------------------------ */
//タイトル
$result_title = array();
$check_title = $wpdb->get_results($wpdb->prepare(
    "
    SELECT ID FROM wp_posts
    WHERE
	post_title LIKE '%".esc_sql($serchword)."%'
	AND
	post_status = 'publish'
    "
),ARRAY_A);
//検索結果を$result_titleに格納
foreach($check_title as $checkpost){
    array_push($result_title, $checkpost['ID']);
}

//本文
$result_content = array();
$$check_content = $wpdb->get_results($wpdb->prepare(
    "
    SELECT ID FROM wp_posts
    WHERE
	post_content LIKE '%".esc_sql($serchword)."%'
	AND
	post_status = 'publish'
    "
),ARRAY_A);
//検索結果を$result_titleに格納
foreach($$check_content as $checkpost){
    array_push($result_content, $checkpost['ID']);
}
	

/* ------------------------------
4. 出力用にデータ合体
------------------------------ */
//検索結果データを結合
$result_post = $result_acf + $result_title + $result_content;

//重複削除
$result_post = array_unique($result_post);
$result_post = array_values($result_post); //配列番号を振り直し
?>

<!-- ------------------------------
5. 検索結果表示
------------------------------ -->
<h1>「<?php echo $serchword; ?>」検索結果</h1>

<?php if(!empty($result_post)): ?>
	<!-- 今回はリスト形式で出力しています。-->
	<ul>
		<?php
		foreach($result_post as $postid):
		$post = get_post($postid,OBJECT);
		?>
			<!-- get_template_part()での出力も可能です -->
			<li><a href="<?php echo get_permalink();?>"><?php echo the_title();?></a></li>
		<?php endforeach; ?>
	</ul>
<?php else: //検索結果0件だった場合の処理 ?>
	<div>
		<p>「<?php echo $serchword; ?>」の記事はありません</p>
	</div>
<?php endif; ?>

<?php get_footer(); ?>

上記以外にもカスタムフィールドを検索する方法として、functions.phpに処理を記載したりなど複数の方法があります。

また、チェックボックスなどの選択肢で値とラベルを設定している場合は、データベースのwp_postmeta上では値のみ保存されています。
別途検索フォームの方をチェックボックスにし、valueにACFで指定している値を入れておくなどする必要があります。

この他にも、範囲検索や絞り込み検索など、データベース上に保存されている値を組み合わせての検索が自由に作成できます。

作成した検索フォームを設置する

テンプレートの設置したい箇所に下記を記述します。

<?php get_search_form(); ?>

また、ウィジェットエリアであれば下記画像のように、管理画面 外観>ウィジェットから「検索」を表示したいエリアに指定することでも表示可能です。

既存の検索機能を残したまま作る

検索フォーム・検索ページのテンプレートをsearch-custom.phpなど既存とは別名で新規作成し、固定ページなどにそのテンプレートを適用させることも可能です。

新規でACF対応の検索フォーム・ページを作成した場合は、表示したい箇所のテンプレートにフォームの設置&固定ページなどで検索結果用ページを作成しテンプレートを適用させる必要があります。

この場合、フォームの設置にはget_search_form()ではなく、下記のようにget_template_part()でテンプレートの読み込みをする記述が必要です。

<?php
//作成した検索フォームファイル名が、searchform_custom.phpの場合
get_template_part('searchform_custom');
?>

お問い合わせ

ガリレオ アンド ヴィーナス合同会社では、Wordpressを使用したコーポレートサイトなどの構築の他、カート機能のついたECショップなどのWEBサイト制作を行っております。

また、ご自身でサイト作成をされたい方向けにセミナー等も開催しております。

詳しくはお気軽にお問い合わせください。

    関連記事

    1. WordPress(ワードプレス)って何?ウェブ系フロントエンジニアが…

    2. ブログなどの投稿記事で実際にWEBデザイナーがよく使用する HTML一…

    3. ブログなどの投稿記事で実際にWEBデザイナーがよく使用する CSS一覧…

    4. 15分でウェブショップ完成!無料&簡単なBASEを使ったウェブショップ…

    5. WordPressで投稿一覧を作成する時に使うのは get_posts…

    6. WordPressを管理するアプリ「WordPressサイトビルダー」…