1 <?php
2 3 4 5 6 7 8 9 10
11
12 if ( ! defined( 'ABSPATH' ) ) exit;
13
14 class WC_Widget_Layered_Nav extends WC_Widget {
15
16 17 18
19 public function __construct() {
20 $this->widget_cssclass = 'woocommerce widget_layered_nav';
21 $this->widget_description = __( 'Shows a custom attribute in a widget which lets you narrow down the list of products when viewing product categories.', 'woocommerce' );
22 $this->widget_id = 'woocommerce_layered_nav';
23 $this->widget_name = __( 'WooCommerce Layered Nav', 'woocommerce' );
24
25 parent::__construct();
26 }
27
28 29 30 31 32 33 34 35 36
37 public function update( $new_instance, $old_instance ) {
38 $this->init_settings();
39 return parent::update( $new_instance, $old_instance );
40 }
41
42 43 44 45 46 47 48 49
50 public function form( $instance ) {
51 $this->init_settings();
52 parent::form( $instance );
53 }
54
55 56 57
58 public function init_settings() {
59 $attribute_array = array();
60 $attribute_taxonomies = wc_get_attribute_taxonomies();
61 if ( $attribute_taxonomies )
62 foreach ( $attribute_taxonomies as $tax )
63 if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) )
64 $attribute_array[ $tax->attribute_name ] = $tax->attribute_name;
65
66 $this->settings = array(
67 'title' => array(
68 'type' => 'text',
69 'std' => __( 'Filter by', 'woocommerce' ),
70 'label' => __( 'Title', 'woocommerce' )
71 ),
72 'attribute' => array(
73 'type' => 'select',
74 'std' => '',
75 'label' => __( 'Attribute', 'woocommerce' ),
76 'options' => $attribute_array
77 ),
78 'display_type' => array(
79 'type' => 'select',
80 'std' => 'list',
81 'label' => __( 'Display type', 'woocommerce' ),
82 'options' => array(
83 'list' => __( 'List', 'woocommerce' ),
84 'dropdown' => __( 'Dropdown', 'woocommerce' )
85 )
86 ),
87 'query_type' => array(
88 'type' => 'select',
89 'std' => 'and',
90 'label' => __( 'Query type', 'woocommerce' ),
91 'options' => array(
92 'and' => __( 'AND', 'woocommerce' ),
93 'or' => __( 'OR', 'woocommerce' )
94 )
95 ),
96 );
97 }
98
99 100 101 102 103 104 105 106 107
108 public function widget( $args, $instance ) {
109 global $_chosen_attributes;
110
111 extract( $args );
112
113 if ( ! is_post_type_archive( 'product' ) && ! is_tax( get_object_taxonomies( 'product' ) ) )
114 return;
115
116 $current_term = is_tax() ? get_queried_object()->term_id : '';
117 $current_tax = is_tax() ? get_queried_object()->taxonomy : '';
118 $title = apply_filters('widget_title', $instance['title'], $instance, $this->id_base);
119 $taxonomy = isset( $instance['attribute'] ) ? wc_attribute_taxonomy_name($instance['attribute']) : '';
120 $query_type = isset( $instance['query_type'] ) ? $instance['query_type'] : 'and';
121 $display_type = isset( $instance['display_type'] ) ? $instance['display_type'] : 'list';
122
123 if ( ! taxonomy_exists( $taxonomy ) )
124 return;
125
126 $get_terms_args = array( 'hide_empty' => '1' );
127
128 $orderby = wc_attribute_orderby( $taxonomy );
129
130 switch ( $orderby ) {
131 case 'name' :
132 $get_terms_args['orderby'] = 'name';
133 $get_terms_args['menu_order'] = false;
134 break;
135 case 'id' :
136 $get_terms_args['orderby'] = 'id';
137 $get_terms_args['order'] = 'ASC';
138 $get_terms_args['menu_order'] = false;
139 break;
140 case 'menu_order' :
141 $get_terms_args['menu_order'] = 'ASC';
142 break;
143 }
144
145 $terms = get_terms( $taxonomy, $get_terms_args );
146
147 if ( count( $terms ) > 0 ) {
148
149 ob_start();
150
151 $found = false;
152
153 echo $before_widget . $before_title . $title . $after_title;
154
155
156 if ( ! is_tax() && is_array( $_chosen_attributes ) && array_key_exists( $taxonomy, $_chosen_attributes ) )
157 $found = true;
158
159 if ( $display_type == 'dropdown' ) {
160
161
162 if ( $current_tax && $taxonomy == $current_tax ) {
163
164 $found = false;
165
166 } else {
167
168 $taxonomy_filter = str_replace( 'pa_', '', $taxonomy );
169
170 $found = false;
171
172 echo '<select id="dropdown_layered_nav_' . $taxonomy_filter . '">';
173
174 echo '<option value="">' . sprintf( __( 'Any %s', 'woocommerce' ), wc_attribute_label( $taxonomy ) ) .'</option>';
175
176 foreach ( $terms as $term ) {
177
178
179 if ( $term->term_id == $current_term )
180 continue;
181
182
183 $transient_name = 'wc_ln_count_' . md5( sanitize_key( $taxonomy ) . sanitize_key( $term->term_id ) );
184
185 if ( false === ( $_products_in_term = get_transient( $transient_name ) ) ) {
186
187 $_products_in_term = get_objects_in_term( $term->term_id, $taxonomy );
188
189 set_transient( $transient_name, $_products_in_term, YEAR_IN_SECONDS );
190 }
191
192 $option_is_set = ( isset( $_chosen_attributes[ $taxonomy ] ) && in_array( $term->term_id, $_chosen_attributes[ $taxonomy ]['terms'] ) );
193
194
195 if ( $query_type == 'and' ) {
196
197 $count = sizeof( array_intersect( $_products_in_term, WC()->query->filtered_product_ids ) );
198
199 if ( $count > 0 )
200 $found = true;
201
202 if ( $count == 0 && ! $option_is_set )
203 continue;
204
205
206 } else {
207
208 $count = sizeof( array_intersect( $_products_in_term, WC()->query->unfiltered_product_ids ) );
209
210 if ( $count > 0 )
211 $found = true;
212
213 }
214
215 echo '<option value="' . esc_attr( $term->term_id ) . '" '.selected( isset( $_GET[ 'filter_' . $taxonomy_filter ] ) ? $_GET[ 'filter_' .$taxonomy_filter ] : '' , $term->term_id, false ) . '>' . $term->name . '</option>';
216 }
217
218 echo '</select>';
219
220 wc_enqueue_js("
221
222 jQuery('#dropdown_layered_nav_$taxonomy_filter').change(function(){
223
224 location.href = '" . esc_url_raw( preg_replace( '%\/page/[0-9]+%', '', add_query_arg('filtering', '1', remove_query_arg( array( 'page', 'filter_' . $taxonomy_filter ) ) ) ) ) . "&filter_$taxonomy_filter=' + jQuery('#dropdown_layered_nav_$taxonomy_filter').val();
225
226 });
227
228 ");
229
230 }
231
232 } else {
233
234
235 echo "<ul>";
236
237 foreach ( $terms as $term ) {
238
239
240 $transient_name = 'wc_ln_count_' . md5( sanitize_key( $taxonomy ) . sanitize_key( $term->term_id ) );
241
242 if ( false === ( $_products_in_term = get_transient( $transient_name ) ) ) {
243
244 $_products_in_term = get_objects_in_term( $term->term_id, $taxonomy );
245
246 set_transient( $transient_name, $_products_in_term );
247 }
248
249 $option_is_set = ( isset( $_chosen_attributes[ $taxonomy ] ) && in_array( $term->term_id, $_chosen_attributes[ $taxonomy ]['terms'] ) );
250
251
252 if ( $current_term == $term->term_id )
253 continue;
254
255
256 if ( $query_type == 'and' ) {
257
258 $count = sizeof( array_intersect( $_products_in_term, WC()->query->filtered_product_ids ) );
259
260 if ( $count > 0 && $current_term !== $term->term_id )
261 $found = true;
262
263 if ( $count == 0 && ! $option_is_set )
264 continue;
265
266
267 } else {
268
269 $count = sizeof( array_intersect( $_products_in_term, WC()->query->unfiltered_product_ids ) );
270
271 if ( $count > 0 )
272 $found = true;
273
274 }
275
276 $arg = 'filter_' . sanitize_title( $instance['attribute'] );
277
278 $current_filter = ( isset( $_GET[ $arg ] ) ) ? explode( ',', $_GET[ $arg ] ) : array();
279
280 if ( ! is_array( $current_filter ) )
281 $current_filter = array();
282
283 $current_filter = array_map( 'esc_attr', $current_filter );
284
285 if ( ! in_array( $term->term_id, $current_filter ) )
286 $current_filter[] = $term->term_id;
287
288
289 if ( defined( 'SHOP_IS_ON_FRONT' ) ) {
290 $link = home_url();
291 } elseif ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id('shop') ) ) {
292 $link = get_post_type_archive_link( 'product' );
293 } else {
294 $link = get_term_link( get_query_var('term'), get_query_var('taxonomy') );
295 }
296
297
298 if ( $_chosen_attributes ) {
299 foreach ( $_chosen_attributes as $name => $data ) {
300 if ( $name !== $taxonomy ) {
301
302
303 while ( in_array( $current_term, $data['terms'] ) ) {
304 $key = array_search( $current_term, $data );
305 unset( $data['terms'][$key] );
306 }
307
308
309 $filter_name = sanitize_title( str_replace( 'pa_', '', $name ) );
310
311 if ( ! empty( $data['terms'] ) )
312 $link = add_query_arg( 'filter_' . $filter_name, implode( ',', $data['terms'] ), $link );
313
314 if ( $data['query_type'] == 'or' )
315 $link = add_query_arg( 'query_type_' . $filter_name, 'or', $link );
316 }
317 }
318 }
319
320
321 if ( isset( $_GET['min_price'] ) )
322 $link = add_query_arg( 'min_price', $_GET['min_price'], $link );
323
324 if ( isset( $_GET['max_price'] ) )
325 $link = add_query_arg( 'max_price', $_GET['max_price'], $link );
326
327
328 if ( isset( $_GET['orderby'] ) )
329 $link = add_query_arg( 'orderby', $_GET['orderby'], $link );
330
331
332 if ( isset( $_chosen_attributes[ $taxonomy ] ) && is_array( $_chosen_attributes[ $taxonomy ]['terms'] ) && in_array( $term->term_id, $_chosen_attributes[ $taxonomy ]['terms'] ) ) {
333
334 $class = 'class="chosen"';
335
336
337 if ( sizeof( $current_filter ) > 1 ) {
338 $current_filter_without_this = array_diff( $current_filter, array( $term->term_id ) );
339 $link = add_query_arg( $arg, implode( ',', $current_filter_without_this ), $link );
340 }
341
342 } else {
343
344 $class = '';
345 $link = add_query_arg( $arg, implode( ',', $current_filter ), $link );
346
347 }
348
349
350 if ( get_search_query() )
351 $link = add_query_arg( 's', get_search_query(), $link );
352
353
354 if ( isset( $_GET['post_type'] ) )
355 $link = add_query_arg( 'post_type', $_GET['post_type'], $link );
356
357
358 if ( $query_type == 'or' && ! ( sizeof( $current_filter ) == 1 && isset( $_chosen_attributes[ $taxonomy ]['terms'] ) && is_array( $_chosen_attributes[ $taxonomy ]['terms'] ) && in_array( $term->term_id, $_chosen_attributes[ $taxonomy ]['terms'] ) ) )
359 $link = add_query_arg( 'query_type_' . sanitize_title( $instance['attribute'] ), 'or', $link );
360
361 echo '<li ' . $class . '>';
362
363 echo ( $count > 0 || $option_is_set ) ? '<a href="' . esc_url( apply_filters( 'woocommerce_layered_nav_link', $link ) ) . '">' : '<span>';
364
365 echo $term->name;
366
367 echo ( $count > 0 || $option_is_set ) ? '</a>' : '</span>';
368
369 echo ' <small class="count">' . $count . '</small></li>';
370
371 }
372
373 echo "</ul>";
374
375 }
376
377 echo $after_widget;
378
379 if ( ! $found )
380 ob_end_clean();
381 else
382 echo ob_get_clean();
383 }
384 }
385 }
386
387 register_widget( 'WC_Widget_Layered_Nav' );
388