ワイヤード・パンチ

元・大阪人が、岡山の山奥でも生きていけることを証明するためのブログ。

WordPressでチェックボックス型カスタムフィールドをOR検索する方法。

仕事のうえで制作してるサイトにて、Advanced Custom Filedsというプラグインを使って、各投稿にチェックボックス型のカスタムフィールドを選択できるようにしました。

そして、サイト上に設置しているフォームからチェックボックスを選択して検索を実行すると、該当する投稿だけが検索結果一覧に出るようにしています。

しかし、選択したものすべてを含むAND検索ではなく、一部でも含んでいたらヒットさせるOR検索にしてほしいと言われてしまいました。

広告

AND検索だったときのコード。

入力フォーム上のチェックボックスによって選ばれた値によって、pre_get_postsで行うカスタムフィールドの値参照の結果が変わり、投稿一覧にも影響を与えるようにします。

add_action("pre_get_posts", function ($query) {
	if(is_admin()) {
		return;
	} elseif(!$query->is_main_query()) {
		return;
	} elseif(is_page()) {
		return;
	}
	if(is_post_type_archive("hogehoge") {
		$meta_query = [
			"relation" => "AND",
		];
		if(filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)) {
			foreach(filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) as $item) {
				$args = [
					"key" => "選べ",
					"value" => $item,
					"compare" => "LIKE",
				];
				array_push($meta_query, $args);
			}
		}
		$query->set("meta_query", $meta_query);
	}
	return $query;
});

フォームのチェックボックスから送信されてきた値は、filter_inputで取得できます。

チェックボックスなど、値が複数あって配列になる場合は、後ろに何やらおまじないを、ごちゃごちゃと付けないといけませんが、そういう決まりなので仕方ありません。

たとえば上記のコードのmeta_queryの配列の中身は、以下のようになります。

"meta_query" => [
	"relation" => "AND",
	[
		"key" => "選べ",
		"value" => "あれ",
		"compare" => "LIKE",
	],
	[
		"key" => "選べ",
		"value" => "なに",
		"compare" => "LIKE",
	],
	[
		"key" => "選べ",
		"value" => "どこ",
		"compare" => "LIKE",
	],
];

上記の場合だと、カスタムフィールドに「あれ」「なに」「どこ」がすべて含まれている投稿のみ表示できます。

では、これをOR検索にするには?

OR検索の失敗例。

add_action("pre_get_posts", function ($query) {
	if(is_admin()) {
		return;
	} elseif(!$query->is_main_query()) {
		return;
	} elseif(is_page()) {
		return;
	}
	if(is_post_type_archive("hogehoge") {
		$meta_query = [
			"relation" => "AND",
		];
		if(filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)) {
			$args = [
				"key" => "選べ",
				"value" => filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY),
				"compare" => "IN",
			];
			array_push($meta_query, $args);
		}
		$query->set("meta_query", $meta_query);
	}
	return $query;
});

先程のコードとどこが違うかと言うと、compareがLIKEからINになっています。

INは、いずれかを含むという意味だそうです。

"meta_query" => [
	"relation" => "AND",
	[
		"key" => "選べ",
		"value" => ["あれ", "どこ", "なに"],
		"compare" => "IN",
	],
];

配列の中身はこのようになるはずです。

よって、foreachで一個一個条件を足すのではなく、配列そのままをvalueにしてINすれば、いずれか一致という検索が可能かと思ったのですが…。

結果は、何もヒットしなくなってしまいました

チェックボックスに対しては使えないのでしょうか?

OR検索の簡単な成功例。

add_action("pre_get_posts", function ($query) {
	if(is_admin()) {
		return;
	} elseif(!$query->is_main_query()) {
		return;
	} elseif(is_page()) {
		return;
	}
	if(is_post_type_archive("hogehoge") {
		$meta_query = [
			"relation" => "OR",
		];
		if(filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)) {
			foreach(filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) as $item) {
				$args = [
					"key" => "選べ",
					"value" => $item,
					"compare" => "LIKE",
				];
				array_push($meta_query, $args);
			}
		}
		$query->set("meta_query", $meta_query);
	}
	return $query;
});

はじめのコードから、relationをただ単純にANDからORに変えただけです。

配列の中身は下記のようになります。

"meta_query" => [
	"relation" => "OR",
	[
		"key" => "選べ",
		"value" => "あれ",
		"compare" => "LIKE",
	],
	[
		"key" => "選べ",
		"value" => "なに",
		"compare" => "LIKE",
	],
	[
		"key" => "選べ",
		"value" => "どこ",
		"compare" => "LIKE",
	],
];

これでいちおう、チェックボックスから選んだもののうち、いずれかを含む投稿をすべて表示させられます。

AND検索とOR検索を両方やりたい。

カスタムフィールドの種類は1つだけではありません。

一部のカスタムフィールドに対してはOR検索にしたいけど、他のものはAND検索にしたい。

そういうときは、どうすればいいのでしょうか?

add_action("pre_get_posts", function ($query) {
	if(is_admin()) {
		return;
	} elseif(!$query->is_main_query()) {
		return;
	} elseif(is_page()) {
		return;
	}
	if(is_post_type_archive("hogehoge") {
		$meta_query = [
			"relation" => "AND",
		];
		if(filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)) {
			$or = [
				"relation" => "OR",
			];
			foreach(filter_input(INPUT_GET, "選べ", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) as $item) {
				$args = [
					"key" => "選べ",
					"value" => $item,
					"compare" => "LIKE",
				];
				array_push($or, $args);
			}
			array_push($meta_query, $or);
		}
		if(filter_input(INPUT_GET, "もうひとつのカスタムフィールド", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY)) {
			foreach(filter_input(INPUT_GET, "もうひとつのカスタムフィールド", FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) as $item) {
				$args = [
					"key" => "もうひとつのカスタムフィールド",
					"value" => $item,
					"compare" => "LIKE",
				];
				array_push($meta_query, $args);
			}
		}
		$query->set("meta_query", $meta_query);
	}
	return $query;
});

実は、relationは複数の階層に分けて、設置することができたのです。

上記のコードの配列は、下記のようになります。

"meta_query" => [
	"relation" => "AND",
	[
		"relation" => "OR",
		[
			"key" => "選べ",
			"value" => "あれ",
			"compare" => "LIKE",
		],
		[
			"key" => "選べ",
			"value" => "なに",
			"compare" => "LIKE",
		],
		[
			"key" => "選べ",
			"value" => "どこ",
			"compare" => "LIKE",
		],
	],
	[
		"relation" => "AND",
		[
			"key" => "もうひとつのカスタムフィールド",
			"value" => "①",
			"compare" => "LIKE",
		],
		[
			"key" => "②",
			"value" => "なに",
			"compare" => "LIKE",
		],
	],
];

これで、「選べ」というカスタムフィールドではOR検索、「もうひとつのカスタムフィールド」というカスタムフィールドではAND検索を、両立することができました。