Making Rating Filter always show
-
I used the widget Rating Filter, on my shop page it will only show if there are available products to filter by rating. I want to show the Rating Filter (1 to 5) even no available products nor no ratings yet. Is this possible, is there a hook for that?
-
Hi there,
Can you share a bit more on the use-case here? The reason I’m asking is that if there are no products (with ratings) to filter, what should the widget then filter?
Hello! It doesn’t matter if there are no products to filter, I just want to keep it viewable for the sake of the UI.
In order to do so, you’d need to alter the widget to no longer count if there are products in that rating. This is the section you’re looking for:
Can you help me a little? I lost in the width of the star. I managed to show them all but the size of the star 5 to 1 is a little messy because of the calculation of rating.
for ( $rating = 5; $rating >= 1; $rating-- ) { $count = $this->get_filtered_product_count( $rating ); /*if ( empty( $count ) ) { continue; }*/ $found = true; $link = $base_link; if ( in_array( $rating, $rating_filter, true ) ) { $link_ratings = implode( ',', array_diff( $rating_filter, array( $rating ) ) ); } else { $link_ratings = implode( ',', array_merge( $rating_filter, array( $rating ) ) ); } $class = in_array( $rating, $rating_filter, true ) ? 'wc-layered-nav-rating chosen' : 'wc-layered-nav-rating'; $link = apply_filters( 'woocommerce_rating_filter_link', $link_ratings ? add_query_arg( 'rating_filter', $link_ratings, $link ) : remove_query_arg( 'rating_filter' ) ); /** This is responsible for the width of the golden color of rating. **/ $rating_html = wc_get_star_rating_html( $rating ); $count_html = wp_kses( apply_filters( 'woocommerce_rating_filter_count', "({$count})", $count, $rating ), array( 'em' => array(), 'span' => array(), 'strong' => array(), ) ); printf( '<li class="%s"><a href="%s"><span class="star-rating">%s</span> %s</a></li>', esc_attr( $class ), esc_url( $link ), $rating_html, $count_html ); // WPCS: XSS ok. }
- This reply was modified 4 years, 3 months ago by panda.
Alright, I managed to do it.
I hope there is an easy way to do this, probably a hook, action, or filter to disable the counter and display them all. Anyway, by extending the class of
WC_Widget_Rating_Filter
I managed to override the widget.Here’s the full source in my
functions.php
./** * Widget rating filter class. */ class Custom_Widget_Rating_Filter extends WC_Widget_Rating_Filter { /** * Constructor. */ public function __construct() { $this->widget_cssclass = 'woocommerce widget_rating_filter'; $this->widget_description = __( 'Display a list of star ratings to filter products in your store.', 'woocommerce' ); $this->widget_id = 'woocommerce_rating_filter'; $this->widget_name = __( 'Filter Products by Rating', 'woocommerce' ); $this->settings = array( 'title' => array( 'type' => 'text', 'std' => __( 'Average rating', 'woocommerce' ), 'label' => __( 'Title', 'woocommerce' ), ), ); parent::__construct(); } /** * Count products after other filters have occurred by adjusting the main query. * * @param int $rating Rating. * @return int */ protected function get_filtered_product_count( $rating ) { global $wpdb; $tax_query = WC_Query::get_main_tax_query(); $meta_query = WC_Query::get_main_meta_query(); // Unset current rating filter. foreach ( $tax_query as $key => $query ) { if ( ! empty( $query['rating_filter'] ) ) { unset( $tax_query[ $key ] ); break; } } // Set new rating filter. $product_visibility_terms = wc_get_product_visibility_term_ids(); $tax_query[] = array( 'taxonomy' => 'product_visibility', 'field' => 'term_taxonomy_id', 'terms' => $product_visibility_terms[ 'rated-' . $rating ], 'operator' => 'IN', 'rating_filter' => true, ); $meta_query = new WP_Meta_Query( $meta_query ); $tax_query = new WP_Tax_Query( $tax_query ); $meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' ); $tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' ); $sql = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) FROM {$wpdb->posts} "; $sql .= $tax_query_sql['join'] . $meta_query_sql['join']; $sql .= " WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish' "; $sql .= $tax_query_sql['where'] . $meta_query_sql['where']; $search = WC_Query::get_main_search_query_sql(); if ( $search ) { $sql .= ' AND ' . $search; } return absint( $wpdb->get_var( $sql ) ); // WPCS: unprepared SQL ok. } /** * Widget function. * * @see WP_Widget * @param array $args Arguments. * @param array $instance Widget instance. */ public function widget( $args, $instance ) { if ( ! is_shop() && ! is_product_taxonomy() ) { return; } if ( ! WC()->query->get_main_query()->post_count ) { return; } ob_start(); $found = false; $rating_filter = isset( $_GET['rating_filter'] ) ? array_filter( array_map( 'absint', explode( ',', wp_unslash( $_GET['rating_filter'] ) ) ) ) : array(); // WPCS: input var ok, CSRF ok, sanitization ok. $base_link = remove_query_arg( 'paged', $this->get_current_page_url() ); $this->widget_start( $args, $instance ); echo '<ul>'; for ( $rating = 5; $rating >= 1; $rating-- ) { $count = $this->get_filtered_product_count( $rating ); /* Responsible for showing available rating filter only. if ( empty( $count ) ) { continue; }*/ $found = true; $link = $base_link; if ( in_array( $rating, $rating_filter, true ) ) { $link_ratings = implode( ',', array_diff( $rating_filter, array( $rating ) ) ); } else { $link_ratings = implode( ',', array_merge( $rating_filter, array( $rating ) ) ); } $class = in_array( $rating, $rating_filter, true ) ? 'wc-layered-nav-rating chosen' : 'wc-layered-nav-rating'; $link = apply_filters( 'woocommerce_rating_filter_link', $link_ratings ? add_query_arg( 'rating_filter', $link_ratings, $link ) : remove_query_arg( 'rating_filter' ) ); /* Responsible for showing rating span (gold|width) $rating_html = wc_get_star_rating_html( $rating ); */ $count_html = wp_kses( apply_filters( 'woocommerce_rating_filter_count', "({$count})", $count, $rating ), array( 'em' => array(), 'span' => array(), 'strong' => array(), ) ); $rating_html = '<span style="width:'.(($rating/5)*100).'%">Rated <strong class="rating">'.$rating.'</strong> out of '.$rating.'</span>'; printf( '<li class="%s"><a href="%s"><span class="star-rating">%s</span> %s</a></li>', esc_attr( $class ), esc_url( $link ), $rating_html, $count_html ); // WPCS: XSS ok. } echo '</ul>'; $this->widget_end( $args ); if ( ! $found ) { ob_end_clean(); } else { echo ob_get_clean(); // WPCS: XSS ok. } } } //handling the widget registration function my_widget_price_filter_register() { unregister_widget( 'WC_Widget_Rating_Filter' ); //unregister the default register_widget( 'Custom_Widget_Rating_Filter' ); //register the new one above. } add_action( 'widgets_init', 'my_widget_price_filter_register' );
then in the
CSS
I override thewidth
because the default one is6.5em
which will make the fill color overlap..widget_rating_filter li.wc-layered-nav-rating span.star-rating{ width: 6em !important; }
I hope this helps someone who wants to make the UI of their store more beautiful.
- This reply was modified 4 years, 3 months ago by panda.
UPDATED: I forgot to remove the condition;
if ( ! WC()->query->get_main_query()->post_count ) { return; }
In
functions.php
, the code should be:class Custom_Widget_Rating_Filter extends WC_Widget_Rating_Filter { /** * Constructor. */ public function __construct() { $this->widget_cssclass = 'woocommerce widget_rating_filter'; $this->widget_description = __( 'Display a list of star ratings to filter products in your store.', 'woocommerce' ); $this->widget_id = 'woocommerce_rating_filter'; $this->widget_name = __( 'Filter Products by Rating', 'woocommerce' ); $this->settings = array( 'title' => array( 'type' => 'text', 'std' => __( 'Average rating', 'woocommerce' ), 'label' => __( 'Title', 'woocommerce' ), ), ); parent::__construct(); } /** * Count products after other filters have occurred by adjusting the main query. * * @param int $rating Rating. * @return int */ protected function get_filtered_product_count( $rating ) { global $wpdb; $tax_query = WC_Query::get_main_tax_query(); $meta_query = WC_Query::get_main_meta_query(); // Unset current rating filter. foreach ( $tax_query as $key => $query ) { if ( ! empty( $query['rating_filter'] ) ) { unset( $tax_query[ $key ] ); break; } } // Set new rating filter. $product_visibility_terms = wc_get_product_visibility_term_ids(); $tax_query[] = array( 'taxonomy' => 'product_visibility', 'field' => 'term_taxonomy_id', 'terms' => $product_visibility_terms[ 'rated-' . $rating ], 'operator' => 'IN', 'rating_filter' => true, ); $meta_query = new WP_Meta_Query( $meta_query ); $tax_query = new WP_Tax_Query( $tax_query ); $meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' ); $tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' ); $sql = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) FROM {$wpdb->posts} "; $sql .= $tax_query_sql['join'] . $meta_query_sql['join']; $sql .= " WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish' "; $sql .= $tax_query_sql['where'] . $meta_query_sql['where']; $search = WC_Query::get_main_search_query_sql(); if ( $search ) { $sql .= ' AND ' . $search; } return absint( $wpdb->get_var( $sql ) ); // WPCS: unprepared SQL ok. } /** * Widget function. * * @see WP_Widget * @param array $args Arguments. * @param array $instance Widget instance. */ public function widget( $args, $instance ) { if ( ! is_shop() && ! is_product_taxonomy() ) { return; } /* Responsible for not showing the STAR when query returns empty if ( ! WC()->query->get_main_query()->post_count ) { return; }*/ ob_start(); $found = false; $rating_filter = isset( $_GET['rating_filter'] ) ? array_filter( array_map( 'absint', explode( ',', wp_unslash( $_GET['rating_filter'] ) ) ) ) : array(); // WPCS: input var ok, CSRF ok, sanitization ok. $base_link = remove_query_arg( 'paged', $this->get_current_page_url() ); $this->widget_start( $args, $instance ); echo '<ul>'; for ( $rating = 5; $rating >= 1; $rating-- ) { $count = $this->get_filtered_product_count( $rating ); /*Responsible for not showing all the 5 star rating if ( empty( $count ) ) { continue; }*/ $found = true; $link = $base_link; if ( in_array( $rating, $rating_filter, true ) ) { $link_ratings = implode( ',', array_diff( $rating_filter, array( $rating ) ) ); } else { $link_ratings = implode( ',', array_merge( $rating_filter, array( $rating ) ) ); } $class = in_array( $rating, $rating_filter, true ) ? 'wc-layered-nav-rating chosen' : 'wc-layered-nav-rating'; $link = apply_filters( 'woocommerce_rating_filter_link', $link_ratings ? add_query_arg( 'rating_filter', $link_ratings, $link ) : remove_query_arg( 'rating_filter' ) ); /* Responsible for showing rating span (gold|width) $rating_html = wc_get_star_rating_html( $rating ); */ $count_html = wp_kses( apply_filters( 'woocommerce_rating_filter_count', "({$count})", $count, $rating ), array( 'em' => array(), 'span' => array(), 'strong' => array(), ) ); $rating_html = '<span style="width:'.(($rating/5)*100).'%">Rated <strong class="rating">'.$rating.'</strong> out of '.$rating.'</span>'; $checked = ''; if(in_array( $rating, $rating_filter, true )){ $checked = '<i class="fas fa-check-circle csx-attribute-active"></i><i class="fas fa-times-circle csx-attribute-active-remove"></i>'; }else{ $checked = '<i class="fas fa-check-circle csx-attribute-not-active"></i>'; } printf( '<li class="%s"><a href="%s"><span class="star-rating">%s</span> %s</a>%s</li>', esc_attr( $class ), esc_url( $link ), $rating_html, $count_html, $checked); // WPCS: XSS ok. } echo '</ul>'; $this->widget_end( $args ); if ( ! $found ) { ob_end_clean(); } else { echo ob_get_clean(); // WPCS: XSS ok. } } } //handling the widget registration function my_widget_price_filter_register() { unregister_widget( 'WC_Widget_Rating_Filter' ); //unregister the default register_widget( 'Custom_Widget_Rating_Filter' ); //register the new one above. } add_action( 'widgets_init', 'my_widget_price_filter_register' );
No need to change the
CSS
but if you do it should be;.widget_rating_filter li.wc-layered-nav-rating span.star-rating{ width: 6em !important; /* change this */ }
- This reply was modified 4 years, 3 months ago by panda.
- The topic ‘Making Rating Filter always show’ is closed to new replies.