1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Rating Filter Widget and related functions. |
4
|
|
|
* |
5
|
|
|
* @package WooCommerce/Widgets |
6
|
|
|
* @version 2.6.0 |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
defined( 'ABSPATH' ) || exit; |
10
|
|
|
|
11
|
|
|
/** |
12
|
|
|
* Widget rating filter class. |
13
|
|
|
*/ |
14
|
|
|
class WC_Widget_Rating_Filter extends WC_Widget { |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Constructor. |
18
|
|
|
*/ |
19
|
|
View Code Duplication |
public function __construct() { |
|
|
|
|
20
|
|
|
$this->widget_cssclass = 'woocommerce widget_rating_filter'; |
21
|
|
|
$this->widget_description = __( 'Display a list of star ratings to filter products in your store.', 'woocommerce' ); |
22
|
|
|
$this->widget_id = 'woocommerce_rating_filter'; |
23
|
|
|
$this->widget_name = __( 'Filter Products by Rating', 'woocommerce' ); |
24
|
|
|
$this->settings = array( |
25
|
|
|
'title' => array( |
26
|
|
|
'type' => 'text', |
27
|
|
|
'std' => __( 'Average rating', 'woocommerce' ), |
28
|
|
|
'label' => __( 'Title', 'woocommerce' ), |
29
|
|
|
), |
30
|
|
|
); |
31
|
|
|
parent::__construct(); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Count products after other filters have occurred by adjusting the main query. |
36
|
|
|
* |
37
|
|
|
* @param int $rating Rating. |
38
|
|
|
* @return int |
39
|
|
|
*/ |
40
|
|
|
protected function get_filtered_product_count( $rating ) { |
41
|
|
|
global $wpdb; |
42
|
|
|
|
43
|
|
|
$tax_query = WC_Query::get_main_tax_query(); |
44
|
|
|
$meta_query = WC_Query::get_main_meta_query(); |
45
|
|
|
|
46
|
|
|
// Unset current rating filter. |
47
|
|
|
foreach ( $tax_query as $key => $query ) { |
48
|
|
|
if ( ! empty( $query['rating_filter'] ) ) { |
49
|
|
|
unset( $tax_query[ $key ] ); |
50
|
|
|
break; |
51
|
|
|
} |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
// Set new rating filter. |
55
|
|
|
$product_visibility_terms = wc_get_product_visibility_term_ids(); |
56
|
|
|
$tax_query[] = array( |
57
|
|
|
'taxonomy' => 'product_visibility', |
58
|
|
|
'field' => 'term_taxonomy_id', |
59
|
|
|
'terms' => $product_visibility_terms[ 'rated-' . $rating ], |
60
|
|
|
'operator' => 'IN', |
61
|
|
|
'rating_filter' => true, |
62
|
|
|
); |
63
|
|
|
|
64
|
|
|
$meta_query = new WP_Meta_Query( $meta_query ); |
65
|
|
|
$tax_query = new WP_Tax_Query( $tax_query ); |
66
|
|
|
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' ); |
67
|
|
|
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' ); |
68
|
|
|
|
69
|
|
|
$sql = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) FROM {$wpdb->posts} "; |
70
|
|
|
$sql .= $tax_query_sql['join'] . $meta_query_sql['join']; |
71
|
|
|
$sql .= " WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish' "; |
72
|
|
|
$sql .= $tax_query_sql['where'] . $meta_query_sql['where']; |
73
|
|
|
|
74
|
|
|
$search = WC_Query::get_main_search_query_sql(); |
75
|
|
|
if ( $search ) { |
76
|
|
|
$sql .= ' AND ' . $search; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
return absint( $wpdb->get_var( $sql ) ); // WPCS: unprepared SQL ok. |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* Widget function. |
84
|
|
|
* |
85
|
|
|
* @see WP_Widget |
86
|
|
|
* @param array $args Arguments. |
87
|
|
|
* @param array $instance Widget instance. |
88
|
|
|
*/ |
89
|
|
|
public function widget( $args, $instance ) { |
90
|
|
|
if ( ! is_shop() && ! is_product_taxonomy() ) { |
91
|
|
|
return; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
if ( ! WC()->query->get_main_query()->post_count ) { |
95
|
|
|
return; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
ob_start(); |
99
|
|
|
|
100
|
|
|
$found = false; |
101
|
|
|
$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. |
102
|
|
|
$base_link = remove_query_arg( 'paged', $this->get_current_page_url() ); |
103
|
|
|
|
104
|
|
|
$this->widget_start( $args, $instance ); |
105
|
|
|
|
106
|
|
|
echo '<ul>'; |
107
|
|
|
|
108
|
|
|
for ( $rating = 5; $rating >= 1; $rating-- ) { |
109
|
|
|
$count = $this->get_filtered_product_count( $rating ); |
110
|
|
|
if ( empty( $count ) ) { |
111
|
|
|
continue; |
112
|
|
|
} |
113
|
|
|
$found = true; |
114
|
|
|
$link = $base_link; |
115
|
|
|
|
116
|
|
|
if ( in_array( $rating, $rating_filter, true ) ) { |
117
|
|
|
$link_ratings = implode( ',', array_diff( $rating_filter, array( $rating ) ) ); |
118
|
|
|
} else { |
119
|
|
|
$link_ratings = implode( ',', array_merge( $rating_filter, array( $rating ) ) ); |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
$class = in_array( $rating, $rating_filter, true ) ? 'wc-layered-nav-rating chosen' : 'wc-layered-nav-rating'; |
123
|
|
|
$link = apply_filters( 'woocommerce_rating_filter_link', $link_ratings ? add_query_arg( 'rating_filter', $link_ratings, $link ) : remove_query_arg( 'rating_filter' ) ); |
124
|
|
|
$rating_html = wc_get_star_rating_html( $rating ); |
125
|
|
|
$count_html = wp_kses( |
126
|
|
|
apply_filters( 'woocommerce_rating_filter_count', "({$count})", $count, $rating ), |
127
|
|
|
array( |
128
|
|
|
'em' => array(), |
129
|
|
|
'span' => array(), |
130
|
|
|
'strong' => array(), |
131
|
|
|
) |
132
|
|
|
); |
133
|
|
|
|
134
|
|
|
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. |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
echo '</ul>'; |
138
|
|
|
|
139
|
|
|
$this->widget_end( $args ); |
140
|
|
|
|
141
|
|
|
if ( ! $found ) { |
142
|
|
|
ob_end_clean(); |
143
|
|
|
} else { |
144
|
|
|
echo ob_get_clean(); // WPCS: XSS ok. |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.