skip to Main Content

I have a Custom Post Type called Products (not WooCommerce). The user selects the Categories using an ACF Taxonomy Field. I’m trying to get each Product per selected Category but some of the products are in multiple categories so when I am looping through the rows they are printing multiple times.

<?php
$product_categories = get_field( 'product_filter_categories' );
$custom_taxonomy='product_category';  
$custom_terms = $product_categories;

foreach($custom_terms as $custom_term) :
    wp_reset_query();

    $args = array(
        'post_type' => 'product',
        'post_status' => 'publish',
        'tax_query' => array(               
            array(
                'taxonomy' => $custom_taxonomy,
                'field' => 'slug',
                'terms' => $custom_term->slug,
            ),
        ),
    );  

    $loop = new WP_Query($args);

    if($loop->have_posts()) :
        $product_coming_soon_image = get_field( 'product_coming_soon_image' );

        while($loop->have_posts()) : $loop->the_post();
            $termsArray = get_the_terms( $post->ID, "product_category" );

            $termsString = "";
            foreach ( $termsArray as $term ) {
                $termsString .= $term->slug.' ';
            } ?>

            <div class="<?php echo $termsString; ?> isotope-item">
                <a href="<?php the_permalink(); ?>">                            
                    <?php if ( has_post_thumbnail() ) :  ?>
                        <img src="<?php the_post_thumbnail_url('') ?>" class="lazy" alt="<?php the_title() ?>" loading="lazy" width="240" height="240">
                    <?php else : ?>
                        <img src="<?php echo esc_url( $product_coming_soon_image['sizes']['our-products'] ); ?>" alt="<?php echo esc_attr( $product_coming_soon_image['alt'] ); ?>" loading="lazy" width="240" height="240" />
                    <?php endif; ?>
                </a>
                <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
            </div>

            <?php
        endwhile; ?>

    <?php
    endif;
endforeach; ?>
</div>

I can’t determine where the duplicates are coming from.

3

Answers


  1. Chosen as BEST ANSWER

    I was able to remove the duplicates by creating an empty array just before the first foreach and then checking if the current post ID was in that array while looping. If the the current post id was not in the array, add it to the array and show the product. If the current post id is in the array, skip it.

    Updated Code

    $product_categories = get_field( 'product_filter_categories' );
    $custom_taxonomy = 'product_category';
    $custom_terms = $product_categories;
    $displayed_products = array();
    
    foreach($custom_terms as $custom_term) :
        wp_reset_query();
    
        $args = array(
            'post_type' => 'product',
            'post_status' => 'publish',
            'tax_query' => array(
                array(
                    'taxonomy' => $custom_taxonomy,
                    'field' => 'slug',
                    'terms' => $custom_term->slug,
                ),
            ),
        );  
    
        $loop = new WP_Query($args);
    
        if($loop->have_posts()) :
            $product_coming_soon_image = get_field( 'product_coming_soon_image' );
    
            while($loop->have_posts()) : $loop->the_post();
                if(!in_array( $post->ID, $displayed_products )) :
                    $termsArray = get_the_terms( $post->ID, "product_category" );
    
                    $termsString = "";
                    foreach ( $termsArray as $term ) {
                        $termsString .= $term->slug.' ';
                    } ?>
    
                    <div class="<?php echo $termsString; ?> isotope-item">
                        <a href="<?php the_permalink(); ?>">
                            <?php if ( has_post_thumbnail() ) :  ?>
                                <img src="<?php the_post_thumbnail_url('') ?>" class="lazy" alt="<?php the_title() ?>" loading="lazy" width="240" height="240">
                            <?php else : ?>
                                <img src="<?php echo esc_url( $product_coming_soon_image['sizes']['our-products'] ); ?>" alt="<?php echo esc_attr( $product_coming_soon_image['alt'] ); ?>" loading="lazy" width="240" height="240" />
                            <?php endif; ?>
                        </a>
                        <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
                    </div>
    
                    <?php
                    array_push( $displayed_products, $post->ID );
                endif;
            endwhile; ?>
    
        <?php
        endif;
    endforeach; ?>
    '''
    

  2. $product_categories = get_field( 'product_filter_categories' );
    $custom_taxonomy='product_category';  
    $custom_terms = $product_categories->term_id;
    
    foreach($custom_terms as $custom_term) :
        
    
        $args = array(
            'post_type' => 'product',
            'post_status' => 'publish',
            'tax_query' => array(               
                array(
                    'taxonomy' => $custom_taxonomy,
                    'field' => 'term_id',
                    'terms' => array($custom_terms),
                    'operator' => 'IN',
                ),
            ),
        );  
    
        $loop = new WP_Query($args);
    
        if($loop->have_posts()) :
            $product_coming_soon_image = get_field( 'product_coming_soon_image',get_the_ID());
    
            while($loop->have_posts()) : $loop->the_post();
                $termsArray = get_the_terms( get_the_ID(), "product_category" );
    
                $termsString = "";
                foreach ( $termsArray as $term ) {
                    $termsString .= $term->slug.' ';
                } ?>
    
                <div class="<?php echo $termsString; ?> isotope-item">
                    <a href="<?php get_permalink(); ?>">                            
                        <?php if ( has_post_thumbnail() ) :  ?>
                            <img src="<?php the_post_thumbnail_url('') ?>" class="lazy" alt="<?php get_the_title() ?>" loading="lazy" width="240" height="240">
                        <?php else : ?>
                            <img src="<?php echo esc_url( $product_coming_soon_image['sizes']['our-products'] ); ?>" alt="<?php echo esc_attr( $product_coming_soon_image['alt'] ); ?>" loading="lazy" width="240" height="240" />
                        <?php endif; ?>
                    </a>
                    <h3><a href="<?php echo get_permalink()(); ?>"><?php get_the_title(); ?></a></h3>
                </div>
    
                <?php
            endwhile; wp_reset_query();?>
    
        <?php
        endif;
    endforeach; ?>
    </div>
    
    Login or Signup to reply.
  3. Ok, so what you are doing is :

    • getting some terms
    • looping on terms
    • getting products by the term
    • looping on products for display

    So indeed, if a product is associated with multiple terms in the loop, they’ll appear multiple times this way.

    You should remove the first foreach, and query product by multiple terms, then loop on the wp_query results. This way you won’t have duplicates:

    $args = array(
                'post_type' => 'product',
                'post_status' => 'publish',
                'tax_query' => array(
                    array(
                        'taxonomy' => $custom_taxonomy,
                        'field' => 'slug',
                        'terms' => array_column($custom_term, 'slug'),
                    ),
                ),
            );
    

    If you really need to loop on your terms, and query product on each loop: you’ll need to store all queried post ids in an array from initiated outside the loop. And add to the query "post not in: ids" with this array of ids "already queried".

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search