0

I'd like to create a WooCommerce products widget like the standard WooCommerce products widget, but with the option to filter on category. I know there is a shortcode for displaying products of a certain category, but I don't like the standard thumbnail view, but like to have a list like in the WooCom products widget.

On Github, I have found the following code which allows to add a WooCom products widget with a filter on product ID:

<?php
/*
Plugin Name: Woocommerce Custom Widget Product
Description: This plugin help display a list of customs products on your website
Author: Binh Nguyen
Version: 1.0
Author URI: http://vietcomic.net/
*/


if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class Bi_Widget_Product extends WP_Widget
{

    function __construct()
    {
        parent::__construct(
                'woocommerce_ndbProducts',
                __( 'WP Customs Products', 'ndb' ),
                array('description' => __( 'This plugin help display a list of customs products on your website.', 'ndb' )) 
                );
    }

    public function widget( $args, $instance ) {

        extract( $args );
        $title = apply_filters( 'widget_title', $instance['title']);
        $ids   = $instance['ids'];
        $arr_id = explode(',',$ids);
        $query_args = array(
            'post_status'    => 'publish',
            'post_type'      => 'product',
            'no_found_rows'  => 1,
            'post__in'       => $arr_id
        ); 

        $r = new WP_Query( $query_args );
        if ( $r->have_posts() ) {

            echo $before_widget;

            if ( $title )
                echo $before_title . $title . $after_title;

            echo '<ul class="product_list_widget">';

            while ( $r->have_posts()) {
                $r->the_post();
                global $product;
                 ?>
                    <li>
                        <a href="<?php echo esc_url( get_permalink( $product->id ) ); ?>" title="<?php echo esc_attr( $product->get_title() ); ?>">
                            <?php echo $product->get_image(); ?>
                            <?php echo $product->get_title(); ?>
                        </a>
                        <?php if ( ! empty( $show_rating ) ) echo $product->get_rating_html(); ?>
                        <?php echo $product->get_price_html(); ?>
                    </li>
                <?php
            }

            echo '</ul>';

            echo $after_widget;
        }

        wp_reset_postdata();

        echo $content;

    }
    // Widget Backend

    public function form($instance){
        $title = (isset($instance['title'])) ? $instance['title'] : __( 'Products', 'ndb' );
        $ids = $instance['ids'];
        ?>
        <p>
            <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title :'); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"  name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
        </p>
        <p>
            <label for="<?php echo $this->get_field_id('ids'); ?>"><?php _e('IDs :'); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id('ids'); ?>"  name="<?php echo $this->get_field_name( 'ids' ); ?>" type="text" value="<?php echo esc_attr( $ids ); ?>" />
        </p>
        <?php

    }

    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        $instance['ids'] = ( ! empty( $new_instance['ids'] ) ) ? strip_tags( $new_instance['ids'] ) : '';
        return $instance;
    }


}



add_action( 'widgets_init', function(){
    register_widget( 'Bi_Widget_Product' );
} );

Can any of you Wordpress Guru's help me to adapt this so I can filter on category instead of product ID? I'll do an attempt myself, but definitely can use your help.


Own attempt: I think I should change my WP_query arguments to retrieve the category ID's instead of the post ID's. However, I tried this & this is not working.

    $query_args = array(
        'post_status'    => 'publish',
        'post_type'      => 'product',
        'no_found_rows'  => 1,
        'cat'        => $'arr_id'
    ); 

    $r = new WP_Query( $query_args );

Full solution as provided by LWS-Mo Many many many thanks! You made my day. I would like to accept and upvote your comment but since I am new on the forum, my reputation is not high enough for that :(. Anyone else who is able to use the solution, give the man some credits ;). Again thanks!

<?php
/*
Plugin Name: Products by category
Description: This plugin displays a list of products of a certain category on your website.
*/


if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class Bi_Widget_Product extends WP_Widget
{

    function __construct()
    {
        parent::__construct(
                'woocommerce_ndbProducts',
                __( 'Products by category', 'ndb' ),
                array('description' => __( 'This plugin displays a list of products of a certain category on your website.', 'ndb' )) 
                );
    }

    public function widget( $args, $instance ) {

        extract( $args );
        $title = apply_filters( 'widget_title', $instance['title']);
        $ids   = $instance['ids'];
        $arr_id = explode(',',$ids);
        $query_args = array(
            'post_status'    => 'publish',
            'post_type'      => 'product',
            'no_found_rows'  => 1,
            'posts_per_page' => -1, //-1 needed for displaying all posts of the category
            'tax_query' => array(
                array(
                    'taxonomy' => 'product_cat', //the taxonomy we want to query
                    'field' => 'term_id', //we use the term_id tp find our terms
                    'terms' => $arr_id //our comma seperated list of ID´s
                )
            )
        );

        $r = new WP_Query( $query_args );
        if ( $r->have_posts() ) {

            echo $before_widget;

            if ( $title )
                echo $before_title . $title . $after_title;

            echo '<ul class="product_list_widget">';

            while ( $r->have_posts()) {
                $r->the_post();
                global $product;
                 ?>
                    <li>
                        <a href="<?php echo esc_url( get_permalink( $product->id ) ); ?>" title="<?php echo esc_attr( $product->get_title() ); ?>">
                            <?php echo $product->get_image(); ?>
                            <?php echo $product->get_title(); ?>
                        </a>
                        <?php if ( ! empty( $show_rating ) ) echo $product->get_rating_html(); ?>
                        <?php echo $product->get_price_html(); ?>
                    </li>
                <?php
            }

            echo '</ul>';

            echo $after_widget;
        }

        wp_reset_postdata();

        echo $content;

    }
    // Widget Backend

    public function form($instance){
        $title = (isset($instance['title'])) ? $instance['title'] : __( 'Products', 'ndb' );
        $ids = $instance['ids'];
        ?>
        <p>
            <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"  name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
        </p>
        <p>
            <label for="<?php echo $this->get_field_id('ids'); ?>"><?php _e('Category:'); ?></label>
            <input class="widefat" id="<?php echo $this->get_field_id('ids'); ?>"  name="<?php echo $this->get_field_name( 'ids' ); ?>" type="text" value="<?php echo esc_attr( $ids ); ?>" />
        </p>
        <?php

    }

    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        $instance['ids'] = ( ! empty( $new_instance['ids'] ) ) ? strip_tags( $new_instance['ids'] ) : '';
        return $instance;
    }


}



add_action( 'widgets_init', function(){
    register_widget( 'Bi_Widget_Product' );
} );

1 Answer 1

1

The plugin you posted creates a new widget with 2 input fields. One field for the title of the widget, another field to enter a comma separated list of product ID´s.

You can change the provided code, to be able to enter a comma separated list of product_cat ID´s. (instead of product ID´s)

You only need to change the $query_args for the WP_Query.

First, remove the line 'post__in' => $arr_id. Instead we are gonna add the $arr_id(containes the list of ID´s) to a new tax_query.

Change the code:

$query_args = array(
  'post_status'    => 'publish',
  'post_type'      => 'product',
  'no_found_rows'  => 1,
  'posts_per_page' => -1, //-1 needed for displaying all posts of the category
  'tax_query' => array(
     array(
      'taxonomy' => 'product_cat', //the taxonomy we want to query
      'field' => 'term_id', //we use the term_id tp find our terms
      'terms' => $arr_id //our comma seperated list of ID´s
     )
  )
);

Now you can enter a comma separated list of product_cat ID´s in the widget. All products which are in these cats will be displayed.

P.S.
Codex for tax_query: WP_Query #Taxonomy_Parameters.
Limit the displayed posts with 'posts_per_page' => -1. WP_Query #Pagination_Parameters
Also take a look at order and orderby args. WP_Query #Order_Orderby_Parameters
And also watch your commas on the $query_args list!

Your Answer

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

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