PluginProbe
Filter Everything — WordPress & WooCommerce Filters / 1.6.1
Filter Everything — WordPress & WooCommerce Filters v1.6.1
1.9.7 1.9.6 1.9.5 1.9.4 1.9.3 1.9.2.2 1.9.2.1 trunk 1.2.1 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.4.1 1.4.4 1.4.5 1.4.8 1.4.9 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 All 52 releases
filter-everything / src / Admin / Widgets / FiltersWidget.php

FiltersWidget.php in Filter Everything — WordPress & WooCommerce Filters 1.6.1, at src/Admin/Widgets/FiltersWidget.php

510 lines 21.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FilterEverything\Filter;
4
5 if ( ! defined('WPINC') ) {
6 wp_die();
7 }
8
9 class FiltersWidget extends \WP_Widget
10 {
11 public $show_instance_in_rest = false;
12
13 public function __construct() {
14 parent::__construct(
15 'wpc_filters_widget', // Base ID
16 esc_html__( 'Filter Everything &mdash; Filters', 'filter-everything'),
17 array(
18 'description' => esc_html__( 'Filters Widget', 'filter-everything' ),
19 'show_instance_in_rest' => false,
20 )
21 );
22 }
23
24 /**
25 * Front-end display of widget.
26 *
27 * @see WP_Widget::widget()
28 *
29 * @param array $args Widget arguments.
30 * @param array $instance Saved values from database.
31 */
32 public function widget( $args, $instance ) {
33 extract( $args );
34
35 $title = isset( $instance['title'] ) ? apply_filters( 'widget_title', $instance['title'] ) : '';
36 $show_selected_class = ( !empty( $instance['chips'] ) ) ? ' wpc-show-on-desktop' : '';
37 $show_count = ( !empty( $instance['show_count'] ) ) ? $instance['show_count'] : '';
38 $set_id = isset( $instance['id'] ) ? preg_replace('/[^\d]?/', '', $instance['id'] ) : 0;
39 $popup_title = esc_html__('Filters', 'filter-everything');
40 if( ! empty( $title ) ){
41 $popup_title = $title;
42 }
43
44 // Display nothing if preview mode
45 if( isset( $_GET['legacy-widget-preview'] ) || isset( $_GET['_locale'] ) ){
46 return;
47 }
48
49 if( isset( $_POST['action'] ) && $_POST['action'] === 'elementor_ajax' ){
50 echo '<strong>'.esc_html__( 'Filter Everything &mdash; Filters', 'filter-everything' ).'</strong>';
51 return;
52 }
53
54 if( isset( $_GET['action'] ) && $_GET['action'] === 'elementor' ){
55 echo '<strong>'.esc_html__( 'Filter Everything &mdash; Filters', 'filter-everything' ).'</strong>';
56 return;
57 }
58
59 do_action( 'wpc_before_filters_widget', $args, $instance );
60
61 /**
62 * @feature Add ability to choose what filter Set to display in widget settings
63 */
64 $debug_mode = flrt_is_debug_mode();
65 $container = Container::instance();
66 $wpManager = $container->getWpManager();
67
68 if( ! $wpManager->getQueryVar( 'allowed_filter_page' ) ){
69 if( $debug_mode ){
70
71 if( defined('FLRT_FILTERS_PRO') ){
72 echo '<p class="wpc-debug-message">';
73 echo sprintf(
74 wp_kses(
75 __( 'No one Filter Set is related with this page. You can configure it in the <a href="%s">Filter Set</a> Where to filter? field.', 'filter-everything' ),
76 array( 'a' => array('href' => true) )
77 ),
78 admin_url( 'edit.php?post_type=filter-set' )
79 );
80 echo '</p>';
81 }else{
82 if( is_singular() ){
83 echo '<p class="wpc-debug-message">';
84 echo sprintf(
85 wp_kses(
86 __( 'The free version of the plugin does not support filtering on singular pages. But <a href="%s">PRO version</a> supports.', 'filter-everything' ),
87 array( 'a' => array('href' => true) )
88 ),
89 esc_url(FLRT_PLUGIN_LINK .'/?get_pro=true')
90 );
91 echo '</p>';
92 }else{
93 echo '<p class="wpc-debug-message">';
94 echo sprintf(
95 wp_kses(
96 __( 'No one Filter Set is configured for this post type pages. You can create a new <a href="%s">Filter Set</a> for them.', 'filter-everything' ),
97 array( 'a' => array('href' => true) )
98 ),
99 admin_url( 'edit.php?post_type=filter-set' )
100 );
101 echo '</p>';
102 }
103 }
104
105 flrt_debug_title();
106 }
107 return false;
108 }
109
110 $templateManager = $container->getTemplateManager();
111 $em = $container->getEntityManager();
112 $fss = $container->getFilterSetService();
113 $urlManager = new UrlManager();
114
115 $has_not_empty_children = [];
116 $theSet = flrt_the_set( $set_id );
117
118 // Display or not Filter Set in dependency from the Apply button configuration
119 if( isset( $theSet['show_on_the_page'] ) && ! $theSet['show_on_the_page'] ){
120 $theSet = flrt_the_set( $set_id );
121 }
122
123 if( ! $theSet ){
124 return false;
125 }
126
127 $setId = $theSet['ID'];
128 $posType = $theSet['filtered_post_type'];
129 $set = $fss->getSet( $theSet['ID'] );
130
131 $chipsObj = new Chips(true, array($setId) );
132 $chips = $chipsObj->getChips();
133
134 $set_edit_url = ( isset( $theSet['ID'] )) ? admin_url('post.php?post='.$theSet['ID'].'&action=edit') : admin_url( 'edit.php?post_type=filter-set' );
135
136 $related_filters = $em->getSetsRelatedFilters( array( $theSet ) );
137 $found_posts = flrt_posts_found_quantity( $setId, true );
138 $actionUrl = $urlManager->getFormActionUrl(true);
139 $view_args = [ 'ask_to_select_parent' => false ];
140
141 // Apply button preparations
142 $filters_counter = 0;
143 $use_apply_button = ( isset( $set['use_apply_button']['value'] ) && $set['use_apply_button']['value'] === 'yes' );
144 $apply_button_menu_order = isset( $set['apply_button_menu_order']['value'] ) ? (int) $set['apply_button_menu_order']['value'] : -1;
145 $apply_button_displayed = false;
146 $has_not_empty_children_flipped = [];
147
148 if( $use_apply_button ){
149
150 $base_permalink = '';
151
152 if( defined('FLRT_FILTERS_PRO') && FLRT_FILTERS_PRO ){
153
154 $wp_page_type = '';
155 $post_type = isset( $set['post_type']['value'] ) ? $set['post_type']['value'] : 'post';
156 $location = isset( $set['post_name']['value'] ) ? $set['post_name']['value'] : '';
157
158 if( isset( $set['wp_page_type']['value'] ) ){
159 $wp_page_type = $set['wp_page_type']['value'];
160 }
161
162 $base_permalink = flrt_get_location_permalink( $location, $wp_page_type, $post_type );
163 }
164
165 $queried_filters = $wpManager->getQueryVar('queried_values', []);
166 $apply_url = $urlManager->getFiltersUrl( $queried_filters, $base_permalink );
167 $reset_url = $urlManager->getResetUrl();
168 }
169
170 do_action( 'wpc_before_display_filters_widget', $setId, $args, $instance );
171
172 if( empty( $related_filters ) ){
173 if( $debug_mode ){
174
175 echo '<p class="wpc-debug-message">';
176 echo sprintf(
177 wp_kses(
178 __( 'There are no filters in the Filter Set yet. Please add them to the <a href="%s">Filter Set</a> related to this page.', 'filter-everything' ),
179 array( 'a' => array('href' => true) )
180 ),
181 $set_edit_url
182 );
183 echo '</p>';
184
185 flrt_debug_title();
186 }
187 return false;
188 }
189
190 echo $before_widget;
191 echo '<div class="wpc-filters-widget-main-wrapper wpc-filter-set-'.esc_attr( $setId ).'" data-set="'.esc_attr( $setId ).'">'."\n";
192 // Open/Closed status class
193 $widgetContentClass = flrt_filters_widget_content_class($setId);
194
195 if( flrt_get_experimental_option('disable_buttons') !== 'on' ) {
196 flrt_filters_button($setId, $widgetContentClass);
197 }
198
199 if( $use_apply_button ){
200 $widgetContentClass .= ( $theSet['query_on_the_page'] ) ? ' wpc-query-on-the-page' : ' wpc-query-not-on-the-page';
201 }
202
203 echo flrt_spinner_html();
204
205 echo '<div class="wpc-filters-widget-content'.esc_attr($widgetContentClass).'">';
206 echo '<div class="wpc-widget-close-container">
207 <a class="wpc-widget-close-icon">
208 <span class="wpc-icon-html-wrapper">
209 <span class="wpc-icon-line-1"></span><span class="wpc-icon-line-2"></span><span class="wpc-icon-line-3"></span>
210 </span>
211 </a>';
212
213 echo '<span class="wpc-widget-popup-title">'.$popup_title.'</span>';
214 echo '</div>';
215 echo '<div class="wpc-filters-widget-containers-wrapper">'."\r\n";
216
217 do_action( 'wpc_before_mobile_filters_widget', $setId, $args, $instance );
218
219 echo '<div class="wpc-filters-widget-top-container'.esc_attr($show_selected_class).'">';
220 echo '<div class="wpc-widget-top-inside">';
221
222 // Add selected terms for mobile widget
223 echo '<div class="wpc-inner-widget-chips-wrapper">';
224 $templateManager->includeFrontView( 'chips', array( 'chips' => $chips, 'setid' => $setId ) );
225 echo '</div>';
226
227 echo '</div>';
228 echo '</div>';
229
230 if ( ! empty( $title ) ) {
231 echo '<div class="wpc-filter-set-widget-title">'."\n";
232 echo $before_title . $title . $after_title;
233 echo '</div>'."\n";
234 }
235
236 echo '<div class="wpc-filters-scroll-container">';
237 echo '<div class="wpc-filters-widget-wrapper">'."\r\n";
238
239 if( $show_count ){
240 flrt_posts_found( $setId );
241 }
242
243 foreach ( $related_filters as $filter_id => $filter ){
244 $filters_counter++;
245
246 $terms = flrt_get_filter_terms( $filter, $posType, $em );
247
248 // Collect terms for a parent filter, if exists
249 if( $filter['parent_filter'] > 0 ){
250 // Here we have to calculate all related with the parent filter
251 $parent_filter_id = (int) $filter['parent_filter'];
252 if( isset( $related_filters[ $parent_filter_id ] ) ){
253 $parent_filter = $related_filters[ $parent_filter_id ];
254
255 if( empty( $parent_filter['values'] ) ){
256
257 // Do not show this filter, until parent is selected
258 if( $filter['hide_until_parent'] === 'yes' && empty( $filter['values'] ) ){
259 continue;
260 }
261
262 if( ! empty( $filter['values'] ) ){
263 $actual_filter_terms = [];
264 $filter_values_flipped = array_flip($filter['values']);
265 foreach( $terms as $single_term ){
266 if( isset( $filter_values_flipped[ $single_term->slug ] ) ){
267 $actual_filter_terms[] = $single_term;
268 }
269 }
270 $terms = $actual_filter_terms;
271 }else{
272 $view_args['ask_to_select_parent'] = sprintf( esc_html__('Select %s first', 'filter-everything' ), $parent_filter['label'] );
273 }
274
275
276 // Here we have to setup signal that forces message "Select parent first"
277 }else{
278 if( $filter['entity'] !== 'post_meta_num' ){
279 // Selected values are term slugs
280 $parent_filter_terms = flrt_get_filter_terms( $parent_filter, $posType, $em );
281
282 $actual_parent_filter_posts = [];
283 $parent_filter_values_flipped = array_flip($parent_filter['values']);
284 foreach( $parent_filter_terms as $parent_filter_term ){
285 if( isset( $parent_filter_values_flipped[ $parent_filter_term->slug ] ) ){
286 $actual_parent_filter_posts = array_merge( $actual_parent_filter_posts, $parent_filter_term->posts );
287 }
288 }
289
290 $actual_filter_terms = [];
291 // if ! empty( $filter['values'] )
292 foreach( $terms as $single_term ){
293 $current_intersection = array_intersect( $actual_parent_filter_posts, $single_term->posts );
294 if( ! empty( $current_intersection ) ){
295 $actual_filter_terms[] = $single_term;
296 }
297 }
298
299 $terms = $actual_filter_terms;
300 }
301 }
302
303 }
304 }else{
305 $view_args[ 'ask_to_select_parent'] = false;
306 }
307
308 if( $filter['hierarchy'] === 'yes' ){
309 $hierarchy_key = 'cross_count';
310 if( $set['hide_empty']['value'] === 'initial' ){
311 $hierarchy_key = 'count';
312 }
313 $has_not_empty_children = flrt_get_parents_with_not_empty_children( $terms, $hierarchy_key );
314 $has_not_empty_children_flipped = array_flip( $has_not_empty_children );
315 }
316
317 // Create a list with excluded empty terms
318 if( ( $set['hide_empty']['value'] === 'yes' ) || ( $set['hide_empty']['value'] === 'initial' ) || ( isset( $set['hide_empty_filter'] ) && $set['hide_empty_filter']['value'] === 'yes' ) ){
319 $allWpQueriedPostIds = $em->getAllSetWpQueriedPostIds( $setId );
320 $allWpQueriedPostIds_flipped = array_flip($allWpQueriedPostIds);
321 $checkTerms = $terms;
322
323 if( $set['hide_empty']['value'] === 'initial' ){
324 foreach ($checkTerms as $index => $term) {
325 if( $filter['hierarchy'] === 'yes' ){
326
327 $intersection = false;
328 foreach( $term->posts as $post_id ){
329 if( isset( $allWpQueriedPostIds_flipped[$post_id] ) ){
330 $intersection = true;
331 break;
332 }
333 }
334
335 if( ! $intersection && ! isset( $has_not_empty_children_flipped[$term->term_id] ) ){
336 unset($checkTerms[$index]);
337 }
338
339 }else{
340
341 $intersection = false;
342 foreach( $term->posts as $post_id ){
343 if( isset( $allWpQueriedPostIds_flipped[$post_id] ) ){
344 $intersection = true;
345 break;
346 }
347 }
348
349 if( ! $intersection ){
350 unset($checkTerms[$index]);
351 }
352 }
353 }
354 }else{
355 $checkTerms = flrt_remove_empty_terms( $terms, $filter, $has_not_empty_children_flipped );
356 }
357 }
358
359 // Remove empty terms, if such option is enabled
360 if( ( $set['hide_empty']['value'] === 'yes' || $set['hide_empty']['value'] === 'initial' ) && ($filter['entity'] !== 'post_meta_num') ) {
361 $terms = $checkTerms;
362 }
363
364 // Hide entire Filter if there are no posts in its terms
365 if( isset( $set['hide_empty_filter'] )
366 &&
367 $set['hide_empty_filter']['value'] === 'yes' ){
368
369 if( $filter['entity'] === 'post_meta_num' ){
370 // Temporary not ideal solution
371 if( (int) $terms[0]->max === 0 && (int) $terms[1]->min === 0 ){
372 // Huh, finally
373 continue;
374 }
375 }else{
376 $checkTerms = flrt_remove_empty_terms( $terms, $filter, $has_not_empty_children_flipped );
377 if( empty( $checkTerms ) ){
378 // Huh, finally
379 continue;
380 }
381 }
382 }
383
384 $terms = flrt_extract_objects_vars( $terms, array(
385 'term_id',
386 'slug',
387 'name',
388 'count',
389 'cross_count',
390 'max',
391 'min',
392 'absMax',
393 'absMin',
394 'parent',
395 'wp_queried'
396 )
397 );
398
399 // Hook terms before display to allow developers modify them.
400 $terms = apply_filters( 'wpc_terms_before_display', $terms, $filter, $set, $urlManager );
401
402 // Show Apply button if configured
403 if( $use_apply_button && $apply_button_menu_order === $filters_counter ){
404 $templateManager->includeFrontView( 'apply-button', array( 'set' => $set, 'apply_url' => $apply_url, 'reset_url' => $reset_url ) );
405 $apply_button_displayed = true;
406 }
407
408 $templateManager->includeFrontView(
409 apply_filters( 'wpc_view_include_filename', $filter['view'], $filter, $set ),
410 array(
411 'filter' => $filter,
412 'terms' => $terms,
413 'set' => $set,
414 'url_manager' => $urlManager,
415 'view_args' => $view_args
416 )
417 );
418
419 }
420
421 // Show Apply button in the end
422 $filters_counter++;
423 if( ! $apply_button_displayed && $use_apply_button && $apply_button_menu_order === $filters_counter ){
424 $templateManager->includeFrontView( 'apply-button', array( 'set' => $set, 'apply_url' => $apply_url, 'reset_url' => $reset_url ) );
425 }
426
427 echo '</div>'."\r\n";
428
429 echo '</div>' . "\r\n";
430
431 echo '<div class="wpc-filters-widget-controls-container">
432 <div class="wpc-filters-widget-controls-wrapper">';
433
434 $templateManager->includeFrontView( 'bottom-controls', array( 'action_url' => $actionUrl, 'found_posts' => $found_posts ) );
435
436 echo '
437 </div>';
438
439 if( $use_apply_button ){
440 $templateManager->includeFrontView( 'apply-button', array( 'set' => $set, 'apply_url' => $apply_url, 'reset_url' => $reset_url ) );
441 }
442
443 echo '</div>';
444
445 if( current_user_can( 'manage_options' ) ){
446 echo '<div class="wpc-edit-filter-set">';
447 echo sprintf(
448 wp_kses(
449 __( '<a href="%s">Edit</a> Filter Set', 'filter-everything' ),
450 array( 'a' => array('href' => true) )
451 ),
452 $set_edit_url
453 );
454 echo '</div>';
455 }
456
457 do_action( 'wpc_after_mobile_filters_widget', $setId, $args, $instance );
458
459 echo '</div>' . "\r\n";
460 echo '</div>' . "\r\n"; // end .wpc-filters-widget-content
461
462 // Show button, that opens bottom filters container
463 $wpc_mobile_width = flrt_get_mobile_width();
464 echo '<style type="text/css">
465 @media screen and (max-width: '.$wpc_mobile_width.'px) {
466 .wpc_show_bottom_widget .wpc-filters-widget-controls-container,
467 .wpc_show_bottom_widget .wpc-filters-widget-top-container,
468 .wpc_show_open_close_button .wpc-filters-open-button-container,
469 .wpc_show_bottom_widget .wpc-filters-open-button-container{
470 display: block;
471 }
472 }
473 </style>'."\r\n";
474 echo '</div>'."\n"; // <!-- wpc-filters-widget-main-wrapper -->
475 echo $after_widget;
476
477 do_action( 'wpc_after_filters_widget', $args, $instance );
478 }
479
480 public function form( $instance ) {
481
482 $title = isset( $instance[ 'title' ] ) ? $instance[ 'title' ] : '';
483 $chips = isset( $instance['chips'] ) ? (bool) $instance['chips'] : false;
484 $show_count = isset( $instance['show_count'] ) ? (bool) $instance['show_count'] : true;
485
486 ?>
487 <p>
488 <label for="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"><?php esc_html_e( 'Title:' ); ?></label>
489 <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
490 </p>
491 <p>
492 <input type="checkbox" class="checkbox" id="<?php echo esc_attr( $this->get_field_id( 'chips' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'chips' ) ); ?>"<?php checked( $chips ); ?> />
493 <label for="<?php echo esc_attr( $this->get_field_id( 'chips' ) ); ?>"><?php esc_html_e( 'Show selected terms (Chips)', 'filter-everything' ); ?></label>
494 </p>
495 <p>
496 <input type="checkbox" class="checkbox" id="<?php echo esc_attr( $this->get_field_id( 'show_count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'show_count' ) ); ?>"<?php checked( $show_count ); ?> />
497 <label for="<?php echo esc_attr( $this->get_field_id( 'show_count' ) ); ?>"><?php esc_html_e( 'Show number of posts found', 'filter-everything' ); ?></label>
498 </p>
499 <?php
500 }
501
502 public function update( $new_instance, $old_instance ) {
503 $instance = [];
504 $instance['title'] = ( !empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
505 $instance['chips'] = ( !empty( $new_instance['chips'] ) ) ? 1 : 0;
506 $instance['show_count'] = ( !empty( $new_instance['show_count'] ) ) ? 1 : 0;
507
508 return $instance;
509 }
510 }