PluginProbe
Filter Everything — WordPress & WooCommerce Filters / 1.9.7
Filter Everything — WordPress & WooCommerce Filters v1.9.7
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 / wpc-third-party.php

wpc-third-party.php in Filter Everything — WordPress & WooCommerce Filters 1.9.7, at src/wpc-third-party.php

1,382 lines 67.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined('ABSPATH') ) {
4 exit;
5 }
6
7 function flrt_is_woocommerce()
8 {
9 if( class_exists('WooCommerce') ){
10 return true;
11 }
12 return false;
13 }
14
15 function flrt_is_acf()
16 {
17 if( class_exists( 'ACF' ) ){
18 return true;
19 }
20 return false;
21 }
22
23 function flrt_get_mobile_width(){
24 return apply_filters( 'wpc_mobile_width', 768 );
25 }
26
27 /**
28 * @feature for other popular themes there is possibility to add action to hook get_template_part_{$slug}
29 * But it seems we need to detect what current theme is enabled
30 */
31 if( ! function_exists('flrt_wp') ){
32
33 function flrt_wp(){
34 $theme_dependencies = flrt_get_theme_dependencies();
35
36 if( flrt_get_option('mobile_filter_settings') === 'show_bottom_widget' ){
37
38 if( flrt_get_experimental_option('disable_buttons') !== 'on' ) {
39
40 if (flrt_is_woocommerce()) { // It means WooCommerce installed
41
42 if( is_woocommerce() ){ // It means is a WooCommerce page
43 add_action('woocommerce_before_shop_loop', 'flrt_filters_button', 5);
44 add_action('woocommerce_no_products_found', 'flrt_filters_button', 5);
45 }else{
46 if (isset($theme_dependencies['button_hook']) && is_array($theme_dependencies['button_hook'])) {
47 foreach ($theme_dependencies['button_hook'] as $button_hook) {
48 add_action($button_hook, function() use ($button_hook) {
49 flrt_filters_button(0, '', $button_hook);
50 }, 15);
51 }
52 }
53 }
54
55 } else {
56 if (isset($theme_dependencies['button_hook']) && is_array($theme_dependencies['button_hook'])) {
57 foreach ($theme_dependencies['button_hook'] as $button_hook) {
58 add_action($button_hook, function() use ($button_hook) {
59 flrt_filters_button(0, '', $button_hook);
60 }, 15);
61 }
62 }
63 }
64 }
65
66 }
67
68 // Add selected terms to the top
69 $chips_hooks = flrt_get_option('show_terms_in_content', []);
70
71 if( $chips_hooks ){
72 if( is_array( $chips_hooks ) && ! empty( $chips_hooks ) ){
73 foreach ( $chips_hooks as $hook ){
74 add_action( $hook, 'flrt_add_selected_terms_above_the_top' );
75 }
76 }
77 }
78 }
79 }
80
81 function wpc_add_selected_terms_above_the_top(){
82 _deprecated_function( __FUNCTION__, '1.0.7', 'flrt_add_selected_terms_above_the_top()' );
83 flrt_add_selected_terms_above_the_top();
84 }
85
86 function flrt_add_selected_terms_above_the_top()
87 {
88 flrt_show_selected_terms(true);
89 }
90
91 function flrt_get_theme_dependencies(){
92 $current_theme = strtolower( get_template() );
93
94 $theme_dependencies = array(
95 'storefront' => array(
96 'posts_container' => '#primary',
97 'sidebar_container' => '#secondary',
98 'primary_color' => '#96588a',
99 'button_hook' => array('storefront_content_top'),
100 'chips_hook' => array('storefront_loop_before')
101 ),
102 'hello-elementor' => array(
103 'posts_container' => '.page-content',
104 'sidebar_container' => '',
105 'primary_color' => '#CC3366',
106 'button_hook' => '',
107 'chips_hook' => ''
108 ),
109 'astra' => array(
110 'posts_container' => '#primary',
111 'sidebar_container' => '#secondary',
112 'primary_color' => '#0274be',
113 'button_hook' => '',
114 'chips_hook' => ''
115 ),
116 'twentyeleven' => array(
117 'posts_container' => '#primary',
118 'sidebar_container' => '#secondary',
119 'primary_color' => '#1982d1',
120 'button_hook' => '',
121 'chips_hook' => ''
122 ),
123 'twentytwelve' => array(
124 'posts_container' => '#primary',
125 'sidebar_container' => '#secondary',
126 'primary_color' => '#21759b',
127 'button_hook' => '',
128 'chips_hook' => ''
129 ),
130 'twentyfourteen' => array(
131 'posts_container' => '#primary',
132 'sidebar_container' => '#secondary',
133 'primary_color' => '#24890d',
134 'button_hook' => '',
135 'chips_hook' => ''
136 ),
137 'twentyfifteen' => array(
138 'posts_container' => '#primary',
139 'sidebar_container' => '#secondary', // There are problems on mobile
140 // because of sidebar is hidden on mobile until user open header menu.
141 'primary_color' => '#333333',
142 'button_hook' => '',
143 'chips_hook' => ''
144 ),
145 'twentysixteen' => array(
146 'posts_container' => '#primary',
147 'sidebar_container' => '#secondary',
148 'primary_color' => '#007acc',
149 'button_hook' => '',
150 'chips_hook' => ''
151 ),
152 'twentyseventeen' => array(
153 'posts_container' => '#primary',
154 'sidebar_container' => '#secondary',
155 'primary_color' => '#222222',
156 'button_hook' => '',
157 'chips_hook' => ''
158 ),
159 'twentynineteen' => array(
160 'posts_container' => '#primary',
161 'sidebar_container' => '#secondary',
162 'primary_color' => '#0073aa',
163 'button_hook' => '',
164 'chips_hook' => ''
165 ),
166 'twentytwentyfive' => array(
167 'posts_container' => '#wp--skip-link--target',
168 'sidebar_container' => '',
169 'primary_color' => '#0073aa',
170 'button_hook' => '',
171 'chips_hook' => ''
172 ),
173 'twentytwenty' => array(
174 'posts_container' => '#site-content',
175 'sidebar_container' => '',
176 'primary_color' => '#cd2653',
177 'button_hook' => '',
178 'chips_hook' => ''
179 ),
180 'twentytwentyone' => array(
181 'posts_container' => '#content',
182 'sidebar_container' => '.widget-area',
183 'primary_color' => '#28303d',
184 'button_hook' => '',
185 'chips_hook' => ''
186 ),
187 'popularfx' => array(
188 'posts_container' => '#primary',
189 'sidebar_container' => '#secondary',
190 'primary_color' => '#0072b7',
191 'button_hook' => '',
192 'chips_hook' => ''
193 ),
194 'oceanwp' => array(
195 'posts_container' => '#primary',
196 'sidebar_container' => '#right-sidebar',
197 'primary_color' => '#13aff0',
198 'button_hook' => array('ocean_before_content'),
199 'chips_hook' => array('ocean_before_content')
200 ),
201 'kadence' => array(
202 'posts_container' => '#main',
203 'sidebar_container' => '#secondary',
204 'primary_color' => '#3182ce',
205 'button_hook' => array('kadence_before_main_content'),
206 'chips_hook' => array('kadence_before_main_content')
207 ),
208 'zakra' => array(
209 'posts_container' => '#primary',
210 'sidebar_container' => '#secondary',
211 'primary_color' => '#269bd1',
212 'button_hook' => array('zakra_before_posts_the_loop'),
213 'chips_hook' => array('zakra_before_posts_the_loop')
214 ),
215 'neve' => array(
216 'posts_container' => '.nv-index-posts',
217 'sidebar_container' => '#secondary', // '.nv-sidebar-wrap',
218 'primary_color' => '#393939',
219 'button_hook' => array('neve_before_loop'),
220 'chips_hook' => array('neve_before_loop')
221 ),
222 'hestia' => array(
223 'posts_container' => '#woo-products-wrap',
224 'sidebar_container' => '#secondary',
225 'primary_color' => '#e91e63',
226 'button_hook' => array('hestia_before_index_posts_loop'),
227 'chips_hook' => array('hestia_before_index_posts_loop')
228 ),
229 'colibri-wp' => array(
230 'posts_container' => '.main-row-inner .h-col:not(.colibri-sidebar)',
231 'sidebar_container' => '.colibri-sidebar',
232 'primary_color' => '#03a9f4',
233 'button_hook' => '',
234 'chips_hook' => ''
235 ),
236 'teluro' => array(
237 'posts_container' => '.main-row-inner .h-col:not(.colibri-sidebar)',
238 'sidebar_container' => '.colibri-sidebar',
239 'primary_color' => '#f26559',
240 'button_hook' => '',
241 'chips_hook' => ''
242 ),
243 'numinous' => array(
244 'posts_container' => '#primary',
245 'sidebar_container' => '#secondary',
246 'primary_color' => '#f4ab00',
247 'button_hook' => array('numinous_content'),
248 'chips_hook' => ''
249 ),
250 'sydney' => array(
251 'posts_container' => '#primary',
252 'sidebar_container' => '#secondary',
253 'primary_color' => '#d65050',
254 'button_hook' => array('sydney_before_content'),
255 'chips_hook' => ''
256 ),
257 // Commercial themes
258 'avada' => array(
259 'posts_container' => '#content',
260 'sidebar_container' => '#sidebar',
261 'primary_color' => '#65bc7b',
262 'button_hook' => array('avada_before_main_container'),
263 'chips_hook' => ''
264 ),
265 'generatepress' => array(
266 'posts_container' => '#primary',
267 'sidebar_container' => '.sidebar',
268 'primary_color' => '#1e73be',
269 'button_hook' => array('generate_before_main_content'),
270 'chips_hook' => array('generate_before_main_content')
271 ),
272 'the7' => array(
273 'posts_container' => '#content',
274 'sidebar_container' => '#sidebar',
275 'primary_color' => '',
276 'button_hook' => '',
277 'chips_hook' => ''
278 ),
279 'dt-the7' => array(
280 'posts_container' => '#content',
281 'sidebar_container' => '#sidebar',
282 'primary_color' => '',
283 'button_hook' => '',
284 'chips_hook' => ''
285 ),
286 'flatsome' => array(
287 'posts_container' => '.shop-container',
288 'sidebar_container' => '#shop-sidebar',
289 'primary_color' => '#446084',
290 'button_hook' => '',
291 'chips_hook' => ''
292 ),
293 'betheme' => array(
294 'posts_container' => '.sections_group',
295 'sidebar_container' => '.sidebar',
296 'primary_color' => '',
297 'button_hook' => '',
298 'chips_hook' => ''
299 ),
300 'bridge' => array(
301 'posts_container' => '.container .column1',
302 'sidebar_container' => '',
303 'primary_color' => '',
304 'button_hook' => '',
305 'chips_hook' => ''
306 ),
307 'impreza' => array(
308 'posts_container' => '#page-content .w-grid-list',
309 'sidebar_container' => '',
310 'primary_color' => '',
311 'button_hook' => '',
312 'chips_hook' => ''
313 ),
314 'enfold' => array(
315 'posts_container' => 'main.content',
316 'sidebar_container' => '',
317 'primary_color' => '',
318 'button_hook' => '',
319 'chips_hook' => ''
320 ),
321 'porto' => array(
322 'posts_container' => '#content',
323 'sidebar_container' => '',
324 'primary_color' => '',
325 'button_hook' => '',
326 'chips_hook' => ''
327 ),
328 'genesis' => array(
329 'posts_container' => '#primary',
330 'sidebar_container' => '#secondary',
331 'primary_color' => '',
332 'button_hook' => '',
333 'chips_hook' => ''
334 ),
335 'woodmart' => array(
336 'posts_container' => '.site-content',
337 'sidebar_container' => '#secondary',
338 'primary_color' => '#83b735',
339 'button_hook' => '',
340 'chips_hook' => array( 'woodmart_shop_filters_area', 'woodmart_main_loop')
341 ),
342
343 'bricks' => array(
344 'posts_container' => '.brxe-container',
345 'sidebar_container' => '',
346 'primary_color' => '',
347 'button_hook' => array('bricks_after_header'),
348 'chips_hook' => ''
349 ),
350 'bb-theme' => array(
351 'posts_container' => '#fl-main-content',
352 'sidebar_container' => '',
353 'primary_color' => '',
354 'button_hook' => array('fl_content_open'),
355 'chips_hook' => ''
356 ),
357 );
358
359 $theme_dependencies = apply_filters( 'wpc_theme_dependencies', $theme_dependencies );
360
361 if( isset( $theme_dependencies[ $current_theme ] ) ){
362 return $theme_dependencies[ $current_theme ];
363 }
364
365 return array(
366 'posts_container' => false,
367 'sidebar_container' => false,
368 'primary_color' => false,
369 'button_hook' => array(),
370 'chips_hook' => array()
371 );
372 }
373
374 add_action( 'wp', 'flrt_wp' );
375
376 if( ! function_exists('flrt_set_posts_container') ){
377 function flrt_set_posts_container( $theme_posts_container )
378 {
379 $theme_dependencies = flrt_get_theme_dependencies();
380
381 if( isset( $theme_dependencies[ 'posts_container' ] ) ){
382 return $theme_dependencies[ 'posts_container' ];
383 }
384
385 return $theme_posts_container;
386 }
387 }
388
389 function flrt_set_theme_color($color ){
390
391 $theme_dependencies = flrt_get_theme_dependencies();
392
393 if( $theme_dependencies['primary_color'] ){
394 $color = $theme_dependencies['primary_color'];
395 }
396
397 return $color;
398 }
399
400 if( ! function_exists('flrt_init') ){
401 function flrt_init()
402 {
403 // Set correct theme posts container
404 add_filter('wpc_theme_posts_container', 'flrt_set_posts_container');
405
406 // Set correct theme color
407 add_filter('wpc_theme_color', 'flrt_set_theme_color');
408
409 //
410 if( flrt_is_acf() ) {
411 add_filter( 'wpc_pre_save_filter', 'flrt_maybe_acf_field' );
412 add_filter( 'wpc_default_sorting_terms', 'flrt_acf_terms_order', 10, 2 );
413 }
414 }
415 }
416 add_action('init', 'flrt_init');
417
418 function flrt_wpml_active(){
419 if( defined('WPML_PLUGIN_BASENAME') ){
420 return true;
421 }
422 return false;
423 }
424
425 add_action( 'elementor/editor/before_enqueue_scripts', 'flrt_include_elementor_script' );
426 function flrt_include_elementor_script(){
427 $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
428 $ver = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? rand(0, 1000) : FLRT_PLUGIN_VER;
429 wp_enqueue_script('wpc-widgets', FLRT_PLUGIN_DIR_URL . 'assets/js/wpc-widgets' . $suffix . '.js', ['jquery', 'jquery-ui-sortable'], $ver, true );
430 wp_enqueue_style('wpc-widgets', FLRT_PLUGIN_DIR_URL . 'assets/css/wpc-widgets' . $suffix . '.css', [], $ver );
431
432 $l10n = array(
433 'wpcItemNum' => esc_html__( 'Item #', 'filter-everything')
434 );
435 wp_localize_script( 'wpc-widgets', 'wpcWidgets', $l10n );
436 }
437
438 /*
439 * Polylang compatibility functions
440 * */
441 function flrt_maybe_has_translation( $post_id, $lang = '' ){
442
443 if( function_exists( 'pll_get_post' ) ){
444 $translation_post_id = pll_get_post( $post_id, $lang );
445 if( $translation_post_id ){
446 $post_id = $translation_post_id;
447 }
448 }
449
450 return $post_id;
451 }
452
453 function flrt_pll_pro_active(){
454 if ( defined('POLYLANG_PRO') ) {
455 return true;
456 }
457 return false;
458 }
459 // Allow Filter Sets to be translatable if Polylang PRO activated
460 // This make sense for Filter Sets with common locations only
461 add_action( 'after_setup_theme', 'flrt_pll_init', 20 );
462 function flrt_pll_init(){
463 if( flrt_pll_pro_active() && defined('FLRT_ALLOW_PLL_TRANSLATIONS') && FLRT_ALLOW_PLL_TRANSLATIONS ){
464 add_filter( 'pll_get_post_types', 'flrt_add_cpt_to_pll', 10, 2 );
465 }
466 }
467
468 function flrt_add_cpt_to_pll( $post_types, $is_settings ) {
469 if ( $is_settings ) {
470 unset( $post_types[ FLRT_FILTERS_SET_POST_TYPE ], $post_types[ FLRT_FILTERS_SET_POST_TYPE ] );
471 } else {
472 $post_types[ FLRT_FILTERS_SET_POST_TYPE ] = FLRT_FILTERS_SET_POST_TYPE;
473 if( defined('FLRT_FILTERS_PRO') && FLRT_FILTERS_PRO ) {
474 $post_types[ FLRT_SEO_RULES_POST_TYPE ] = FLRT_SEO_RULES_POST_TYPE;
475 }
476 }
477 return $post_types;
478 }
479
480 /**
481 * Adds compatibility the Price filter with multi-currency plugins WOOCS and CURCY
482 * @since 1.7.12
483 */
484 add_action('init', 'flrt_add_currencies_support');
485 function flrt_add_currencies_support() {
486 if ( flrt_is_woocommerce() ) {
487 // For the FOX - Currency Switcher Professional for WooCommerce
488 if ( defined( 'WOOCS_PLUGIN_NAME' ) && WOOCS_PLUGIN_NAME ) {
489 // Converts values into selected currency. Visible in the range slider form
490 add_filter( 'wpc_set_num_shift', 'flrt_set_woocs_shift', 10, 2 );
491 function flrt_set_woocs_shift( $value, $entity_name ) {
492 global $WOOCS;
493
494 if ( $entity_name === '_price' ) {
495 if ( property_exists( $WOOCS, 'default_currency' ) && property_exists( $WOOCS, 'current_currency' ) ) {
496 if ( ! $WOOCS->default_currency || ! $WOOCS->current_currency ) {
497 return $value;
498 }
499
500 if ( $WOOCS->default_currency !== $WOOCS->current_currency && method_exists( $WOOCS, 'convert_from_to_currency' ) ) {
501 $value = $WOOCS->convert_from_to_currency( $value, $WOOCS->default_currency, $WOOCS->current_currency );
502 }
503 }
504 }
505
506 return $value;
507 }
508
509 // Converts values back to default currency for WP_Query
510 add_filter( 'wpc_unset_num_shift', 'flrt_unset_woocs_shift', 10, 2 );
511 function flrt_unset_woocs_shift( $value, $entity_name ) {
512 global $WOOCS;
513
514 if ( $entity_name === '_price' ) {
515 if ( property_exists( $WOOCS, 'default_currency' ) && property_exists( $WOOCS, 'current_currency' ) ) {
516 if ( ! $WOOCS->default_currency || ! $WOOCS->current_currency ) {
517 return $value;
518 }
519
520 $precision = 2;
521 if( method_exists( $WOOCS, 'get_currency_price_num_decimals' ) ) {
522 $precision = $WOOCS->get_currency_price_num_decimals( $WOOCS->current_currency, $WOOCS->price_num_decimals );
523 }
524
525 if ( $WOOCS->default_currency !== $WOOCS->current_currency && method_exists( $WOOCS, 'convert_from_to_currency' ) ) {
526 $value = $WOOCS->convert_from_to_currency( $value, $WOOCS->current_currency, $WOOCS->default_currency );
527 $value = round( $value, $precision );
528 }
529 }
530 }
531
532 return $value;
533 }
534 }
535
536 // For the CURCY - Multi Currency for WooCommerce
537 if ( defined( 'WOOMULTI_CURRENCY_F_VERSION' ) && WOOMULTI_CURRENCY_F_VERSION ) {
538 // Converts values into selected currency. Visible in the range slider form
539 add_filter( 'wpc_set_num_shift', 'flrt_set_curcy_shift', 10, 2 );
540 function flrt_set_curcy_shift( $value, $entity_name ) {
541
542 if ( $entity_name === '_price' ) {
543 if ( method_exists( 'WOOMULTI_CURRENCY_F_Data', 'get_ins' ) && function_exists('wmc_get_price' ) ) {
544 $settings = WOOMULTI_CURRENCY_F_Data::get_ins();
545
546 if ( ! method_exists( $settings, 'get_current_currency' ) || ! method_exists( $settings, 'get_default_currency' ) ) {
547 return $value;
548 }
549
550 $currency = $settings->get_current_currency();
551 $default_currency = $settings->get_default_currency();
552
553 if ( $currency !== $default_currency ) {
554 $value = wmc_get_price( $value, $currency );
555 }
556 }
557 }
558
559 return $value;
560 }
561
562 // Converts values back to default currency for WP_Query
563 add_filter( 'wpc_unset_num_shift', 'flrt_unset_curcy_shift', 10, 2 );
564 function flrt_unset_curcy_shift( $value, $entity_name ) {
565
566 if ( $entity_name === '_price' ) {
567 if ( method_exists( 'WOOMULTI_CURRENCY_F_Data', 'get_ins' ) && function_exists('wmc_revert_price' ) ) {
568 $settings = WOOMULTI_CURRENCY_F_Data::get_ins();
569
570 if ( ! method_exists( $settings, 'get_current_currency' ) || ! method_exists( $settings, 'get_default_currency' ) ) {
571 return $value;
572 }
573
574 $currency = $settings->get_current_currency();
575 $default_currency = $settings->get_default_currency();
576
577 if ( $currency !== $default_currency ) {
578 $value = wmc_revert_price( $value );
579 }
580 }
581 }
582
583 return $value;
584 }
585 }
586 }
587 }
588
589 /**
590 * Removes WooCommerce Product Query post clauses for the price filter
591 * @since 1.7.12
592 */
593 function flrt_remove_product_query_post_clauses( $wp_query, $WC_query ) {
594 $wpManager = \FilterEverything\Filter\Container::instance()->getWpManager();
595
596 if ( $wpManager->getQueryVar( 'wpc_is_filter_request' ) ) {
597 remove_filter('posts_clauses', array( $WC_query, 'product_query_post_clauses' ), 10, 2);
598 }
599
600 return $wp_query;
601 }
602
603 add_filter('wpc_check_broken_filter', function ($is_broken, $query) {
604 $detector_class = 'FilterEverything\\Filter\\WP_Query_Source_Detector';
605 $is_allowed_method = 'is_allowed';
606 $source_var = 'flrt_detected_source';
607
608 if (defined('FLRT_FILTERS_PRO')) {
609 if (defined('FLRT_PRO_BUILDER_KEY')) {
610 $builder_key = apply_filters('wpc_builder_key_pro', $query->get($source_var), constant('FLRT_PRO_BUILDER_KEY'));
611
612 if ($detector_class::$is_allowed_method($builder_key)) {
613 return false;
614 }
615 }
616 }
617
618 if (!defined('FLRT_FILTERS_PRO')) {
619 $builder_key = apply_filters('wpc_builder_key', $query->get($source_var), $detector_class::$builder_key);
620
621 if ($detector_class::$is_allowed_method($builder_key)) {
622 return false;
623 }
624 }
625
626 return true;
627 }, 10, 2);
628
629 function flrt_is_dokan() {
630 return function_exists('dokan');
631 }
632
633 function flrt_maybe_acf_field( $filter ){
634 if( $filter['entity'] === 'post_meta' ) {
635 global $wpdb;
636 // Try to check if this is ACF field
637 $sql[] = "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts}";
638 $sql[] = "WHERE {$wpdb->posts}.post_excerpt = %s";
639 $sql[] = "AND {$wpdb->posts}.post_type = %s";
640 $sql[] = "ORDER BY {$wpdb->posts}.ID ASC";
641
642 $sql = implode(' ', $sql );
643 $sql = $wpdb->prepare( $sql, $filter['e_name'], 'acf-field' );
644 $results = $wpdb->get_results( $sql, ARRAY_A );
645
646 if ( ! empty( $results ) ) {
647 $ids = [];
648 foreach ( $results as $single_result ) {
649 if( isset( $single_result['ID'] ) ){
650 $ids[] = $single_result['ID'];
651 }
652 }
653 $acf_field_ids = implode( ',', $ids );
654
655 if( ! empty( $acf_field_ids ) ){
656 $filter['acf_fields'] = $acf_field_ids;
657 }
658 }
659 }
660
661 return $filter;
662 }
663
664 function flrt_acf_terms_order( $entity_items, $filter ){
665
666 if( isset( $filter['acf_fields'] ) && $filter['acf_fields'] !== '' ) {
667 global $wpdb;
668 // Here we have to get ACF fields by their IDs and sort terms in according to
669 // the order in the field.
670 $sql = [];
671 $acf_field_ids = preg_replace( '/^[\d]\,/', '', $filter['acf_fields'] );
672 $sql[] = "SELECT {$wpdb->posts}.post_content FROM {$wpdb->posts}";
673 $sql[] = "WHERE {$wpdb->posts}.ID IN( {$acf_field_ids} )";
674 $sql[] = "ORDER BY {$wpdb->posts}.ID ASC";
675 $sql = implode(' ', $sql );
676
677 $results = $wpdb->get_results( $sql, ARRAY_A );
678
679 if( empty( $results ) ) {
680 return $entity_items;
681 }
682
683 $field_terms = [];
684 foreach ( $results as $acf_field ){
685 if( isset( $acf_field['post_content'] ) ) {
686 $field_options = maybe_unserialize( $acf_field['post_content'] );
687
688 if( isset( $field_options['choices'] ) && is_array( $field_options['choices'] ) ){
689 foreach ( $field_options['choices'] as $value => $label ){
690 if( ! isset( $field_terms[$value] ) ) {
691 $field_terms[$value] = $label;
692 }
693 }
694 }
695 }
696 }
697
698 $current_items = $entity_items;
699 $sorted_items = [];
700
701 foreach ( $field_terms as $tslug => $tvalue ) {
702 $tslug = sanitize_title( $tslug );
703
704 if( isset( $current_items[ $tslug ] ) ) {
705 $term_object = $current_items[ $tslug ];
706 $term_object->name = $tvalue;
707 $sorted_items[ $tslug ] = $term_object;
708 unset( $current_items[ $tslug ] );
709 }
710 }
711
712 if( ! empty( $current_items ) ){
713 foreach ( $current_items as $slug => $item ){
714 $sorted_items[$slug] = $item;
715 }
716 }
717 $entity_items = $sorted_items;
718 }
719
720 return $entity_items;
721 }
722
723 /**
724 * Adds correct pagination URLs to the Load more/Infinite scroll button for Elementor posts block
725 */
726 add_filter( 'elementor/widget/render_content', 'flrt_elementor_load_more_anchor', 10, 2 );
727 function flrt_elementor_load_more_anchor( $widget_content, $module ){
728 // Nothing is needed if there is no Filter request
729 if( ! flrt_is_filter_request() ){
730 return $widget_content;
731 }
732
733 if( $module instanceof ElementorPro\Modules\Posts\Widgets\Posts ){
734 global $wp_rewrite;
735
736 $urlManager = \FilterEverything\Filter\Container::instance()->getUrlManager();
737 $current_page = $module->get_current_page();
738 $next_page = intval( $current_page ) + 1;
739 $data_next_page = $module->get_wp_link_page( $next_page );
740 $rewrite = $wp_rewrite->wp_rewrite_rules();
741
742 /*
743 * Loop widgets (Loop Grid/Loop Carousel) paginate with a widget-scoped
744 * query arg (?e-page-<widget id>=N) instead of /page/N/, so the
745 * path-based base replacement below never matches. Swap the base for
746 * the filtered URL directly and carry the pagination args over.
747 */
748 $next_page_args = array();
749 $next_url_parts = parse_url( $data_next_page );
750 if ( isset( $next_url_parts['query'] ) ) {
751 parse_str( $next_url_parts['query'], $next_page_args );
752 }
753
754 $e_page_args = array();
755 foreach ( $next_page_args as $arg_key => $arg_value ) {
756 if ( strpos( $arg_key, 'e-page-' ) === 0 ) {
757 $e_page_args[ $arg_key ] = $arg_value;
758 }
759 }
760
761 if ( ! empty( $e_page_args ) ) {
762 // The current request may already contain pagination args (page 2+)
763 $data_next_page = remove_query_arg( array_keys( $e_page_args ), $urlManager->getFormActionOrFullPageUrl( true ) );
764 foreach ( $e_page_args as $arg_key => $arg_value ) {
765 $data_next_page = flrt_add_query_arg( $arg_key, $arg_value, $data_next_page );
766 }
767 } else if ( defined('FLRT_PERMALINKS_ENABLED') && FLRT_PERMALINKS_ENABLED ) {
768 // This is ok when permalinks are enabled.
769 $data_next_page = str_replace( $urlManager->removePaginationBase( $data_next_page ), $urlManager->getFormActionOrFullPageUrl(), $data_next_page );
770 $uri_components = explode( "?", $urlManager->getFormActionOrFullPageUrl( true ) );
771 if( isset( $uri_components[1] ) ){
772 $data_next_page = $data_next_page . '?'.$uri_components[1];
773 }
774 } else if ( ! FLRT_PERMALINKS_ENABLED && ! empty( $rewrite ) ) {
775 // WordPress permalinks are Enabled, but Filter Everything permalinks are Disabled
776 $uri_components = explode( "?", $urlManager->getFormActionOrFullPageUrl( true ) );
777 // If URI part after ? exists
778 if( isset( $uri_components[1] ) ){
779 $data_next_page = $data_next_page . '?'.$uri_components[1];
780 }
781 } else {
782 // No permalinks at all
783 $current_page_url = $urlManager->getFormActionOrFullPageUrl( true );
784 $url_parts = parse_url( $data_next_page );
785 if( isset( $url_parts['query'] ) ){
786 parse_str( $url_parts['query'], $params );
787 if( isset( $params['page'] ) && $params['page'] ) {
788 $data_next_page = flrt_add_query_arg( 'page', $params['page'], $current_page_url );
789 }
790 }
791 }
792
793 /*
794 * $data_next_page carries the GET part of the current request, and
795 * getFormActionOrFullPageUrl() hands it back URL-DECODED (parse_str()
796 * + build_query(), which does not re-encode). Printed raw, a request
797 * like ?x="><script>… closed the attribute and injected markup —
798 * reflected XSS, reported by Wordfence (CVE-2026-87869). esc_url()
799 * drops the characters that can break out of the attribute and
800 * re-encodes the ampersands for the HTML context.
801 * A callback instead of a replacement string: in a string "$1" or
802 * "\1" coming from the URL would be read as a backreference.
803 */
804 $next_page_attr = 'data-next-page="' . esc_url( $data_next_page ) . '"';
805 $widget_content = preg_replace_callback(
806 '%data-next-page\="[^"]+"%',
807 function () use ( $next_page_attr ) {
808 return $next_page_attr;
809 },
810 $widget_content
811 );
812 }
813
814 return $widget_content;
815 }
816
817 add_filter( 'wpc_remove_pagination_base', 'flrt_remove_pagination_base' );
818 function flrt_remove_pagination_base( $url ){
819 global $wp_rewrite;
820
821 $rewrite = $wp_rewrite->wp_rewrite_rules();
822 $url = ( ! empty( $rewrite ) ) ? user_trailingslashit( $url ) : rtrim( $url, '/' ) . '/';
823
824 return $url;
825 }
826
827 function flrt_is_woo_discount_rules()
828 {
829 $check_woo_discount_rules = apply_filters('flrt_woo_discount_rules_enabled', true);
830 if(!$check_woo_discount_rules) return false;
831 if( flrt_is_woocommerce() &&
832 class_exists('Wdr\App\Helpers\Woocommerce') &&
833 class_exists('Wdr\App\Controllers\Base') &&
834 class_exists('Wdr\App\Helpers\Rule') &&
835 class_exists('Wdr\App\Controllers\ManageDiscount') &&
836 class_exists('Wdr\App\Controllers\DiscountCalculator') &&
837 class_exists('Wdr\App\Models\DBTable')
838 )
839 {
840 $tb_table = new Wdr\App\Models\DBTable();
841 $wdr_rules = $tb_table::getRules();
842 if(!empty($wdr_rules)){
843 $discount_types = [];
844 foreach ($wdr_rules as $rule){
845 $discount_types[] = $rule->discount_type;
846 }
847 $allowed_discount_types = ['wdr_simple_discount', 'wdr_bulk_discount', 'wdr_set_discount'];
848 if(!empty(array_intersect($allowed_discount_types, $discount_types))){
849 return true;
850 }
851 }
852 }
853 return false;
854 }
855
856 function flrt_is_elementor_active()
857 {
858 return did_action( 'elementor/loaded' );
859 }
860
861 if ( flrt_is_elementor_active() ) {
862 function wpc_add_elementor_widget_categories( $elements_manager ) {
863 $pro_text = (defined('FLRT_FILTERS_PRO') && FLRT_FILTERS_PRO)
864 ? ' ' .esc_html__('PRO', 'filter-everything')
865 : '';
866
867 $elements_manager->add_category(
868 'filter-everything',
869 [
870 'title' => esc_html__( 'Filter Everything', 'filter-everything' ) . $pro_text,
871 'icon' => 'fa-solid fa-filter',
872 ]
873 );
874 }
875 add_action( 'elementor/elements/categories_registered', 'wpc_add_elementor_widget_categories' );
876
877 function wpc_register_elementor_widget( $widgets_manager ) {
878
879 flrt_include('src/Frontend/Builders/ElementorWidgets/ChipsElementorWidget.php');
880 flrt_include('src/Frontend/Builders/ElementorWidgets/FiltersElementorWidget.php');
881 flrt_include('src/Frontend/Builders/ElementorWidgets/SortingElementorWidget.php');
882
883 $widgets_manager->register( new \FilterEverything\Filter\ChipsElementorWidget() );
884 $widgets_manager->register( new \FilterEverything\Filter\FiltersElementorWidget() );
885 $widgets_manager->register( new \FilterEverything\Filter\SortingElementorWidget() );
886
887 }
888 add_action( 'elementor/widgets/register', 'wpc_register_elementor_widget' );
889
890 add_action( 'elementor/editor/after_enqueue_styles', function() {
891 wp_enqueue_style(
892 'filter-everything-elementor',
893 FLRT_PLUGIN_DIR_URL . 'assets/css/elementor-icon.css'
894 );
895 $css = '
896 .wpc-fe-icon {
897 background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDUzIDUzIiBpZD0iTGF5ZXJfMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA1MyA1MyIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTMgNTM7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCiAgICAgICAgICAgICAgIDxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQogICAgICAgICAgICAgICAgLnN0MHtkaXNwbGF5Om5vbmU7fQ0KICAgICAgICAgICAgICAgIC5zdDF7ZGlzcGxheTppbmxpbmU7fQ0KICAgICAgICAgICAgICAgIC5zdDN7ZmlsbDojZmZmZmZmO30NCiAgICAgICAgICAgICAgICAuc3Q0e2Rpc3BsYXk6bm9uZTtmaWxsOiNmZmZmZmY7fQ0KICAgICAgICAgICAgICAgIC5zdDV7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eTowO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDozO3N0cm9rZS1taXRlcmxpbWl0OjEwO30NCiAgICAgICAgICAgICAgICAuc3Q2e2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MDtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQogICAgICAgICAgICAgICA8L3N0eWxlPg0KICAgICAgICAgICAgICAgPGcgaWQ9IkxheWVyXzJfMDAwMDAwNDc3NzA3MTk3MTAxMTA3NDIyMzAwMDAwMDM5MjM5NTE2MjYxNDg4NDk1NTdfIiBjbGFzcz0ic3QwIj4NCiAgICAgICAgICAgICAgICA8cmVjdCB4PSIwIiB5PSIwIiBjbGFzcz0ic3QxIiB3aWR0aD0iNTMuMSIgaGVpZ2h0PSI1My4xIi8+DQogICAgICAgICAgICAgICA8L2c+DQogICAgICAgICAgICAgICA8ZyBpZD0iTGF5ZXJfMV8wMDAwMDE2MjMzMzEwMzI2NTgwNjk4MTUzMDAwMDAxNzE0NjYyNDI0NzU5MTY3NDU1Nl8iPg0KICAgICAgICAgICAgICAgIDxnPg0KICAgICAgICAgICAgICAgICAgIDxkZWZzPg0KICAgICAgICAgICAgICAgICAgICAgIDxwYXRoIGlkPSJTVkdJRF8xXyIgZD0iTTAsMGg1M3Y1M0gwVjB6IE0yMy4zLDM3LjJjMS40LDAsMi41LTEuMSwyLjUtMi41cy0xLjEtMi41LTIuNS0yLjVzLTIuNSwxLjEtMi41LDIuNSAgICAgQzIwLjgsMzYuMSwyMS45LDM3LjIsMjMuMywzNy4yeiBNMzMuNCwyNy4yYzEuNCwwLDIuNS0xLjEsMi41LTIuNXMtMS4xLTIuNS0yLjUtMi41cy0yLjUsMS4xLTIuNSwyLjVTMzIsMjcuMiwzMy40LDI3LjJ6ICAgICAgTTIzLDIyLjhjMS42LDAsMi45LTEuMywyLjktMi45UzI0LjYsMTcsMjMsMTdzLTIuOSwxLjMtMi45LDIuOUMyMC4yLDIxLjUsMjEuNSwyMi44LDIzLDIyLjh6Ii8+DQogICAgICAgICAgICAgICAgICAgPC9kZWZzPg0KICAgICAgICAgICAgICAgICAgIDxjbGlwUGF0aCBpZD0iU1ZHSURfMDAwMDAxMTI2MDgzNDA4MDQyNDU0NDI0NjAwMDAwMTM5ODYyMTkxNzgxOTkwODYyNDRfIj4NCiAgICAgICAgICAgICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNTVkdJRF8xXyIgc3R5bGU9Im92ZXJmbG93OnZpc2libGU7Ii8+DQogICAgICAgICAgICAgICAgICAgPC9jbGlwUGF0aD4NCiAgICAgICAgICAgICAgICAgICA8ZyBpZD0iQmFyc0NsaXBwZWQiIHN0eWxlPSJjbGlwLXBhdGg6dXJsKCNTVkdJRF8wMDAwMDExMjYwODM0MDgwNDI0NTQ0MjQ2MDAwMDAxMzk4NjIxOTE3ODE5OTA4NjI0NF8pOyI+DQogICAgICAgICAgICAgICAgICAgICAgPHBhdGggY2xhc3M9InN0MyIgZD0iTTM5LjksMzEuNUwxOCwzNy4zYy0wLjYsMC4yLTEuMi0wLjItMS40LTAuOGMtMC4yLTAuNiwwLjItMS4yLDAuOC0xLjRsMjEuOS01LjljMC42LTAuMiwxLjIsMC4yLDEuNCwwLjggICAgIEM0MC44LDMwLjcsNDAuNSwzMS4zLDM5LjksMzEuNXoiLz4NCiAgICAgICAgICAgICAgICAgICAgICA8cGF0aCBjbGFzcz0ic3QzIiBkPSJNMzguMSwyNC42bC0yMS45LDUuOWMtMC42LDAuMi0xLjItMC4yLTEuNC0wLjhjLTAuMi0wLjYsMC4yLTEuMiwwLjgtMS40bDIxLjktNS45YzAuNi0wLjIsMS4yLDAuMiwxLjQsMC44ICAgICBDMzksMjMuOCwzOC43LDI0LjUsMzguMSwyNC42eiIvPg0KICAgICAgICAgICAgICAgICAgICAgIDxwYXRoIGNsYXNzPSJzdDMiIGQ9Ik0zNi4yLDE3LjlsLTIxLjksNS45Yy0wLjYsMC4yLTEuMi0wLjItMS40LTAuOGMtMC4yLTAuNiwwLjItMS4yLDAuOC0xLjRsMjEuOS01LjljMC42LTAuMiwxLjIsMC4yLDEuNCwwLjggICAgIEMzNy4yLDE3LjEsMzYuOCwxNy43LDM2LjIsMTcuOXoiLz4NCiAgICAgICAgICAgICAgICAgICA8L2c+DQogICAgICAgICAgICAgICAgPC9nPg0KICAgICAgICAgICAgICAgIDxwYXRoIGNsYXNzPSJzdDQiIGQ9Ik0yMy4zLDM3LjJjMS40LDAsMi41LTEuMSwyLjUtMi41cy0xLjEtMi41LTIuNS0yLjVzLTIuNSwxLjEtMi41LDIuNUMyMC44LDM2LjEsMjEuOSwzNy4yLDIzLjMsMzcuMnoiLz4NCiAgICAgICAgICAgICAgICA8cGF0aCBjbGFzcz0ic3Q0IiBkPSJNMzMuNCwyNy4yYzEuNCwwLDIuNS0xLjEsMi41LTIuNXMtMS4xLTIuNS0yLjUtMi41cy0yLjUsMS4xLTIuNSwyLjVTMzIsMjcuMiwzMy40LDI3LjJ6Ii8+DQogICAgICAgICAgICAgICAgPHBhdGggY2xhc3M9InN0NCIgZD0iTTIzLDIyLjhjMS42LDAsMi45LTEuMywyLjktMi45UzI0LjYsMTcsMjMsMTdzLTIuOSwxLjMtMi45LDIuOUMyMC4yLDIxLjUsMjEuNSwyMi44LDIzLDIyLjh6Ii8+DQogICAgICAgICAgICAgICAgPHBhdGggY2xhc3M9InN0NCIgZD0iTTIzLjksMzguMmMtMS45LDAuNS0zLjgtMC42LTQuMy0yLjVjLTAuNS0xLjksMC42LTMuOCwyLjUtNC4zczMuOCwwLjYsNC4zLDIuNUMyNi45LDM1LjgsMjUuOCwzNy43LDIzLjksMzguMiAgIHogTTIyLjYsMzMuMmMtMC45LDAuMi0xLjQsMS4xLTEuMSwyYzAuMiwwLjksMS4xLDEuNCwyLDEuMWMwLjktMC4yLDEuNC0xLjEsMS4xLTJDMjQuMywzMy41LDIzLjQsMzMsMjIuNiwzMy4yeiIvPg0KICAgICAgICAgICAgICAgIDxwYXRoIGNsYXNzPSJzdDQiIGQ9Ik0zNC4xLDI4LjJjLTEuOSwwLjUtMy44LTAuNi00LjMtMi41czAuNi0zLjgsMi41LTQuM2MxLjktMC41LDMuOCwwLjYsNC4zLDIuNUMzNy4xLDI1LjgsMzYsMjcuNywzNC4xLDI4LjJ6ICAgIE0zMi44LDIzLjJjLTAuOSwwLjItMS40LDEuMS0xLjEsMmMwLjIsMC45LDEuMSwxLjQsMiwxLjFjMC45LTAuMiwxLjQtMS4xLDEuMS0yQzM0LjUsMjMuNSwzMy42LDIzLDMyLjgsMjMuMnoiLz4NCiAgICAgICAgICAgICAgICA8cGF0aCBjbGFzcz0ic3Q0IiBkPSJNMjQuMiwyMy41Yy0xLjksMC41LTMuOC0wLjYtNC4zLTIuNXMwLjYtMy44LDIuNS00LjNzMy44LDAuNiw0LjMsMi41UzI2LjEsMjMsMjQuMiwyMy41eiBNMjIuOSwxOC42ICAgYy0wLjksMC4yLTEuNCwxLjEtMS4xLDJjMC4yLDAuOSwxLjEsMS40LDIsMS4xYzAuOS0wLjIsMS40LTEuMSwxLjEtMkMyNC43LDE4LjgsMjMuOCwxOC4zLDIyLjksMTguNnoiLz4NCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8cGF0aCBjbGFzcz0ic3Q1IiBmaWxsLW9wYWNpdHk9IjAiIGQ9Ik0yNi41LDUxLjVjMTMuOCwwLDI1LTExLjIsMjUtMjVzLTExLjItMjUtMjUtMjVzLTI1LDExLjItMjUsMjVTMTIuNyw1MS41LDI2LjUsNTEuNXoiLz4NCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8cGF0aCBjbGFzcz0ic3Q0IiBkPSJNMzMuMywyMWgxMGMwLjQsMCwwLjgtMC4zLDAuOC0wLjhzLTAuMy0wLjgtMC44LTAuOGgtMTBDMzMuMywyMC4yLDMzLjMsMjAuMiwzMy4zLDIxeiIvPg0KICAgICAgICAgICAgICAgPC9nPg0KICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICA8Y2lyY2xlIGNsYXNzPSJzdDYiIGZpbGwtb3BhY2l0eT0iMCIgY3g9IjIzLjMiIGN5PSIyMC4xIiByPSIyLjUiLz4NCiAgICAgICAgICAgICAgIDxjaXJjbGUgY2xhc3M9InN0NiIgZmlsbC1vcGFjaXR5PSIwIiBjeD0iMzMuMiIgY3k9IjI0LjgiIHI9IjIuNSIvPg0KICAgICAgICAgICAgICAgPGNpcmNsZSBjbGFzcz0ic3Q2IiBmaWxsLW9wYWNpdHk9IjAiIGN4PSIyMyIgY3k9IjM0LjgiIHI9IjIuNSIvPg0KICAgICAgICAgICAgICAgPC9zdmc+) no-repeat;
898 background-size: auto;
899 background-size: contain;
900 display: inline-block;
901 width: 28px;
902 height: 28px;
903 margin-bottom: -5px;
904 }
905
906 .elementor-navigator__element-widget .wpc-fe-icon {
907 width: 15px;
908 height: 15px;
909 margin-bottom: 0px;
910 }';
911 wp_add_inline_style( 'filter-everything-elementor', $css );
912 });
913
914 add_filter('elementor/document/wrapper_attributes', function($attributes) {
915 $attributes['wpc-filter-elementor-widget'] = true;
916 return $attributes;
917 });
918
919 add_action( 'wp_footer', function() {
920 if ( ! defined( 'ELEMENTOR_VERSION' ) ) {
921 return;
922 }
923 if( flrt_get_option('mobile_filter_settings') === 'show_bottom_widget' ){
924 if( flrt_get_experimental_option('disable_buttons') !== 'on' ) {
925
926 ?>
927
928 <script>
929 jQuery(function($) {
930 $(window).on('elementor/frontend/init', function() {
931 elementorFrontend.hooks.addAction(
932 'frontend/element_ready/filter-everything-filters.default',
933 function($scope) {
934 let $el = $('[wpc-filter-elementor-widget="1"][data-elementor-type]:not([data-elementor-type="loop-item"])');
935 if($el.length > 0){
936 $el.before(`<?php flrt_filters_button() ?>`);
937 }
938 }
939 );
940 });
941 });
942 </script>
943 <?php
944 }
945 }
946 });
947 }
948
949 add_action('admin_enqueue_scripts', function () {
950 $handle = 'filter-everything-menu-icon';
951 wp_register_style($handle, false);
952 wp_enqueue_style($handle);
953
954
955 $css = <<<PHP_CSS
956 #toplevel_page_edit-post_type-filter-set .wp-menu-image{
957 content: '';
958 background-repeat: no-repeat;
959 background-position: center;
960 background-size: 20px;
961 background-image: url('data:image/svg+xml,%3C%3Fxml version="1.0" encoding="utf-8"%3F%3E%3C!-- --%3E%3Csvg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 53 53" style="enable-background:new 0 0 53 53;" xml:space="preserve"%3E%3Cstyle type="text/css"%3E .st0%7Bdisplay:none;%7D .st1%7Bdisplay:inline;%7D .st2%7Bclip-path:url(%23SVGID_00000142154616827085436530000012698217856111301567_);%7D .st3%7Bfill:%23a7aaad;%7D .st4%7Bdisplay:none;fill:%23FFFFFF;%7D .st5%7Bfill:none;stroke:%23a7aaad;stroke-width:3;stroke-miterlimit:10;%7D .st6%7Bfill:none;stroke:%23a7aaad;stroke-width:2;stroke-miterlimit:10;%7D%0A%3C/style%3E%3Cg id="Layer_2_00000047770719710110742230000003923951626148849557_" class="st0"%3E%3Crect class="st1" width="53.1" height="53.1"/%3E%3C/g%3E%3Cg id="Layer_1_00000162333103265806981530000017146624247591674556_"%3E%3Cg%3E%3Cg%3E%3Cdefs%3E%3Cpath id="SVGID_1_" d="M0,0h53v53H0V0z M23.3,37.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5 C20.8,36.1,21.9,37.2,23.3,37.2z M33.4,27.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5S32,27.2,33.4,27.2z M23,22.8c1.6,0,2.9-1.3,2.9-2.9S24.6,17,23,17s-2.9,1.3-2.9,2.9C20.2,21.5,21.5,22.8,23,22.8z"/%3E%3C/defs%3E%3CclipPath id="SVGID_00000111880200341027563210000003406718579453459379_"%3E%3Cuse xlink:href="%23SVGID_1_" style="overflow:visible;"/%3E%3C/clipPath%3E%3Cg id="BarsClipped" style="clip-path:url(%23SVGID_00000111880200341027563210000003406718579453459379_);"%3E%3Cpath class="st3" d="M39.9,31.5L18,37.3c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C40.8,30.7,40.5,31.3,39.9,31.5z"/%3E%3Cpath class="st3" d="M38.1,24.6l-21.9,5.9c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C39,23.8,38.7,24.5,38.1,24.6z"/%3E%3Cpath class="st3" d="M36.2,17.9l-21.9,5.9c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C37.2,17.1,36.8,17.7,36.2,17.9z"/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3Cpath class="st4" d="M23.3,37.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5C20.8,36.1,21.9,37.2,23.3,37.2z"/%3E%3Cpath class="st4" d="M33.4,27.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5S32,27.2,33.4,27.2z"/%3E%3Cpath class="st4" d="M23,22.8c1.6,0,2.9-1.3,2.9-2.9S24.6,17,23,17s-2.9,1.3-2.9,2.9C20.2,21.5,21.5,22.8,23,22.8z"/%3E%3Cpath class="st4" d="M23.9,38.2c-1.9,0.5-3.8-0.6-4.3-2.5c-0.5-1.9,0.6-3.8,2.5-4.3s3.8,0.6,4.3,2.5C26.9,35.8,25.8,37.7,23.9,38.2 z M22.6,33.2c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C24.3,33.5,23.4,33,22.6,33.2z"/%3E%3Cpath class="st4" d="M34.1,28.2c-1.9,0.5-3.8-0.6-4.3-2.5s0.6-3.8,2.5-4.3c1.9-0.5,3.8,0.6,4.3,2.5C37.1,25.8,36,27.7,34.1,28.2z M32.8,23.2c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C34.5,23.5,33.6,23,32.8,23.2z"/%3E%3Cpath class="st4" d="M24.2,23.5c-1.9,0.5-3.8-0.6-4.3-2.5s0.6-3.8,2.5-4.3s3.8,0.6,4.3,2.5S26.1,23,24.2,23.5z M22.9,18.6 c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C24.7,18.8,23.8,18.3,22.9,18.6z"/%3E%3Cpath class="st5" d="M26.5,51.5c13.8,0,25-11.2,25-25s-11.2-25-25-25s-25,11.2-25,25S12.7,51.5,26.5,51.5z"/%3E%3Cpath class="st4" d="M33.3,21h10c0.4,0,0.8-0.3,0.8-0.8s-0.3-0.8-0.8-0.8h-10C33.3,20.2,33.3,20.2,33.3,21z"/%3E%3C/g%3E%3Ccircle class="st6" cx="23.3" cy="20.1" r="2.5"/%3E%3Ccircle class="st6" cx="33.2" cy="24.8" r="2.5"/%3E%3Ccircle class="st6" cx="23" cy="34.8" r="2.5"/%3E%3C/svg%3E');
962 }
963 #toplevel_page_edit-post_type-filter-set:hover .wp-menu-image{
964 background-image: url('data:image/svg+xml,%3C%3Fxml version="1.0" encoding="utf-8"%3F%3E%3C!-- --%3E%3Csvg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 53 53" style="enable-background:new 0 0 53 53;" xml:space="preserve"%3E%3Cstyle type="text/css"%3E .st0%7Bdisplay:none;%7D .st1%7Bdisplay:inline;%7D .st2%7Bclip-path:url(%23SVGID_00000142154616827085436530000012698217856111301567_);%7D .st3%7Bfill:%2372AEE6;%7D .st4%7Bdisplay:none;fill:%23FFFFFF;%7D .st5%7Bfill:none;stroke:%2372AEE6;stroke-width:3;stroke-miterlimit:10;%7D .st6%7Bfill:none;stroke:%2372AEE6;stroke-width:2;stroke-miterlimit:10;%7D%0A%3C/style%3E%3Cg id="Layer_2_00000047770719710110742230000003923951626148849557_" class="st0"%3E%3Crect class="st1" width="53.1" height="53.1"/%3E%3C/g%3E%3Cg id="Layer_1_00000162333103265806981530000017146624247591674556_"%3E%3Cg%3E%3Cg%3E%3Cdefs%3E%3Cpath id="SVGID_1_" d="M0,0h53v53H0V0z M23.3,37.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5 C20.8,36.1,21.9,37.2,23.3,37.2z M33.4,27.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5S32,27.2,33.4,27.2z M23,22.8c1.6,0,2.9-1.3,2.9-2.9S24.6,17,23,17s-2.9,1.3-2.9,2.9C20.2,21.5,21.5,22.8,23,22.8z"/%3E%3C/defs%3E%3CclipPath id="SVGID_00000111880200341027563210000003406718579453459379_"%3E%3Cuse xlink:href="%23SVGID_1_" style="overflow:visible;"/%3E%3C/clipPath%3E%3Cg id="BarsClipped" style="clip-path:url(%23SVGID_00000111880200341027563210000003406718579453459379_);"%3E%3Cpath class="st3" d="M39.9,31.5L18,37.3c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C40.8,30.7,40.5,31.3,39.9,31.5z"/%3E%3Cpath class="st3" d="M38.1,24.6l-21.9,5.9c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C39,23.8,38.7,24.5,38.1,24.6z"/%3E%3Cpath class="st3" d="M36.2,17.9l-21.9,5.9c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C37.2,17.1,36.8,17.7,36.2,17.9z"/%3E%3C/g%3E%3C/g%3E%3C/g%3E%3Cpath class="st4" d="M23.3,37.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5C20.8,36.1,21.9,37.2,23.3,37.2z"/%3E%3Cpath class="st4" d="M33.4,27.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5S32,27.2,33.4,27.2z"/%3E%3Cpath class="st4" d="M23,22.8c1.6,0,2.9-1.3,2.9-2.9S24.6,17,23,17s-2.9,1.3-2.9,2.9C20.2,21.5,21.5,22.8,23,22.8z"/%3E%3Cpath class="st4" d="M23.9,38.2c-1.9,0.5-3.8-0.6-4.3-2.5c-0.5-1.9,0.6-3.8,2.5-4.3s3.8,0.6,4.3,2.5C26.9,35.8,25.8,37.7,23.9,38.2 z M22.6,33.2c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C24.3,33.5,23.4,33,22.6,33.2z"/%3E%3Cpath class="st4" d="M34.1,28.2c-1.9,0.5-3.8-0.6-4.3-2.5s0.6-3.8,2.5-4.3c1.9-0.5,3.8,0.6,4.3,2.5C37.1,25.8,36,27.7,34.1,28.2z M32.8,23.2c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C34.5,23.5,33.6,23,32.8,23.2z"/%3E%3Cpath class="st4" d="M24.2,23.5c-1.9,0.5-3.8-0.6-4.3-2.5s0.6-3.8,2.5-4.3s3.8,0.6,4.3,2.5S26.1,23,24.2,23.5z M22.9,18.6 c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C24.7,18.8,23.8,18.3,22.9,18.6z"/%3E%3Cpath class="st5" d="M26.5,51.5c13.8,0,25-11.2,25-25s-11.2-25-25-25s-25,11.2-25,25S12.7,51.5,26.5,51.5z"/%3E%3Cpath class="st4" d="M33.3,21h10c0.4,0,0.8-0.3,0.8-0.8s-0.3-0.8-0.8-0.8h-10C33.3,20.2,33.3,20.2,33.3,21z"/%3E%3C/g%3E%3Ccircle class="st6" cx="23.3" cy="20.1" r="2.5"/%3E%3Ccircle class="st6" cx="33.2" cy="24.8" r="2.5"/%3E%3Ccircle class="st6" cx="23" cy="34.8" r="2.5"/%3E%3C/svg%3E');
965 }
966 .wp-menu-open#toplevel_page_edit-post_type-filter-set .wp-menu-image {
967 background-image: url('data:image/svg+xml,%3C%3Fxml version="1.0" encoding="utf-8"%3F%3E%3C!-- --%3E%3Csvg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 53 53" style="enable-background:new 0 0 53 53;" xml:space="preserve"%3E%3Cstyle type="text/css"%3E .st0%7Bdisplay:none;%7D .st1%7Bdisplay:inline;%7D .st2%7Bclip-path:url(%23SVGID_00000098199702249043298830000017010845528166695064_);%7D .st3%7Bfill:%23FFFFFF;%7D .st4%7Bdisplay:none;fill:%23FFFFFF;%7D .st5%7Bfill:none;stroke:%23FFFFFF;stroke-width:3;stroke-miterlimit:10;%7D .st6%7Bfill:none;stroke:%23FFFFFF;stroke-width:2;stroke-miterlimit:10;%7D%0A%3C/style%3E%3Cg id="Layer_2_00000047770719710110742230000003923951626148849557_" class="st0"%3E%3Crect x="0" y="0" class="st1" width="53.1" height="53.1"/%3E%3C/g%3E%3Cg id="Layer_1_00000162333103265806981530000017146624247591674556_"%3E%3Cg%3E%3Cdefs%3E%3Cpath id="SVGID_1_" d="M0,0h53v53H0V0z M23.3,37.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5 C20.8,36.1,21.9,37.2,23.3,37.2z M33.4,27.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5S32,27.2,33.4,27.2z M23,22.8c1.6,0,2.9-1.3,2.9-2.9S24.6,17,23,17s-2.9,1.3-2.9,2.9C20.2,21.5,21.5,22.8,23,22.8z"/%3E%3C/defs%3E%3CclipPath id="SVGID_00000112608340804245442460000013986219178199086244_"%3E%3Cuse xlink:href="%23SVGID_1_" style="overflow:visible;"/%3E%3C/clipPath%3E%3Cg id="BarsClipped" style="clip-path:url(%23SVGID_00000112608340804245442460000013986219178199086244_);"%3E%3Cpath class="st3" d="M39.9,31.5L18,37.3c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C40.8,30.7,40.5,31.3,39.9,31.5z"/%3E%3Cpath class="st3" d="M38.1,24.6l-21.9,5.9c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C39,23.8,38.7,24.5,38.1,24.6z"/%3E%3Cpath class="st3" d="M36.2,17.9l-21.9,5.9c-0.6,0.2-1.2-0.2-1.4-0.8c-0.2-0.6,0.2-1.2,0.8-1.4l21.9-5.9c0.6-0.2,1.2,0.2,1.4,0.8 C37.2,17.1,36.8,17.7,36.2,17.9z"/%3E%3C/g%3E%3C/g%3E%3Cpath class="st4" d="M23.3,37.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5C20.8,36.1,21.9,37.2,23.3,37.2z"/%3E%3Cpath class="st4" d="M33.4,27.2c1.4,0,2.5-1.1,2.5-2.5s-1.1-2.5-2.5-2.5s-2.5,1.1-2.5,2.5S32,27.2,33.4,27.2z"/%3E%3Cpath class="st4" d="M23,22.8c1.6,0,2.9-1.3,2.9-2.9S24.6,17,23,17s-2.9,1.3-2.9,2.9C20.2,21.5,21.5,22.8,23,22.8z"/%3E%3Cpath class="st4" d="M23.9,38.2c-1.9,0.5-3.8-0.6-4.3-2.5c-0.5-1.9,0.6-3.8,2.5-4.3s3.8,0.6,4.3,2.5C26.9,35.8,25.8,37.7,23.9,38.2 z M22.6,33.2c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C24.3,33.5,23.4,33,22.6,33.2z"/%3E%3Cpath class="st4" d="M34.1,28.2c-1.9,0.5-3.8-0.6-4.3-2.5s0.6-3.8,2.5-4.3c1.9-0.5,3.8,0.6,4.3,2.5C37.1,25.8,36,27.7,34.1,28.2z M32.8,23.2c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C34.5,23.5,33.6,23,32.8,23.2z"/%3E%3Cpath class="st4" d="M24.2,23.5c-1.9,0.5-3.8-0.6-4.3-2.5s0.6-3.8,2.5-4.3s3.8,0.6,4.3,2.5S26.1,23,24.2,23.5z M22.9,18.6 c-0.9,0.2-1.4,1.1-1.1,2c0.2,0.9,1.1,1.4,2,1.1c0.9-0.2,1.4-1.1,1.1-2C24.7,18.8,23.8,18.3,22.9,18.6z"/%3E%3Cpath class="st5" d="M26.5,51.5c13.8,0,25-11.2,25-25s-11.2-25-25-25s-25,11.2-25,25S12.7,51.5,26.5,51.5z"/%3E%3Cpath class="st4" d="M33.3,21h10c0.4,0,0.8-0.3,0.8-0.8s-0.3-0.8-0.8-0.8h-10C33.3,20.2,33.3,20.2,33.3,21z"/%3E%3C/g%3E%3Ccircle class="st6" cx="23.3" cy="20.1" r="2.5"/%3E%3Ccircle class="st6" cx="33.2" cy="24.8" r="2.5"/%3E%3Ccircle class="st6" cx="23" cy="34.8" r="2.5"/%3E%3C/svg%3E');
968 }
969 PHP_CSS;
970 wp_add_inline_style($handle, $css);
971 });
972
973 /**
974 * Fix Elementor query arguments for filtered content
975 *
976 * This function adjusts Elementor's query arguments when dealing with
977 * filtered content from Filter Everything Pro plugin. It ensures proper
978 * handling of custom post types in Elementor queries.
979 *
980 * @param array $query_args The Elementor query arguments
981 * @return array Modified query arguments
982 */
983 add_filter( 'elementor/query/get_query_args/current_query', 'flrt_fix_elementor_query_args' );
984 function flrt_fix_elementor_query_args( $query_args ) {
985 // Verify that we're dealing with a filtered query
986 if ( ! isset( $query_args['flrt_filtered_query'] ) || !$query_args['flrt_filtered_query'] ) {
987 return $query_args;
988 }
989
990 // Get post type from query args or current post
991 $post_type = isset( $query_args['post_type'] ) ? $query_args['post_type'] : get_post_type();
992
993 // Sanitize the post type
994 if ( ! empty( $post_type ) ) {
995 $post_type = sanitize_text_field( $post_type );
996 }
997
998 // Check if the post type is non-built-in
999 $post_type_object = get_post_type_object( $post_type );
1000
1001 if ( $post_type_object && !$post_type_object->_builtin ) {
1002 // Remove taxonomy from query args if present
1003 if ( isset( $query_args['taxonomy'] ) ) {
1004 unset( $query_args['taxonomy'] );
1005 }
1006 }
1007
1008 return $query_args;
1009 }
1010
1011 /**
1012 * Fixes Elementor featured products price range query arguments.
1013 *
1014 * This function addresses an issue where Elementor's featured products widget
1015 * incorrectly applies meta_key filtering when sorting by price, which can
1016 * interfere with price range filtering functionality. It removes the meta_key
1017 * from query arguments for featured products sorted by price.
1018 *
1019 *
1020 * @param array $query_args Query arguments for Elementor widget.
1021 * @param object $widget The Elementor widget instance.
1022 * @return array Modified query arguments.
1023 */
1024 if ( flrt_is_elementor_active() ) {
1025 add_filter( 'elementor/query/query_args', 'flrt_fix_elementor_featured_products_price_range', 10, 2 );
1026
1027 function flrt_fix_elementor_featured_products_price_range( array $query_args, $widget ): array {
1028 $is_featured = ( $query_args['post_type'] ?? '' ) === 'featured';
1029 $is_price_order = ( $query_args['orderby'] ?? '' ) === 'price';
1030
1031 if ( $is_featured && $is_price_order ) {
1032 static $registered = false;
1033
1034 if ( ! $registered ) {
1035 add_filter( 'elementor/query/query_args', function ( array $query_args, $widget ): array {
1036 unset( $query_args['meta_key'] );
1037 return $query_args;
1038 }, 11, 2 );
1039
1040 $registered = true;
1041 }
1042 }
1043
1044 return $query_args;
1045 }
1046 }
1047
1048
1049
1050 function flrt_is_divi_theme()
1051 {
1052 if ( 'Divi' === wp_get_theme()->get('Name') || 'Divi' === wp_get_theme()->get_template() ) {
1053 return true;
1054 }
1055 return false;
1056 }
1057
1058 if ( flrt_is_divi_theme() ) {
1059
1060 function wpc_initialize_divi_custom_module() {
1061 if (!class_exists('ET_Builder_Module')) {
1062 return;
1063 }
1064
1065 flrt_include('src/Frontend/Builders/DiviWidgets/ChipsDiviWidget.php');
1066 flrt_include('src/Frontend/Builders/DiviWidgets/FiltersDiviWidget.php');
1067 flrt_include('src/Frontend/Builders/DiviWidgets/SortingDiviWidget.php');
1068 }
1069
1070 add_action('et_builder_ready', 'wpc_initialize_divi_custom_module');
1071
1072 add_filter( 'et_builder_inner_content_class', function ($classes){
1073 $classes[] = 'wpc-divi-inner-content';
1074 return $classes;
1075 }, 10 );
1076
1077 if( flrt_get_option('mobile_filter_settings') === 'show_bottom_widget' ) {
1078 if (flrt_get_experimental_option('disable_buttons') !== 'on') {
1079 add_action('et_before_main_content', 'flrt_divi_filter_button');
1080 }
1081 }
1082 }
1083
1084 function flrt_divi_filter_button()
1085 {
1086 // et_before_main_content fires more than once per page when a Divi Theme
1087 // Builder header layout is present (both header.php and
1088 // theme-after-header.php do_action it), so nothing here may declare a
1089 // function at runtime — the previous nested declaration fataled with
1090 // "Cannot redeclare modify_specific_module" on the second call.
1091 // Re-adding the same filter callback is a no-op in WordPress.
1092 add_filter('et_module_process_display_conditions', 'flrt_divi_modify_specific_module', 10, 3);
1093 }
1094
1095 function flrt_divi_modify_specific_module($output, $render_slug, $module)
1096 {
1097 if ($module->slug === 'filter_everything') {
1098 flrt_filters_button(0, '', 'et_before_main_content');
1099 }
1100 return $output;
1101 }
1102 /**
1103 * Checks if the Breakdance plugin and its required classes/functions are active and exist.
1104 *
1105 * This function verifies the presence of the Breakdance plugin, along with specific
1106 * classes and functions used by the plugin. It returns true only if all checks pass,
1107 * indicating that Breakdance is properly installed and functional.
1108 *
1109 * @return bool True if Breakdance is active and its required components exist, false otherwise.
1110 */
1111 function flrt_check_breakdance() {
1112 // is_plugin_active() lives in wp-admin/includes/plugin.php and is not loaded
1113 // on the frontend, in WP-CLI or in cron. Fall back to the raw option list.
1114 if ( ! function_exists( 'is_plugin_active' ) ) {
1115 $active = (array) get_option( 'active_plugins', [] );
1116 if ( is_multisite() ) {
1117 $active = array_merge( $active, array_keys( (array) get_site_option( 'active_sitewide_plugins', [] ) ) );
1118 }
1119 if ( ! in_array( 'breakdance/plugin.php', $active, true ) ) {
1120 return false;
1121 }
1122 } elseif ( ! is_plugin_active( 'breakdance/plugin.php' ) ) {
1123 return false;
1124 }
1125
1126 if (!function_exists('Breakdance\Util\getDirectoryPathRelativeToPluginFolder')) {
1127 return false;
1128 }
1129
1130 return true;
1131 }
1132 if(flrt_check_breakdance()){
1133 function flrt_breakdance_custom_css() {
1134 echo '<style>
1135 .breakdance-add-panel__element{
1136 background: #0A2D48;
1137 }
1138 </style>';
1139 }
1140 add_action('wp_head', 'flrt_breakdance_custom_css');
1141 flrt_include('src/Frontend/Builders/breakdance/widgets/breakdance.php');
1142 }
1143
1144 /**
1145 * Checks if Bricks Builder theme and its classes are ready to register custom elements.
1146 *
1147 * @return bool True if Bricks Builder theme is active and necessary classes exist, false otherwise.
1148 */
1149 function flrt_is_bricks_ready_for_elements() {
1150 $theme = wp_get_theme();
1151
1152 if (
1153 $theme->get_stylesheet() !== 'bricks' &&
1154 $theme->get_template() !== 'bricks'
1155 ) {
1156 return false;
1157 }
1158
1159 if ( ! class_exists( '\Bricks\Elements' ) ) {
1160 return false;
1161 }
1162
1163 if ( ! method_exists( '\Bricks\Elements', 'register_element' ) ) {
1164 return false;
1165 }
1166
1167 return true;
1168 }
1169
1170 /**
1171 * Registers custom Bricks elements during WordPress initialization.
1172 *
1173 * This function checks if Bricks Builder is ready using flrt_is_bricks_ready_for_elements().
1174 * If it is, it includes the ChipsBricksWidget.php file and registers the element using Bricks\Elements::register_element().
1175 */
1176
1177 add_action('init', 'flrt_init_bricks_widgets', 11);
1178
1179 function flrt_init_bricks_widgets() {
1180 if (flrt_is_bricks_ready_for_elements()) {
1181 $element_files = [
1182 FLRT_PLUGIN_DIR_PATH .'src/Frontend/Builders/bricks/ChipsBricksWidget.php',
1183 FLRT_PLUGIN_DIR_PATH .'src/Frontend/Builders/bricks/FiltersBricksWidget.php',
1184 FLRT_PLUGIN_DIR_PATH .'src/Frontend/Builders/bricks/SortingBricksWidget.php',
1185 ];
1186 foreach ($element_files as $file) {
1187 \Bricks\Elements::register_element($file);
1188 }
1189
1190 add_filter( 'bricks/builder/i18n', function( $i18n ) {
1191 $i18n['filter-everything'] = esc_html__( 'Filter Everything', 'filter-everything' );
1192 return $i18n;
1193 } );
1194
1195 function flrt_bricks_custom_css() {
1196 echo '<style>
1197 .wpc-fe-icon {
1198 background: var(--builder-color);
1199 mask-image: url(' . flrt_get_icon_logo_svg_css() . ');
1200 mask-repeat: no-repeat;
1201 mask-size: contain;
1202 display: inline-block;
1203 width: 28px;
1204 height: 28px;
1205 margin-bottom: -5px;
1206 }
1207
1208 .bricks-add-element:focus .wpc-fe-icon, .bricks-add-element:hover .wpc-fe-icon {
1209 background: var(--builder-color-accent);
1210 }
1211
1212 .structure-item .wpc-fe-icon {
1213 width: 16px;
1214 height: 16px;
1215 margin-bottom: 0px;
1216 }
1217 </style>';
1218 }
1219 add_action('wp_head', 'flrt_bricks_custom_css');
1220 }
1221 }
1222
1223 function wpc_beaver_builder_widgets_load() {
1224 if ( class_exists( 'FLBuilder' ) ) {
1225 flrt_include('src/Frontend/Builders/beaver/chips/ChipsBeaverWidget.php');
1226 flrt_include('src/Frontend/Builders/beaver/filters/FiltersBeaverWidget.php');
1227 flrt_include('src/Frontend/Builders/beaver/sorting/SortingBeaverWidget.php');
1228 }
1229 }
1230 add_action( 'init', 'wpc_beaver_builder_widgets_load' );
1231
1232 /**
1233 * XStore theme — "Display variable products as single variations" compatibility.
1234 *
1235 * With that XStore option (variable_products_detach) the theme:
1236 * 1. adds 'product_variation' to the shop query's post_type, hides variable
1237 * parents via post__not_in and flags the query with single_variations_filter=yes;
1238 * 2. on posts_clauses (priority 20) appends a TOP-LEVEL
1239 * "OR ( post_type='product_variation' AND post_status='publish' AND … )"
1240 * branch, re-implementing WooCommerce's own layered-nav filters for the
1241 * detached variations (price, rating, brand, chosen attributes from $_GET).
1242 *
1243 * The theme knows nothing about Filter Everything, so on FE-filtered pages that
1244 * OR branch let EVERY published variation into the results, past FE's term
1245 * constraints — filtering visually "did nothing" (each alternative of a
1246 * top-level OR must repeat the filter conditions).
1247 *
1248 * Fix: append FE's active filter constraints AFTER the theme's branch
1249 * (priority 30). AND binds tighter than OR, so in
1250 * <first alternative> OR ( <theme branch> ) AND ( <FE constraints> )
1251 * the constraints apply to the variations branch only, leaving the first
1252 * alternative (already filtered by FE the regular way) untouched.
1253 */
1254 function flrt_xstore_detached_variations_where( $clauses, $wp_query ) {
1255 global $wpdb;
1256
1257 if ( is_admin() || empty( $clauses['where'] ) ) {
1258 return $clauses;
1259 }
1260
1261 // Only XStore "detached variations" queries that FE has actually filtered.
1262 if ( $wp_query->get( 'single_variations_filter' ) !== 'yes' || ! $wp_query->get( 'flrt_filtered_query' ) ) {
1263 return $clauses;
1264 }
1265
1266 // The theme adds its branch at priority 20 — bail if it is not there.
1267 if ( strpos( $clauses['where'], "OR ({$wpdb->posts}.post_type = 'product_variation'" ) === false ) {
1268 return $clauses;
1269 }
1270
1271 $wpManager = \FilterEverything\Filter\Container::instance()->getWpManager();
1272 $queried_values = $wpManager->getQueryVar( 'queried_values' );
1273
1274 if ( empty( $queried_values ) || ! is_array( $queried_values ) ) {
1275 return $clauses;
1276 }
1277
1278 $conditions = [];
1279
1280 foreach ( $queried_values as $queried ) {
1281
1282 if ( ! isset( $queried['entity'], $queried['e_name'] ) ) {
1283 continue;
1284 }
1285
1286 // Taxonomy filters: a variation matches when its PARENT product carries
1287 // the term (variations have no term_relationships rows of their own).
1288 if ( $queried['entity'] === 'taxonomy' && ! empty( $queried['values'] ) ) {
1289 $tax = $queried['e_name'];
1290 $and_logic = ( isset( $queried['logic'] ) && $queried['logic'] === 'and' );
1291 $groups = []; // one ttid-group per condition: single for OR-logic, per-term for AND-logic
1292 $slugs = [];
1293
1294 foreach ( (array) $queried['values'] as $value_slug ) {
1295 $term = get_term_by( 'slug', $value_slug, $tax );
1296 if ( ! $term ) {
1297 continue;
1298 }
1299 $slugs[] = esc_sql( $term->slug );
1300
1301 $ttids = [ (int) $term->term_taxonomy_id ];
1302 if ( is_taxonomy_hierarchical( $tax ) && ! $and_logic ) {
1303 foreach ( get_term_children( $term->term_id, $tax ) as $child_id ) {
1304 $child = get_term( $child_id, $tax );
1305 if ( $child && ! is_wp_error( $child ) ) {
1306 $ttids[] = (int) $child->term_taxonomy_id;
1307 }
1308 }
1309 }
1310
1311 if ( $and_logic ) {
1312 $groups[] = $ttids; // every term required — own condition each
1313 } elseif ( empty( $groups ) ) {
1314 $groups[] = $ttids; // any term enough — collect into one IN()
1315 } else {
1316 $groups[0] = array_merge( $groups[0], $ttids );
1317 }
1318 }
1319
1320 if ( empty( $groups ) ) {
1321 continue;
1322 }
1323
1324 foreach ( $groups as $group_ttids ) {
1325 $ttids_in = implode( ',', array_unique( $group_ttids ) );
1326 $parent_has_term = "{$wpdb->posts}.post_parent IN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ({$ttids_in}) )";
1327
1328 if ( strpos( $tax, 'pa_' ) === 0 && ! $and_logic && ! empty( $slugs ) ) {
1329 // Variation attributes: prefer the variation's own value —
1330 // a variation with a DIFFERENT value must not ride in on its
1331 // parent's term. Variations without own value ("Any …")
1332 // fall back to the parent's term.
1333 $meta_key = esc_sql( 'attribute_' . $tax );
1334 $slugs_in = "'" . implode( "','", $slugs ) . "'";
1335
1336 $conditions[] = "( {$wpdb->posts}.ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '{$meta_key}' AND meta_value IN ({$slugs_in}) )"
1337 . " OR ( {$parent_has_term}"
1338 . " AND {$wpdb->posts}.ID NOT IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '{$meta_key}' AND meta_value <> '' ) ) )";
1339 } else {
1340 $conditions[] = $parent_has_term;
1341 }
1342 }
1343 }
1344
1345 // Numeric meta filters (price and alike): variations carry their own value.
1346 if ( $queried['entity'] === 'post_meta_num' && isset( $queried['values'] ) && is_array( $queried['values'] ) ) {
1347 $meta_key = esc_sql( $queried['e_name'] );
1348 $min = ( isset( $queried['values']['min'] ) && $queried['values']['min'] !== '' ) ? (float) $queried['values']['min'] : false;
1349 $max = ( isset( $queried['values']['max'] ) && $queried['values']['max'] !== '' ) ? (float) $queried['values']['max'] : false;
1350
1351 $range = [];
1352 if ( $min !== false ) {
1353 $range[] = "CAST(meta_value AS DECIMAL(15,6)) >= {$min}";
1354 }
1355 if ( $max !== false ) {
1356 $range[] = "CAST(meta_value AS DECIMAL(15,6)) <= {$max}";
1357 }
1358
1359 if ( $range ) {
1360 $conditions[] = "{$wpdb->posts}.ID IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '{$meta_key}' AND " . implode( ' AND ', $range ) . " )";
1361 }
1362 }
1363
1364 // Other filter entities (post_meta choices, author, post_date …) are not
1365 // mirrored into the variations branch yet — they are rare on shop archives.
1366 }
1367
1368 if ( ! empty( $conditions ) ) {
1369 $clauses['where'] .= ' AND ( ' . implode( ' ) AND ( ', $conditions ) . ' )';
1370 }
1371
1372 return $clauses;
1373 }
1374 add_filter( 'posts_clauses', 'flrt_xstore_detached_variations_where', 30, 2 );
1375
1376 //@todo check this with PLL support
1377 //function flrt_add_cpt_to_pll_tmp( $post_types, $is_settings ) {
1378 // if ( $is_settings ) {
1379 // $post_types[ FLRT_FILTERS_SET_POST_TYPE ] = FLRT_FILTERS_SET_POST_TYPE;
1380 // }
1381 // return $post_types;
1382 //}