2

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" }
  • Did you check out what the variables contain? E.g. $required_features_slugs and $tmp_required are currently empty arrays and $features_slugs and $feature are never used. – birgire Aug 8 '16 at 10:42
  • I've updated my answer hopefully that answers your question :) – Stephen Aug 8 '16 at 10:44
  • features in $_GET should have brackets on end to behave as array, for example example.com/?features[]=10&features[]=20... – Krzysztof Grabania Aug 8 '16 at 13:18
  • @KrzysztofGrabania they do have the [] there in Unicode %5B%5D is the [] in Unicode – Stephen Aug 8 '16 at 13:24
3
+50

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.

  • Hmmm... maybe I didn't put enough into the question to make it understandable - I have added to the question now. All I want to do is $_GET the URL; check if there is features in the search query and if there is return result depending on that query. However if there are 2 terms in the query only return the Properties with both terms – Stephen Aug 8 '16 at 13:06
  • 1
    As a debug step, just use $input_terms = [ 'term_one', 'term_two' ] and make sure the $property array here above returns correct query results. What happens then? @CoderSte – birgire Aug 8 '16 at 13:09
  • So I've done a var_dump to make sure the query works and it seems to be correct. As for adding in the terms manually to $input_terms I have done that and I still get the result I am getting now with no change – Stephen Aug 8 '16 at 13:13
  • I just tested this and it seems to work as expected on my vanilla install. I only get posts that are assigned to all terms in our $input_terms array. What does your SQL query look like? @CoderSte – birgire Aug 8 '16 at 13:24
  • By SQL Query I assume you mean the WP_Query for that page? If so here it is --> Pastebin Query – Stephen Aug 8 '16 at 13:28
1

Try change operator to 'operator' => 'IN', or try use code something like this:

$required_features_slugs = array();
if( isset ( $_GET['features'] ) ) {
    $required_features_slugs = $_GET['features'];
}

 if( ! empty( $required_features_slugs ) ) {

 $property = array(
        'post_type'     => 'properties',
        'paged'         => $paged,
        'tax_query'         => array(
        'relation' => 'AND',
        ),
  );


foreach ( $required_features_slugs as $feature ) {
        $property['tax_query'][] = array(
            'taxonomy'  => 'features',
            'field'     => 'slug',
            'terms'     => $feature,
        );
    }


}
}
  • Yeah I tried in IN operator and I still get the same result as before - I just tried your method really hoping it was going to work but unfortunately it did not :( – Stephen Aug 8 '16 at 12:49
  • try debug final $property var: echo '<pre>'; print_r( $property ); echo '</pre>'; – Nefro Aug 9 '16 at 6:55
  • Yeah I managed to figure out what was wrong in the end :) Thanks for all your help @Nefro I appreciate it :D – Stephen Aug 9 '16 at 7:48
0

Maybe this will work:

$property = array(
    'post_type'     => 'properties',
    'paged'         => $paged,
    'tax_query'     => array(
        'relation' => 'AND',    
    ),
);

$features = $_GET['features'];

foreach ($features as $feature) {
    $property['tax_query'][] = array(
        'taxonomy'  => 'features',
        'field'     => 'slug',
        'terms'     => $feature,   
    );
}
  • Thanks for your answer :) This one is similar to @Nefro answer so I don't think it will work – Stephen Aug 8 '16 at 13:30
  • But there is no another possibility to make it work – Krzysztof Grabania Aug 8 '16 at 13:31
  • Maybe something could be wrong with my overall Query :/ – Stephen Aug 8 '16 at 13:38
  • Maybe you should change field property in tax_query to term_id istead of slug? EDIT. nvm, I see that in query URL are slugs – Krzysztof Grabania Aug 8 '16 at 13:41
  • Do you iterate over $_GET or get_terms? – Krzysztof Grabania Aug 8 '16 at 13:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.