phpwordpresswoocommerceproductcustom-taxonomy

How to list all visible products for specific product category in WooCommerce


I want to simply display all products for a specific product category [e.g. "smart-shoes" term slug] on my WooCommerce website. I only want visible products in that category listed.

Here is my code:

$args = array(
 'number' => $number,
 'orderby' => 'title',
 'order' => 'ASC',
 'hide_empty' => $hide_empty,
 'include' => $ids
);
$product_categories = get_terms( 'product_cat', $args );
$count = count($product_categories);
if ( $count > 0 ){
 foreach ( $product_categories as $product_category ) {
 echo '<h4><a href="' . get_term_link( $product_category ) . '">' . $product_category->name . '</a></h4>';
 $args = array(

 'posts_per_page' => -1,
 'tax_query' => array(
 'relation' => 'AND',
   
 array(
 'taxonomy' => 'product_cat',
 'field' => 'slug',
 'terms' => $product_category->slug
   
 )
   
 ),
 'post_type' => 'product',
  'orderby' => 'title',
 'order' => 'ASC',

 );
 $products = new WP_Query( $args );
 echo "<ul>";
 while ( $products->have_posts() ) {
 $products->the_post();
 ?>
 <li>
 <a href="<?php the_permalink(); ?>">
 <?php the_title(); ?>
 </a>
 </li>
 <?php
 }
 echo "</ul>";
 }
}

So far with the code I have been using can only list all categories and all products, even hidden ones.

Any insights? I have been googling and tinkering for hours, without success.


Solution

  • You can include everything in your WP Query (see the related threads at the end) using a combined meta query (one for the product category and the other for the product visibility).

    Try the following (code is commented):

    // Here define the targeted product category term(s) slug
    $targeted_terms = array( 'smart-shoes' );
    
    // The WP_Query
    $wp_query = new WP_Query( array(
        'post_type'      => 'product',
        'post_status'    => 'publish', // Target published products
        'posts_per_page' => -1, // Target all products
        'orderby'        => 'title',
        'order'          => 'ASC',
        'tax_query'      => array(
            'relation'     => 'AND',
            // Target specific product category term(s)
            array(
                'taxonomy' => 'product_cat',
                'field'    => 'slug',
                'terms'    => $targeted_terms,
            ),
            // Target visible products
            array(
                'taxonomy' => 'product_visibility',
                'terms'    => array( 'exclude-from-catalog' ),
                'field'    => 'name',
                'operator' => 'NOT IN',
            )
        ),
    ) );
    
    // The display
    if ($wp_query->have_posts()) {
        echo '<ul>';
    
        while ($wp_query->have_posts()) { 
            $wp_query->the_post();
            printf( '<li><a href="%s">%s</a></li>', get_the_permalink(), get_the_title() );
        }
        echo '</ul>'; 
    } else {
        printf( '<p>%s</p>', esc_html__('Sorry, no products found.') ) ;
    }
    // Restore original Post Data.
    wp_reset_postdata();
    

    It should work as expected.


    Addition

    Embed an Add to Cart button (plus), after each product name:

    1 - Normal Add to Cart link

    Replace:

    printf( '<li><a href="%s">%s</a></li>', get_the_permalink(), get_the_title() );
    

    with:

    // Add to cart button (+)
    $atc_plus = sprintf( ' <a class="button atc-plus" href="?add-to-cart=%d">&plus;</a>', get_the_ID() );
    
    printf( '<li><a href="%s">%s</a> %s</li>', get_the_permalink(), get_the_title(), $atc_plus );
    

    2 - Ajax Add to Cart link

    Replace:

    printf( '<li><a href="%s">%s</a></li>', get_the_permalink(), get_the_title() );
    

    with:

    // Ajax Add to cart button (+)
    $atc_plus = sprintf( ' <a href="?add-to-cart=%d"  rel="nofollow" data-quantity="1" data-product_id="%d" class="button add_to_cart_button ajax_add_to_cart">&plus;</a>', get_the_ID(), get_the_ID() );
    
    printf( '<li><a href="%s">%s</a> %s</li>', get_the_permalink(), get_the_title(), $atc_plus );
    

    Note that on Ajax add to cart action, a "View Cart" link will be displayed. You can hide it with some CSS or by adding this code line before echo '<ul>'; in your code:

    echo '<style>.added_to_cart.wc-forward{display:none;}</style>';
    

    Related threads: