So on this Custom Post Type list page there is a list of Properties.
I have a custom search feature where they can search for Properties with certain Taxonomy Terms – but they can also search for Multiple Taxonomy Terms.
Question:
If someone selects 2 terms then the only Properties that should display in the list are Properties with term_one
AND
term_two
So I tried this below:
$required_features_slugs = array();
if( isset ( $_GET['features'] ) ) {
$features_slugs = $_GET['features'];
}
$feature = get_terms('features');
$tmp_required = $required_features_slugs;
$property = array(
'post_type' => 'properties',
'paged' => $paged,
'tax_query' => array(
array(
'taxonomy' => 'features',
'field' => 'slug',
'terms' => $tmp_required,
'operator' => 'AND',
)
),
);
The URL looks like this:
features%5B%5D=accredited-landlord&features%5B%5D=cellarbasement
Now because these two Features are selected it should only return one Property because there is only one Property with term_one
AND
term_two
together
However I don’t get this result instead I get 4 Properties because there are 4 Properties. 3 with term_one
and 1 with term_two
.
What I want to happen is for 1 Property to be returned because there is only one Property with term_once
AND
term_two
together.
Is there something wrong that I am doing in the Query?
Edit: Updated PHP
file
$required_features_slugs = array();
if( isset ( $_GET['features'] ) ) {
$required_features_slugs = $_GET['features'];
}
$all_features = get_terms('features');
if( ! empty( $required_features_slugs ) ) {
foreach ( $all_features as $feature ) {
$tmp_required = $required_features_slugs;
if( ! in_array($feature->slug, $required_features_slugs) ) {
array_push( $tmp_required, $feature->slug );
}
$property = array(
'post_type' => 'properties',
'paged' => $paged,
'tax_query' => array(
'taxonomy' => 'features',
'field' => 'slug',
'terms' => $tmp_required,
'operator' => 'AND',
),
);
}
}
Edit #2:
So here is the var_dump
to the Query:
array(3) { ["post_type"]=> string(10) "properties" ["paged"]=> int(1) ["tax_query"]=> array(4) { ["taxonomy"]=> string(8) "features" ["field"]=> string(4) "slug" ["terms"]=> array(2) { [0]=> string(19) "accredited-landlord" [1]=> string(14) "cellarbasement" } ["operator"]=> string(3) "AND" } }
And here is the var_dump
to the terms:
array(2) { [0]=> string(19) "accredited-landlord" [1]=> string(14) "cellarbasement" }
3 Answers
Query Arguments:
If $input_terms
is the input array of term slugs, then you should be able to use (if I understand the question correctly):
$property = [
'post_type' => 'properties',
'paged' => $paged,
'tax_query' => [
[
'taxonomy' => 'features',
'field' => 'slug',
'terms' => $input_terms,
'operator' => 'AND',
]
],
];
where we added a missing array in the tax query.
Validation:
We should validate the input terms first.
Here are some examples:
-
Check the maximum number of allowed terms:
$valid_input_terms_max_count = count( $input_terms ) <= 4;
-
Check the minimum number of allowed terms:
$valid_input_terms_min_count = count( $input_terms ) >= 1;
-
Check if they input terms slugs exists (assumes non-empty input array):
$valid_input_terms_slugs = array_reduce( (array) $input_terms, function( $carry, $item ) { return $carry && null !== term_exists( $item, 'features' ); }, true );
where we collect
term_exists()
for all the terms into a single boolean value. -
We could also match the input slugs against a predefined array of slugs
Generated SQL:
Here’s a generated SQL query for two existing term slugs in $input_terms
:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
WHERE 1=1 AND (
(
SELECT COUNT(1)
FROM wp_term_relationships
WHERE term_taxonomy_id IN (160,161)
AND object_id = wp_posts.ID
) = 2
)
AND wp_posts.post_type="properties"
AND (wp_posts.post_status="publish" OR wp_posts.post_status="private")
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date DESC
LIMIT 0, 10
Hope you can adjust this to your needs.