1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Abstract widget class |
4
|
|
|
* |
5
|
|
|
* @class WC_Widget |
6
|
|
|
* @package WooCommerce/Abstracts |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
10
|
|
|
exit; |
11
|
|
|
} |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* WC_Widget |
15
|
|
|
* |
16
|
|
|
* @package WooCommerce/Abstracts |
17
|
|
|
* @version 2.5.0 |
18
|
|
|
* @extends WP_Widget |
19
|
|
|
*/ |
20
|
|
|
abstract class WC_Widget extends WP_Widget { |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* CSS class. |
24
|
|
|
* |
25
|
|
|
* @var string |
26
|
|
|
*/ |
27
|
|
|
public $widget_cssclass; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Widget description. |
31
|
|
|
* |
32
|
|
|
* @var string |
33
|
|
|
*/ |
34
|
|
|
public $widget_description; |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Widget ID. |
38
|
|
|
* |
39
|
|
|
* @var string |
40
|
|
|
*/ |
41
|
|
|
public $widget_id; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Widget name. |
45
|
|
|
* |
46
|
|
|
* @var string |
47
|
|
|
*/ |
48
|
|
|
public $widget_name; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Settings. |
52
|
|
|
* |
53
|
|
|
* @var array |
54
|
|
|
*/ |
55
|
|
|
public $settings; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Constructor. |
59
|
|
|
*/ |
60
|
3 |
|
public function __construct() { |
61
|
|
|
$widget_ops = array( |
62
|
3 |
|
'classname' => $this->widget_cssclass, |
63
|
3 |
|
'description' => $this->widget_description, |
64
|
|
|
'customize_selective_refresh' => true, |
65
|
|
|
); |
66
|
|
|
|
67
|
3 |
|
parent::__construct( $this->widget_id, $this->widget_name, $widget_ops ); |
68
|
|
|
|
69
|
3 |
|
add_action( 'save_post', array( $this, 'flush_widget_cache' ) ); |
70
|
3 |
|
add_action( 'deleted_post', array( $this, 'flush_widget_cache' ) ); |
71
|
3 |
|
add_action( 'switch_theme', array( $this, 'flush_widget_cache' ) ); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Get cached widget. |
76
|
|
|
* |
77
|
|
|
* @param array $args Arguments. |
78
|
|
|
* @return bool true if the widget is cached otherwise false |
79
|
|
|
*/ |
80
|
1 |
|
public function get_cached_widget( $args ) { |
81
|
1 |
|
$cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' ); |
82
|
|
|
|
83
|
1 |
|
if ( ! is_array( $cache ) ) { |
84
|
1 |
|
$cache = array(); |
85
|
|
|
} |
86
|
|
|
|
87
|
1 |
|
if ( isset( $cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ] ) ) { |
88
|
1 |
|
echo $cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ]; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped |
89
|
1 |
|
return true; |
90
|
|
|
} |
91
|
|
|
|
92
|
1 |
|
return false; |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Cache the widget. |
97
|
|
|
* |
98
|
|
|
* @param array $args Arguments. |
99
|
|
|
* @param string $content Content. |
100
|
|
|
* @return string the content that was cached |
101
|
|
|
*/ |
102
|
1 |
|
public function cache_widget( $args, $content ) { |
103
|
1 |
|
$cache = wp_cache_get( $this->get_widget_id_for_cache( $this->widget_id ), 'widget' ); |
104
|
|
|
|
105
|
1 |
|
if ( ! is_array( $cache ) ) { |
106
|
1 |
|
$cache = array(); |
107
|
|
|
} |
108
|
|
|
|
109
|
1 |
|
$cache[ $this->get_widget_id_for_cache( $args['widget_id'] ) ] = $content; |
110
|
|
|
|
111
|
1 |
|
wp_cache_set( $this->get_widget_id_for_cache( $this->widget_id ), $cache, 'widget' ); |
112
|
|
|
|
113
|
1 |
|
return $content; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Flush the cache. |
118
|
|
|
*/ |
119
|
485 |
|
public function flush_widget_cache() { |
120
|
485 |
|
foreach ( array( 'https', 'http' ) as $scheme ) { |
121
|
485 |
|
wp_cache_delete( $this->get_widget_id_for_cache( $this->widget_id, $scheme ), 'widget' ); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Get this widgets title. |
127
|
|
|
* |
128
|
|
|
* @param array $instance Array of instance options. |
129
|
|
|
* @return string |
130
|
|
|
*/ |
131
|
|
|
protected function get_instance_title( $instance ) { |
132
|
|
|
if ( isset( $instance['title'] ) ) { |
133
|
|
|
return $instance['title']; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
if ( isset( $this->settings, $this->settings['title'], $this->settings['title']['std'] ) ) { |
137
|
|
|
return $this->settings['title']['std']; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return ''; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Output the html at the start of a widget. |
145
|
|
|
* |
146
|
|
|
* @param array $args Arguments. |
147
|
|
|
* @param array $instance Instance. |
148
|
|
|
*/ |
149
|
|
|
public function widget_start( $args, $instance ) { |
150
|
|
|
echo $args['before_widget']; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped |
151
|
|
|
|
152
|
|
|
$title = apply_filters( 'widget_title', $this->get_instance_title( $instance ), $instance, $this->id_base ); |
153
|
|
|
|
154
|
|
|
if ( $title ) { |
155
|
|
|
echo $args['before_title'] . $title . $args['after_title']; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped |
156
|
|
|
} |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Output the html at the end of a widget. |
161
|
|
|
* |
162
|
|
|
* @param array $args Arguments. |
163
|
|
|
*/ |
164
|
|
|
public function widget_end( $args ) { |
165
|
|
|
echo $args['after_widget']; // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* Updates a particular instance of a widget. |
170
|
|
|
* |
171
|
|
|
* @see WP_Widget->update |
172
|
|
|
* @param array $new_instance New instance. |
173
|
|
|
* @param array $old_instance Old instance. |
174
|
|
|
* @return array |
175
|
|
|
*/ |
176
|
|
|
public function update( $new_instance, $old_instance ) { |
177
|
|
|
|
178
|
|
|
$instance = $old_instance; |
179
|
|
|
|
180
|
|
|
if ( empty( $this->settings ) ) { |
181
|
|
|
return $instance; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
// Loop settings and get values to save. |
185
|
|
|
foreach ( $this->settings as $key => $setting ) { |
186
|
|
|
if ( ! isset( $setting['type'] ) ) { |
187
|
|
|
continue; |
188
|
|
|
} |
189
|
|
|
|
190
|
|
|
// Format the value based on settings type. |
191
|
|
|
switch ( $setting['type'] ) { |
192
|
|
|
case 'number': |
193
|
|
|
$instance[ $key ] = absint( $new_instance[ $key ] ); |
194
|
|
|
|
195
|
|
View Code Duplication |
if ( isset( $setting['min'] ) && '' !== $setting['min'] ) { |
196
|
|
|
$instance[ $key ] = max( $instance[ $key ], $setting['min'] ); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
View Code Duplication |
if ( isset( $setting['max'] ) && '' !== $setting['max'] ) { |
200
|
|
|
$instance[ $key ] = min( $instance[ $key ], $setting['max'] ); |
201
|
|
|
} |
202
|
|
|
break; |
203
|
|
|
case 'textarea': |
204
|
|
|
$instance[ $key ] = wp_kses( trim( wp_unslash( $new_instance[ $key ] ) ), wp_kses_allowed_html( 'post' ) ); |
205
|
|
|
break; |
206
|
|
|
case 'checkbox': |
207
|
|
|
$instance[ $key ] = empty( $new_instance[ $key ] ) ? 0 : 1; |
208
|
|
|
break; |
209
|
|
|
default: |
210
|
|
|
$instance[ $key ] = isset( $new_instance[ $key ] ) ? sanitize_text_field( $new_instance[ $key ] ) : $setting['std']; |
211
|
|
|
break; |
212
|
1 |
|
} |
213
|
|
|
|
214
|
1 |
|
/** |
215
|
1 |
|
* Sanitize the value of a setting. |
216
|
|
|
*/ |
217
|
|
|
$instance[ $key ] = apply_filters( 'woocommerce_widget_settings_sanitize_option', $instance[ $key ], $new_instance, $key, $setting ); |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
$this->flush_widget_cache(); |
221
|
|
|
|
222
|
|
|
return $instance; |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* Outputs the settings update form. |
227
|
|
|
* |
228
|
|
|
* @see WP_Widget->form |
229
|
|
|
* |
230
|
|
|
* @param array $instance Instance. |
231
|
|
|
*/ |
232
|
|
|
public function form( $instance ) { |
233
|
|
|
|
234
|
|
|
if ( empty( $this->settings ) ) { |
235
|
|
|
return; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
foreach ( $this->settings as $key => $setting ) { |
239
|
|
|
|
240
|
|
|
$class = isset( $setting['class'] ) ? $setting['class'] : ''; |
241
|
|
|
$value = isset( $instance[ $key ] ) ? $instance[ $key ] : $setting['std']; |
242
|
|
|
|
243
|
|
|
switch ( $setting['type'] ) { |
244
|
|
|
|
245
|
|
View Code Duplication |
case 'text': |
246
|
|
|
?> |
247
|
|
|
<p> |
248
|
|
|
<label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo wp_kses_post( $setting['label'] ); ?></label><?php // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?> |
249
|
|
|
<input class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="text" value="<?php echo esc_attr( $value ); ?>" /> |
250
|
|
|
</p> |
251
|
|
|
<?php |
252
|
|
|
break; |
253
|
|
|
|
254
|
|
|
case 'number': |
255
|
|
|
?> |
256
|
|
|
<p> |
257
|
|
|
<label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label> |
258
|
|
|
<input class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="number" step="<?php echo esc_attr( $setting['step'] ); ?>" min="<?php echo esc_attr( $setting['min'] ); ?>" max="<?php echo esc_attr( $setting['max'] ); ?>" value="<?php echo esc_attr( $value ); ?>" /> |
259
|
|
|
</p> |
260
|
|
|
<?php |
261
|
|
|
break; |
262
|
|
|
|
263
|
|
|
case 'select': |
264
|
|
|
?> |
265
|
|
|
<p> |
266
|
|
|
<label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label> |
267
|
|
|
<select class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>"> |
268
|
|
View Code Duplication |
<?php foreach ( $setting['options'] as $option_key => $option_value ) : ?> |
269
|
|
|
<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( $option_key, $value ); ?>><?php echo esc_html( $option_value ); ?></option> |
270
|
|
|
<?php endforeach; ?> |
271
|
|
|
</select> |
272
|
|
|
</p> |
273
|
|
|
<?php |
274
|
|
|
break; |
275
|
|
|
|
276
|
|
|
case 'textarea': |
277
|
|
|
?> |
278
|
|
|
<p> |
279
|
|
|
<label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label> |
280
|
|
|
<textarea class="widefat <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" cols="20" rows="3"><?php echo esc_textarea( $value ); ?></textarea> |
281
|
|
|
<?php if ( isset( $setting['desc'] ) ) : ?> |
282
|
|
|
<small><?php echo esc_html( $setting['desc'] ); ?></small> |
283
|
|
|
<?php endif; ?> |
284
|
|
|
</p> |
285
|
|
|
<?php |
286
|
|
|
break; |
287
|
|
|
|
288
|
|
View Code Duplication |
case 'checkbox': |
289
|
|
|
?> |
290
|
|
|
<p> |
291
|
|
|
<input class="checkbox <?php echo esc_attr( $class ); ?>" id="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( $key ) ); ?>" type="checkbox" value="1" <?php checked( $value, 1 ); ?> /> |
292
|
|
|
<label for="<?php echo esc_attr( $this->get_field_id( $key ) ); ?>"><?php echo $setting['label']; /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></label> |
293
|
|
|
</p> |
294
|
|
|
<?php |
295
|
|
|
break; |
296
|
|
|
|
297
|
|
|
// Default: run an action. |
298
|
|
|
default: |
299
|
|
|
do_action( 'woocommerce_widget_field_' . $setting['type'], $key, $value, $setting, $instance ); |
300
|
|
|
break; |
301
|
|
|
} |
302
|
|
|
} |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
/** |
306
|
|
|
* Get current page URL with various filtering props supported by WC. |
307
|
|
|
* |
308
|
|
|
* @return string |
309
|
|
|
* @since 3.3.0 |
310
|
|
|
*/ |
311
|
|
|
protected function get_current_page_url() { |
312
|
|
|
if ( defined( 'SHOP_IS_ON_FRONT' ) ) { |
313
|
|
|
$link = home_url(); |
314
|
|
|
} elseif ( is_shop() ) { |
315
|
|
|
$link = get_permalink( wc_get_page_id( 'shop' ) ); |
316
|
|
|
} elseif ( is_product_category() ) { |
317
|
|
|
$link = get_term_link( get_query_var( 'product_cat' ), 'product_cat' ); |
318
|
|
|
} elseif ( is_product_tag() ) { |
319
|
|
|
$link = get_term_link( get_query_var( 'product_tag' ), 'product_tag' ); |
320
|
|
|
} else { |
321
|
|
|
$queried_object = get_queried_object(); |
322
|
|
|
$link = get_term_link( $queried_object->slug, $queried_object->taxonomy ); |
323
|
|
|
} |
324
|
|
|
|
325
|
|
|
// Min/Max. |
326
|
|
View Code Duplication |
if ( isset( $_GET['min_price'] ) ) { |
327
|
|
|
$link = add_query_arg( 'min_price', wc_clean( wp_unslash( $_GET['min_price'] ) ), $link ); |
|
|
|
|
328
|
|
|
} |
329
|
|
|
|
330
|
|
View Code Duplication |
if ( isset( $_GET['max_price'] ) ) { |
331
|
|
|
$link = add_query_arg( 'max_price', wc_clean( wp_unslash( $_GET['max_price'] ) ), $link ); |
|
|
|
|
332
|
|
|
} |
333
|
|
|
|
334
|
|
|
// Order by. |
335
|
|
View Code Duplication |
if ( isset( $_GET['orderby'] ) ) { |
336
|
|
|
$link = add_query_arg( 'orderby', wc_clean( wp_unslash( $_GET['orderby'] ) ), $link ); |
|
|
|
|
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
/** |
340
|
|
|
* Search Arg. |
341
|
|
|
* To support quote characters, first they are decoded from " entities, then URL encoded. |
342
|
|
|
*/ |
343
|
|
|
if ( get_search_query() ) { |
344
|
|
|
$link = add_query_arg( 's', rawurlencode( htmlspecialchars_decode( get_search_query() ) ), $link ); |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
// Post Type Arg. |
348
|
|
View Code Duplication |
if ( isset( $_GET['post_type'] ) ) { |
349
|
|
|
$link = add_query_arg( 'post_type', wc_clean( wp_unslash( $_GET['post_type'] ) ), $link ); |
|
|
|
|
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
// Min Rating Arg. |
353
|
|
View Code Duplication |
if ( isset( $_GET['rating_filter'] ) ) { |
354
|
|
|
$link = add_query_arg( 'rating_filter', wc_clean( wp_unslash( $_GET['rating_filter'] ) ), $link ); |
|
|
|
|
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
// All current filters. |
358
|
|
|
if ( $_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes() ) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found, WordPress.CodeAnalysis.AssignmentInCondition.Found |
359
|
|
|
foreach ( $_chosen_attributes as $name => $data ) { |
360
|
|
|
$filter_name = wc_attribute_taxonomy_slug( $name ); |
361
|
486 |
|
if ( ! empty( $data['terms'] ) ) { |
362
|
486 |
|
$link = add_query_arg( 'filter_' . $filter_name, implode( ',', $data['terms'] ), $link ); |
363
|
485 |
|
} |
364
|
|
|
if ( 'or' === $data['query_type'] ) { |
365
|
1 |
|
$link = add_query_arg( 'query_type_' . $filter_name, 'or', $link ); |
366
|
|
|
} |
367
|
|
|
} |
368
|
486 |
|
} |
369
|
|
|
|
370
|
|
|
return apply_filters( 'woocommerce_widget_get_current_page_url', $link, $this ); |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
/** |
374
|
|
|
* Get widget id plus scheme/protocol to prevent serving mixed content from (persistently) cached widgets. |
375
|
|
|
* |
376
|
|
|
* @since 3.4.0 |
377
|
|
|
* @param string $widget_id Id of the cached widget. |
378
|
|
|
* @param string $scheme Scheme for the widget id. |
379
|
|
|
* @return string Widget id including scheme/protocol. |
380
|
|
|
*/ |
381
|
|
|
protected function get_widget_id_for_cache( $widget_id, $scheme = '' ) { |
382
|
|
|
if ( $scheme ) { |
383
|
|
|
$widget_id_for_cache = $widget_id . '-' . $scheme; |
384
|
|
|
} else { |
385
|
|
|
$widget_id_for_cache = $widget_id . '-' . ( is_ssl() ? 'https' : 'http' ); |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
return apply_filters( 'woocommerce_cached_widget_id', $widget_id_for_cache ); |
389
|
|
|
} |
390
|
|
|
} |
391
|
|
|
|