Get a sidebar widget that show products of the same categories in Woocommerce

I’m trying to set a sidebar in the single product page that show all products of the same categories as the product displayed.

That’s how I proceed:

Read More

1) First I’ve created a sidebar called “Products_of_same_Category” to put in there a widget to show what I needed, then in function.php of my child theme I added the following snippet to execute php code in text widget:

// Enable PHP in widgets
add_filter('widget_text','execute_php',100);
function execute_php($html){
     if(strpos($html,"<"."?php")!==false){
          ob_start();
          eval("?".">".$html);
          $html=ob_get_contents();
          ob_end_clean();
     }
     return $html;
}

2) Then when I saw that the snippet runs ok I added that code to test it:

<?php 
$prod=get_the_term_list( $post->ID, 'product_cat');
echo $prod; 
?>

And all worked fine, it gave me the exact name of the current category of the product displayed in the single product page.

3) So I’ve tried another test, deleting the previous code, to view if a shortcode translated in php should works in a widget too (writing at this time the exact category name requested, in this case “towels” – in the code below I substitute it with THE-CATEGORY-I-LIKE):

<?php echo do_shortcode('[product_category category=“THE-CATEGORY-I-LIKE” per_page="20" columns="1" orderby="title" order="desc"]'); ?>`

And all was again well done!

4) Finally I mixed all in this code to show the list of products of same categories but something goes wrong:

<?php $prod=get_the_term_list( $post->ID, 'product_cat', '', '', '' );
echo do_shortcode('[product_category category="'.$prod.'" per_page="20" columns="1" orderby="title" order="desc"]'); ?>

In last case the code doesn’t display anything. I don’t understand where I made mistakes, the syntax is wrong or the solving approach is illogical?

I really appreciate any help about this.

Related posts

1 comment

  1. The problem is how you get the category slug. get_the_term_list will give you a formatted linked list of the categories, so it will display category names, not category slugs, which are different things. “Towels” would be your category name, but the category slug would be “towels”. And product_category shortcode expect a slug, not a name.

    The correct approach to get the category product slug is the following:

    $terms = get_the_terms($post, 'product_cat');
    if($terms && ! is_wp_error($terms)) {
        foreach($terms as $term) {
            echo do_shortcode('[product_category category="'.$term->slug.'" per_page="20" columns="1" orderby="title" order="desc"]');
        }
    }
    

    This will display the products of all the categories associated to your product. See get_the_terms doc for reference.

    In order to remove from the results the current product shown, you can make use of the woocommerce_shortcode_products_query filter. It isn’t documented, but you can find it by looking at the product_category shortcode code located in includes/class-wc-shortcodes.php. In the product_category() method you will find the following line:

    $return = self::product_loop( $query_args, $atts, 'product_cat' );
    

    Where $query_args is a WP_Query parameters array. In the same class you will find the method product_loop() called here and see the following:

    $products = new WP_Query( apply_filters( 'woocommerce_shortcode_products_query', $query_args, $atts ) ); 
    

    So the query arguments are filtered – you will be able to work with that to add the desirated behavour. What you want to do is to use the post__not_in parameter to the query like this:

    function remove_current_product_from_wc_shortcode($args, $atts) {
        if(is_product()) { // check if we're on a single product page
            $args['post__not_in'] = array(get_queried_object_id());
        }
        return $args;
    }
    add_filter('woocommerce_shortcode_products_query', 'remove_current_product_from_wc_shortcode');
    

    This code should go in your theme functions.php – please not this is untested, so if it doesn’t work look at the get_queried_object_id() return if it contain the current product ID.

Comments are closed.