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.
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.
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">+</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">+</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: