2

I'm trying to find a way to not show all the terms of a taxonomy, but only the terms of the current displayed posts of the wp_query.

The code below displays all terms for 'brands' taxonomy and the query displays all products of the current category, i want to display only the terms that are set on the products that are displaying.

$marcas_terms = get_terms([
  'taxonomy' => 'brands'
]);

foreach ($brands_terms as $brand_term) { 
  <input type="checkbox" id="<?php echo $brand_term->term_id; ?>" name="marca" value="<?php echo $brand_term->term_id; ?>">
  <label for="<?php echo $brand_term->term_id; ?>"><?php echo $brand_term->name; ?></label>
}

$args = array(
  'post_type' => 'product',
  'product_cat' => get_queried_object()
);

$query = new WP_Query( $args );
   if ( $query->have_posts() ) {
     while( $query->have_posts() ) : $query->the_post();

        get_template_part("templates/product-content-category");

     endwhile;
   } wp_reset_postdata(); 

2 Answers 2

3

You'd probably do something like this

$args = array(
  'post_type' => 'product',
  'product_cat' => get_queried_object()
);
$query = new WP_Query( $args );

$termsInPosts = array();
if ( $query->have_posts() ) {
    while( $query->have_posts() ) : $query->the_post();
        $postTerms = wp_get_post_terms(get_the_ID(), 'brands', array('fields' => 'term_id'));
        foreach ($postTerms as $postTerm)
            if (!in_array($postTerm->term_id, $termsInPosts))
                $termsInPosts[] = $postTerm->term_id;
    endwhile;
} 

$marcas_terms = get_terms([
  'taxonomy' => 'brands',
  'include' => $termsInPosts
]);

foreach ($brands_terms as $brand_term) { 
  <input type="checkbox" id="<?php echo $brand_term->term_id; ?>" name="marca" value="<?php echo $brand_term->term_id; ?>">
  <label for="<?php echo $brand_term->term_id; ?>"><?php echo $brand_term->name; ?></label>
}

if ( $query->have_posts() ) {
    while( $query->have_posts() ) : $query->the_post();
        get_template_part("templates/product-content-category");
    endwhile;
} 

wp_reset_postdata(); 

What you're doing is just running through the loop before hand, getting the id's of terms within the posts, adding to an array, then when you call get_terms() you're using include to include only the terms you found.

I haven't tested this code, it's freehand, but it should work, or at least steer you in the right direction.

Hope that helps.

3

I think we can simplify it with the object_ids argument of get_terms(), with post IDs plucked from the given posts array.

Here's an untested skeleton, if I understand the problem correctly:

// Your post query
$query = new WP_Query( $args );

if( $query->have_posts() ) {

    // Get terms from the post IDs of the above post query
    $brand_terms = get_terms( [
        'taxonomy'   => 'brands',
        'object_ids' => wp_list_pluck( $query->posts, 'ID' ),
    ] );

    // Your terms loop
    foreach ( $brands_terms as $brand_term ) { 
        // ...
    }

    // Your posts loop
    while( $query->have_posts() ) { 
        $query->the_post();
        get_template_part( "templates/product-content-category" );
    }

    wp_reset_postdata(); 
}

Hope it helps.

4
  • Would this work if you have a WP Query with pagination? Would it work with a WP Query returning 1000s of posts? Thanks Commented Mar 1, 2019 at 9:36
  • I think so if I understand you correctly, because with pagination, e.g. $args['posts_per_page']=10; and $args['paged']=2; then $query->posts should only contain the posts that are within that given page. @user1280853
    – birgire
    Commented Mar 1, 2019 at 10:56
  • that's the problem, for example, I want to do what the original poster wants above, only display taxonomies that actually have posts attached to them in WP Query, so if that post was on page 5 of pagination, for example, if wouldn't include them. Hope that makes sense? Commented Mar 1, 2019 at 13:13
  • I guess I'm misunderstanding your setup :-) but the object_ids part of get_terms() should fetch only the terms that are associated with the post IDs of that array. The default of WP_Query is to have posts_per_page as 10. so the OP is most likely fetching 10 posts of the first page. So $query->posts should contain these 10 posts, and we pluck the ID out if it and feed it to the object_ids part of the get_terms().
    – birgire
    Commented Mar 1, 2019 at 16:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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