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 / WpManager.php

WpManager.php in Filter Everything — WordPress & WooCommerce Filters 1.9.7, at src/WpManager.php

1,183 lines 46.0 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('ABSPATH') ) {
6 exit;
7 }
8
9 class WpManager
10 {
11 private $requestParser;
12
13 /** @var FilterContext */
14 private $context;
15
16 private $em;
17 private static $fqcn;
18 private static $is;
19 private static $m;
20 private static $mg;
21
22 public function init()
23 {
24 global $wp_rewrite;
25
26 if ( ! defined( 'FLRT_PERMALINKS_ENABLED' ) ) {
27 define( 'FLRT_PERMALINKS_ENABLED', flrt_permalinks_enabled() );
28 }
29
30 if ( ! defined('FLRT_SET_TRANSIENT_ENABLED')){
31 define( 'FLRT_SET_TRANSIENT_ENABLED', true );
32 }
33
34 self::$fqcn = 'FilterEverything\\Filter\\WP_Query_Source_Detector';
35 self::$is = 'is_allowed';
36 self::$m = 'identify_query_source';
37 self::$mg = 'get_query_builder_name';
38
39 $this->requestParser = new RequestParser( $this->prepareRequest() );
40 $this->context = Container::instance()->getFilterContext();
41 $this->em = Container::instance()->getEntityManager();
42 }
43
44 public function parseRequest($WP)
45 {
46 if ( $this->requestParser->detectFilterRequest() ) {
47 foreach ( $this->requestParser->getQueryVars() as $key => $queryVar ) {
48 $this->setQueryVar( $key, $queryVar );
49 }
50
51 $this->context->markFilterRequest();
52 $this->setQueryVar('wpc_is_filter_request', true );
53
54 if ( $this->getQueryVar('error') === '404' ) {
55 $WP->set_query_var( 'error', '404' );
56 return false;
57 }
58
59 /**
60 * Although we disabled redirect to canonical on filtering result pages
61 * The problem with trailing slash (when /color-blue/ and /color-blue load the same page)
62 * should not be a problem because by default all these pages are closed from indexing
63 * via meta robots tag.
64 * Also pages with wrong trailing slash that have SEO Rules and are opened for indexing
65 * contain correct canonical link in their HTML code.
66 * But to avoid extra questions from users we added our custom 301 redirect to
67 * correct trailing slash URL.
68 *
69 * To disable this redirect please use
70 * add_action('wp', 'my_init');
71 * function my_init(){
72 * remove_action( 'template_redirect', [ 'FilterEverything\Filter\WpManager', 'redirectCanonical' ] );
73 * }
74 */
75 remove_action( 'template_redirect', 'redirect_canonical' );
76 add_action( 'template_redirect', [ __CLASS__, 'redirectCanonical' ] );
77 }
78 }
79
80 /**
81 * Checks if requested date/time matches to the registered filters date/time format
82 * @return bool false if the format is invalid
83 */
84 public function isValidRequestedDateFormat()
85 { // Main goal is to detect if queried date format does not match to the existing date filters format
86 // How to check it?
87 // Get queried date formats and compare it with related filters format
88 $valid = true;
89 $date_types = [];
90 $stored_date_types = [];
91 $queried_filters = $this->getQueryVar( 'queried_values', [] );
92
93 if ( ! empty( $queried_filters ) ) {
94
95 foreach ( $queried_filters as $slug => $filter ) {
96 if ( $filter['entity'] === 'post_date' || $filter['entity'] === 'post_meta_date') {
97 $date_filters[$slug] = $filter;
98 if ( isset( $filter['values']['from'] ) && $filter['values']['from'] ) {
99 $date_types[] = flrt_detect_date_type( $filter['values']['from'] );
100 }
101 if ( isset( $filter['values']['to'] ) && $filter['values']['to'] ) {
102 $date_types[] = flrt_detect_date_type( $filter['values']['to'] );
103 }
104 }
105 }
106
107 $date_types = array_unique( $date_types );
108 }
109
110 $related_filters = $this->em->getSetsRelatedFilters( $sets = [] );
111
112 if ( ! empty( $related_filters ) ) {
113 $stored_date_types = [];
114 foreach ( $related_filters as $filter ) {
115 if ( $filter['entity'] === 'post_date' || $filter['entity'] === 'post_meta_date') {
116 $stored_date_types[] = $filter['date_type'];
117 }
118 }
119 $stored_date_types = array_flip( $stored_date_types );
120 }
121
122 if ( ! empty( $date_types ) && ! empty( $stored_date_types ) ) {
123 foreach ( $date_types as $date_type ) {
124 if ( ! isset( $stored_date_types[$date_type] ) ) {
125 $valid = false;
126 break; // this means that requested URL is not valid
127 }
128 }
129 }
130
131 return $valid;
132 }
133
134 public static function redirectCanonical()
135 {
136 // We do not need to check for is_admin() because this works only in frontend
137 $permalinksOn = defined('FLRT_PERMALINKS_ENABLED') ? FLRT_PERMALINKS_ENABLED : false;
138 if ( ! $permalinksOn ) {
139 return true;
140 }
141
142 $requested_url = is_ssl() ? 'https://' : 'http://';
143 $requested_url .= $_SERVER['HTTP_HOST'];
144 $requested_url .= $_SERVER['REQUEST_URI'];
145
146 $original = parse_url( $requested_url );
147 if ( false === $original ) {
148 return;
149 }
150
151 // Notice fixing.
152 if ( ! isset( $original['path'] ) ) {
153 $original['path'] = '';
154 }
155 if ( ! isset( $original['query'] ) ) {
156 $original['query'] = '';
157 }
158 if ( ! isset( $original['scheme'] ) ) {
159 $original['scheme'] = is_ssl() ? 'https' : 'http';
160 }
161
162 $correct_path = user_trailingslashit( $original['path'] );
163
164 // 301 redirect if the path is wrong
165 if ( $correct_path !== $original['path'] && $original['path'] !== '/' ) {
166 $redirect_url = $original['scheme'] . '://' . $original['host'] . $correct_path;
167 if ( $original['query'] !== '' ) {
168 $redirect_url .= '?' . $original['query'];
169 }
170
171 wp_redirect( $redirect_url, 301 );
172 exit;
173 }
174 }
175
176 public function addFilterQueryToWpQuery( $wp_query )
177 {
178 // The main difference is that we need to detect relevantSetId:
179 // - one time and store it into the FilterContext
180 // - do it before comparing with the current query
181 $fqcn = self::$fqcn;
182 $m = self::$m;
183
184 $source = $fqcn::$m($wp_query);
185 $wp_query->set('flrt_detected_source', $source);
186
187 $this->collectWPQueries( $wp_query );
188 if ( $wp_query->is_main_query() && $this->context->isMainQueryPending() ) {
189 $filterSet = Container::instance()->getFilterSetService();
190
191 // Set global filters vars
192 $this->setQueryVar('wp_queried_object', $this->identifyWpQueriedObject($wp_query) );
193 $sets = $filterSet->findRelevantSets( $this->getQueryVar('wp_queried_object') );
194
195 // Queue the sets for the widgets (consumed by flrt_the_set())
196 $this->context->setSets( $sets );
197 $this->setQueryVar('wpc_page_related_set_ids', $sets);
198
199 do_action( 'wpc_related_set_ids', $sets );
200
201 if( $this->isFilterRequest() ){
202
203 if (!$filterSet->validateSets($sets)) {
204 self::make_404($wp_query, 'Invalid Set Ids');
205 return true;
206 }
207
208 /**
209 * We couldn't do this earlier because we didn't know
210 * what exact filter set was queried for this post type.
211 * We only knew, that some filter with some exact slug was
212 * requested.
213 */
214 // Here we should fill queried_values with correct logic
215 if ( ! $this->populateQueriedValuesWithAdditionalParams( $sets ) ) {
216 self::make_404($wp_query, 'Forbidden filter requested 2');
217 return true;
218 }
219
220 // Now we have correct logic separator in queried filter and can validate requested separators
221 if (!$this->validateFiltersLogic()) {
222 self::make_404($wp_query, 'Incorrect logic separator');
223 return true;
224 }
225
226 /**
227 * Validate situations, when /param-value/ and /?param=value is not correct
228 */
229 if (FLRT_PERMALINKS_ENABLED) {
230 if (!$this->validateFiltersPosition()) {
231 self::make_404($wp_query, 'Term is not in correct part of URL');
232 return true;
233 }
234 }
235
236 if (!$this->em->checkForbiddenFilters($this->getQueryVar('queried_values'), $this->em->getOnlyBelongsFilters($sets))) {
237 self::make_404($wp_query, 'Forbidden filter requested');
238 return true;
239 }
240
241 if ( ! $this->isValidRequestedDateFormat() ) {
242 self::make_404( $wp_query, 'Invalid date/time format requested');
243 return true;
244 }
245 }
246 // This section must never run again for this request
247 $this->context->markMainQueryHandled();
248 }
249
250 // This should be an array!
251 $setIds = $this->isFilteredQuery( $wp_query );
252 // if $setIds not empty it means, that current query is filtered query
253 if ( ! empty( $setIds ) ){
254
255 //Clone and store this object to use it in the future
256 $to_save = clone $wp_query;
257 foreach ( $setIds as $setId ){
258 // If there are two or more sets related with the same $wp_query
259 // It should be stored in object two or more times with different setId
260 $this->setQueryVar('wpc_set_filter_query_' . $setId, $to_save);
261 }
262 unset($to_save);
263 }
264
265 if ( ! empty( $setIds ) && $this->isFilterRequest() ) {
266
267 /**
268 * Finally all right and we can impact core Wordpress query
269 */
270 $em = Container::instance()->getEntityManager();
271 $set_filter_keys = $em->getSetFilterKeys( $setIds );
272
273 foreach ( $this->getQueryVar('queried_values' ) as $queried_value ) {
274 $queried_value_key = $queried_value['entity'].'#'.$queried_value['e_name'];
275
276 if( ! $wp_query->get( 'flrt_query_clone' ) && in_array( $queried_value_key, $set_filter_keys ) ){
277
278 $do_filter_request = apply_filters( 'wpc_do_filter_request', true, $queried_value, $wp_query );
279
280 if ( $do_filter_request ) {
281 $wpc_main_query = $this->em->addTermsToWpQuery( $queried_value, $wp_query );
282 } else {
283 $wpc_main_query = $wp_query;
284 }
285
286 if( method_exists( $wpc_main_query , 'set') ){
287 $wpc_main_query->set( 'flrt_filtered_query', true );
288 }
289
290 if ( ! ( $wpc_main_query instanceof \WP_Query ) ) {
291 return true;
292 }
293 }
294 }
295 }
296
297 // Filter $wp_query after adding filtering terms
298 if ( ! empty( $setIds ) && ! $wp_query->get('flrt_query_clone') ) {
299 do_action( 'wpc_filtered_query_end', $wp_query );
300 }
301
302 }
303
304 private function isFilteredQuery( $query )
305 {
306 return apply_filters( 'wpc_is_check_errors_pro', [], $query );
307 }
308
309
310 /**
311 * @return bool
312 */
313 private function validateFiltersLogic()
314 {
315 $queriedValues = $this->getQueryVar('queried_values');
316 foreach ($this->getQueryVar('wpc_logic_separators') as $slug => $logic) {
317 if ($queriedValues[$slug]['logic'] !== $logic) {
318 return false;
319 }
320 }
321 return true;
322 }
323
324 private function validateFiltersPosition()
325 {
326 foreach ($this->getQueryVar('queried_values') as $slug => $filterParams ) {
327 if ($filterParams['in_path'] !== $filterParams['founded_in_path']) {
328 return false;
329 }
330 }
331 return true;
332 }
333
334 /**
335 * @param array $sets
336 */
337 private function populateQueriedValuesWithAdditionalParams($sets)
338 {
339 $queriedValues = $this->getQueryVar('queried_values');
340 $relatedFilters = $this->em->getOnlyBelongsFilters($sets);
341
342 $queriedValuesWithLogic = [];
343
344 foreach ($relatedFilters as $filter) {
345 $slug = $filter['slug'];
346
347 if ( isset( $queriedValues[$slug] ) ) {
348 $queriedValuesWithLogic[$slug] = $queriedValues[$slug];
349 $queriedValuesWithLogic[$slug]['logic'] = $filter['logic'];
350 $queriedValuesWithLogic[$slug]['show_chips'] = $filter['show_chips'];
351 $queriedValuesWithLogic[$slug]['in_path'] = $filter['in_path'];
352 $queriedValuesWithLogic[$slug]['label'] = $filter['label'];
353 $queriedValuesWithLogic[$slug]['used_for_variations'] = $filter['used_for_variations'];
354 $queriedValuesWithLogic[$slug]['min_num_label'] = $filter['min_num_label'];
355 $queriedValuesWithLogic[$slug]['max_num_label'] = $filter['max_num_label'];
356
357 if ( in_array( $filter['entity'], [ 'post_meta_num', 'tax_numeric' ] ) ) {
358 $queriedValuesWithLogic[$slug]['step'] = $filter['step'];
359 }
360
361 if ( in_array( $filter['entity'], [ 'post_date', 'post_meta_date' ] ) ) {
362 $queriedValuesWithLogic[$slug]['date_format'] = $filter['date_format'];
363 }
364
365 }
366
367 }
368
369 if ( count( $queriedValuesWithLogic ) !== count( $queriedValues ) ) {
370 // Here was self:make_404() but I moved it.
371 return false;
372 }
373
374 // Deliberate overwrite: queried values now carry the logic separators
375 if (!empty($queriedValuesWithLogic)) {
376 $this->context->replace('queried_values', $queriedValuesWithLogic);
377 }
378
379 return true;
380 }
381
382 /**
383 * @return array
384 */
385 public function identifyWpQueriedObject( $wp_query )
386 {
387 $wp_queried_object = [];
388
389 if (!is_object($wp_query)) {
390 return $wp_queried_object;
391 }
392
393 // Archive pages
394 if ( $wp_query->is_archive() ) {
395
396 if ($wp_query->is_tax()) {
397 $wp_queried_object = $this->fillQueriedTermObject($wp_query);
398 }
399
400 if ($wp_query->is_post_type_archive()) {
401 $post_type_object = $wp_query->get_queried_object();
402 $post_type_name = '';
403
404 if ( $post_type_object instanceof \WP_Post_Type ) {
405 $post_type_name = $post_type_object->name;
406 } else {
407 // Since WooCommerce 11 the queried object on the Shop page is
408 // the shop page WP_Post, not the "product" post type object —
409 // fall back to the query var to keep the archive recognized.
410 $query_post_type = $wp_query->get('post_type');
411 if ( is_array( $query_post_type ) ) {
412 $query_post_type = reset( $query_post_type );
413 }
414 if ( is_string( $query_post_type ) && $query_post_type !== '' ) {
415 $post_type_name = $query_post_type;
416 }
417 }
418
419 if ( $post_type_name ) {
420 $wp_queried_object['post_types'][] = $post_type_name;
421
422 // Shop page
423 if( $post_type_name === 'product' ){
424 $wp_queried_object['common'][] = 'shop_page';
425 }
426
427 if( $wp_query->is_search() ){
428 $wp_queried_object['common'][] = 'search_results';
429 }
430 }
431
432 }
433
434 if ($wp_query->is_author()) {
435 if( ! isset( $wp_queried_object['post_types'] ) ){
436 $wp_queried_object['post_types'][] = 'post';
437 }
438
439 if( $wp_query->get('author_name') ){
440 $wp_queried_object['author'] = $wp_query->get('author_name');
441 } else {
442 $user_id = $wp_query->get('author');
443 $user = get_user_by('ID', $user_id);
444 if( ! is_null( $user ) && is_object( $user ) && property_exists( $user, 'data' ) && property_exists( $user->data, 'user_nicename' ) ) {
445 $wp_queried_object['author'] = $user->data->user_nicename;
446 }
447 }
448
449 }
450
451 if ($wp_query->is_date()) {
452 $wp_queried_object['post_types'][] = 'post';
453 }
454
455 if ($wp_query->is_tag()) {
456 $wp_queried_object = $this->fillQueriedTermObject($wp_query);
457 }
458
459 if ($wp_query->is_category()) {
460 $wp_queried_object = $this->fillQueriedTermObject($wp_query);
461 }
462 }
463
464 // Blog, posts page
465 // @bug when homepage is Shop page and price filter has slug 'price' it generates error
466 if ( $wp_query->is_home() || $wp_query->is_posts_page ) {
467 $wp_queried_object['post_types'][] = 'post';
468 $wp_queried_object['common'][] = 'page_for_posts';
469 }
470
471 // Front page (if is home page)
472 // For some reason WP_Query::is_front_page() produces PHP notices so we will check is_front_page later
473 if ( ! $wp_query->is_singular() && $wp_query->is_front_page() ){
474 // Can be shop, archive page, static page, index page(is_home())
475 $wp_queried_object['common'][] = 'page_on_front';
476 }
477
478 // Search results
479 if ($wp_query->is_search() && !$wp_query->is_archive()) {
480 $wp_queried_object['post_types'][] = ($wp_query->get('post_type')) ? $wp_query->get('post_type') : 'post';
481 $wp_queried_object['common'][] = 'search_results';
482 }
483
484 if( $wp_query->is_singular() ){
485 /**
486 * @todo add params about Homepage, Posts page (Blog), Search page, Shop page.
487 * is_front_page(), is_home(),
488 */
489 if( $post_obj = $wp_query->get_queried_object() ) {
490 // It seems it works for pages only
491 $wp_queried_object['post_types'][] = isset($post_obj->post_type) ? $post_obj->post_type : false;
492 $wp_queried_object['post_id'] = isset($post_obj->ID) ? $post_obj->ID : false;
493
494 }elseif( isset( $wp_query->query['name'] ) && ! isset( $wp_query->query['post_type'] ) && $wp_query->query['name'] ){
495 $name = $wp_query->query['name'];
496 $f_post = get_page_by_path( $name, OBJECT, 'post' );
497
498 if ( isset( $f_post->post_type ) ) {
499 $wp_queried_object['post_id'] = $f_post->ID;
500 $wp_queried_object['post_types'][] = $f_post->post_type;
501 }
502 }elseif( $post_type = $wp_query->get('post_type') ){
503
504 if( is_array( $post_type ) ){
505 $wp_queried_object['post_types'] = $post_type;
506 }else{
507 $wp_queried_object['post_types'][] = $post_type;
508 }
509
510 // not $wp_query->get('name') because it is not compatible with WPML
511 $name = ( isset( $wp_query->query['name'] ) ) ? $wp_query->query['name'] : '' ;
512
513 if( $name /* = $wp_query->get('name') */ ) {
514
515 foreach ( (array) $post_type as $_post_type ) {
516 $ptype_obj = get_post_type_object( $_post_type );
517 if ( ! $ptype_obj ) {
518 continue;
519 }
520
521 $f_post = get_page_by_path( $name, OBJECT, $_post_type );
522 if ( isset( $f_post->post_type ) ) {
523 $wp_queried_object['post_id'] = $f_post->ID;
524 break;
525 }
526 }
527
528 unset( $ptype_obj );
529 } elseif( $page_id = $wp_query->get('page_id') ){
530 $wp_queried_object['post_id'] = $page_id;
531 }
532
533 } elseif( $page_id = $wp_query->get('page_id') ){
534 $wp_queried_object['post_types'][] = 'page';
535 $wp_queried_object['post_id'] = $page_id;
536
537 } elseif ( $post_id = $wp_query->get('p') ){
538 $f_post = get_post( $post_id );
539 if( isset( $f_post->post_type ) ){
540 $wp_queried_object['post_types'][] = $f_post->post_type;
541 $wp_queried_object['post_id'] = $post_id;
542 }
543 }
544
545 // When single page is front page
546 if( isset( $wp_queried_object['post_id'] ) && get_option( 'page_on_front' ) == $wp_queried_object['post_id'] ){
547 $wp_queried_object['common'][] = 'page_on_front';
548 unset($wp_queried_object['post_id']);
549 }
550
551 }
552
553 // Maybe Ajax Home
554 $postData = Container::instance()->getThePost();
555 if( isset( $postData['flrt_ajax_link'] ) && empty( $wp_queried_object ) ){
556 $wp_queried_object['post_types'][] = ($wp_query->get('post_type')) ? $wp_query->get('post_type') : 'post';
557 }
558
559 return apply_filters( 'wpc_wp_queried_object', $wp_queried_object, $wp_query );
560 }
561
562 private function fillQueriedTermObject($wp_query)
563 {
564 $wp_queried_object = [];
565 $term = $wp_query->get_queried_object();
566
567 if (isset($term->taxonomy) && $term->taxonomy) {
568 $taxonomy = get_taxonomy($term->taxonomy);
569
570 $wp_queried_object['post_types'] = isset( $taxonomy->object_type ) ? $taxonomy->object_type : false;
571 $wp_queried_object['taxonomy'] = isset( $term->taxonomy ) ? $term->taxonomy : false;
572 $wp_queried_object['term_id'] = isset( $term->term_id ) ? $term->term_id : false;
573
574 }
575
576 return $wp_queried_object;
577 }
578
579 public function fixSearchPostType( $wpQuery )
580 {
581 if( $wpQuery->is_search() && $wpQuery->is_main_query() ){
582 $relevantSetIds = $this->getQueryVar('wpc_page_related_set_ids' );
583
584 if( ! empty( $relevantSetIds ) && ! $wpQuery->get('post_type') ){
585 $wpQuery->set('post_type', 'any' );
586 }
587 }
588 }
589
590 public function addSQlComment( $limits, $wpQuery )
591 {
592 if( $wpQuery->get('flrt_filtered_query') ){
593 $limits .= " /* Current SQL Query is filtered by Filter Everything plugin */";
594 }
595
596 return $limits;
597 }
598
599 public function fixPostsWhereForSearch( $where, $wpQuery )
600 {
601 if( $wpQuery->is_search() && $wpQuery->is_main_query() ){
602 $relevantSetIds = $this->getQueryVar('wpc_page_related_set_ids' );
603
604 if( ! empty( $relevantSetIds ) ){
605 if( is_user_logged_in() ){
606 global $wpdb;
607 $where = str_replace( "OR {$wpdb->posts}.post_status = 'private'", "", $where );
608 }
609 }
610 }
611
612 return $where;
613 }
614
615 /**
616 * Thin delegates to FilterContext; kept for backward compatibility.
617 * New code should use Container::instance()->getFilterContext() directly.
618 */
619 public function getQueryVar($var, $default = false)
620 {
621 return $this->ctx()->get( $var, $default );
622 }
623
624 public function setQueryVar($var, $value)
625 {
626 return $this->ctx()->set( $var, $value );
627 }
628
629 /**
630 * getQueryVar() may be called (e.g. from admin screens) before init() ran;
631 * resolve the context lazily so those callers keep getting the default.
632 */
633 private function ctx()
634 {
635 if ( ! $this->context ) {
636 $this->context = Container::instance()->getFilterContext();
637 }
638 return $this->context;
639 }
640
641 public static function make_404($wp_query, $message = '')
642 {
643 $wp_query->set_404();
644 status_header(404);
645 nocache_headers();
646 if ($message && FLRT_PLUGIN_DEBUG) {
647 echo esc_html( $message );
648 }
649 }
650
651 public function isFilterRequest()
652 {
653 return $this->ctx()->isFilterRequest();
654 }
655
656 private function collectWPQueries( $wp_query )
657 {
658 $fqcn = self::$fqcn;
659 $mg = self::$mg;
660
661 if( $wp_query->is_archive() ||
662 $wp_query->get( 'post_type' ) ||
663 $wp_query->is_home() ||
664 $wp_query->is_search()
665 ) {
666
667 if( is_admin() ){
668 return $wp_query;
669 }
670
671 if( $post_type = $wp_query->get( 'post_type' ) ){
672 $filterSet = Container::instance()->getFilterSetService();
673 $allowedPostTypes = $filterSet->getPostTypes();
674 $allowedPostTypesKeys = array_keys( $allowedPostTypes );
675
676 if( ! is_array($post_type) ){
677 $post_type_array[] = $post_type;
678 }else{
679 $post_type_array = $post_type;
680 }
681
682 // Let's try to find at least one allowed post type in the $wp_query
683 $test_post_types = [];
684 foreach ( $post_type_array as $single_post_type ){
685 if( in_array( $single_post_type, $allowedPostTypesKeys ) ){
686 $test_post_types[] = $single_post_type;
687 }
688 }
689 // If no one post type found, break.
690 if( empty( $test_post_types ) ){
691 return $wp_query;
692 }
693 }
694
695 if( $wp_query->is_singular() ){
696 return $wp_query;
697 }
698
699 // Check if it is our Filtered query and return
700 if( $wp_query->get('flrt_query_clone') || $wp_query->get('flrt_set_query') ){
701 return $wp_query;
702 }
703
704 global $flrt_queries, $wpcQueryOrder;
705 // We must always get post type to compare with selected Post type in Filter Set
706
707 //Added for work woo_discount_rules and query hash
708 if($wp_query->get('flrt_wdr_pagination')){
709 unset( $wp_query->query_vars['flrt_pagination'] );
710 $wp_query->set('flrt_pagination', true);
711 }
712
713 $flrt_query_vars = [];
714 $query_label = '';
715
716 $flrt_query_vars['is_main_query'] = $wp_query->is_main_query();
717 $flrt_query_vars['is_home'] = $wp_query->is_home();
718 $flrt_query_vars['fields'] = $wp_query->get('fields');
719 $flrt_query_vars['is_archive'] = $wp_query->is_archive();
720 $flrt_query_vars['is_post_type_archive'] = $wp_query->is_post_type_archive();
721 $flrt_query_vars['is_tax'] = $wp_query->is_tax();
722 $flrt_query_vars['is_tag'] = $wp_query->is_tag();
723 $flrt_query_vars['is_category'] = $wp_query->is_category();
724 $flrt_query_vars['is_author'] = $wp_query->is_author();
725 $flrt_query_vars['is_search'] = $wp_query->is_search();
726 $flrt_query_vars['is_post__in'] = ! empty( $wp_query->get('post__in') );
727 $flrt_query_vars['is_post__not_in'] = ! empty( $wp_query->get('post__not_in') );
728
729 $flrt_query_vars = apply_filters('wpc_check_broken_query_vars', $flrt_query_vars, $wp_query);
730
731 if( $wp_query->is_archive() ){
732 if( ! $post_type ){
733 if( $wp_query->is_tag() || $wp_query->is_category() || $wp_query->is_tax() ){
734 $term = $wp_query->get_queried_object();
735 $tax = ( isset( $term->taxonomy ) ) ? $term->taxonomy : '';
736
737 if ( $tax ) {
738 $taxonomy = get_taxonomy($tax);
739 $post_type_array = isset( $taxonomy->object_type ) ? $taxonomy->object_type : [];
740 } else {
741 $post_type_array[] = 'post';
742 }
743 }
744
745 if( $wp_query->is_date() || $wp_query->is_author() ){
746 $post_type_array[] = 'post';
747 }
748
749 }
750 }
751
752 if($wp_query->is_search()){
753 $query_label .= esc_html__('Search', 'filter-everything').' ';
754
755 if( ! $post_type ){
756 $post_type_array[] = 'post';
757 }
758 }
759
760 if( $wp_query->is_home() ){
761
762 if( ! $post_type ){
763 $post_type_array[] = 'post';
764 }
765 }
766 $query_label .= esc_html__('Posts list', 'filter-everything');
767 $query_label .= ' «';
768 if( ! empty( $post_type_array ) ){
769 $copy_post_type_array = $post_type_array;
770 $copy_post_type_array = array_map('flrt_ucfirst', $copy_post_type_array);
771 foreach ($copy_post_type_array as $key => $type){
772 $post_type = get_post_type_object(strtolower($type));
773
774 if ( $post_type && isset($post_type->labels->name) ) {
775 $copy_post_type_array[$key] = $post_type->labels->name;
776 }
777 }
778 $query_label .= implode(", ", $copy_post_type_array);
779
780 $flrt_query_vars['post_types'] = $post_type_array;
781 }
782
783 $is_broken_filter = apply_filters('wpc_check_broken_filter', false, $wp_query);
784
785 $hash = md5( serialize( $flrt_query_vars ) );
786 $query_label .= '»';
787 if( $wp_query->is_main_query() ){
788 $query_label .= '. '.esc_html__('Main Query.', 'filter-everything');
789 }
790
791 if( !$wp_query->is_main_query() && !empty($wp_query->get('flrt_detected_source')) ){
792 $query_label .= $fqcn::$mg($wp_query->get('flrt_detected_source'));
793 }
794
795 $flrt_query_vars['label'] = $query_label;
796 $to_save_query_vars = $wp_query->query_vars;
797
798 // IN case of using Pods
799 unset($to_save_query_vars['settings']);
800 // To avoid problems with search query
801 $to_save_query_vars['s'] = '';
802 if($is_broken_filter){
803 $flrt_query_vars['disabled'] = $is_broken_filter;
804 }
805 $flrt_query_vars['query_vars'] = serialize( $to_save_query_vars );
806 $flrt_queries[ $hash ][] = $flrt_query_vars;
807 // Every Query Vars equal combination starts counter from zero value
808 $currentOrder = array_key_last( $flrt_queries[ $hash ] );
809
810 if( $currentOrder === 0 ) {
811 $wpcQueryOrder = $currentOrder;
812 }
813
814 if( ! $wp_query->get('flrt_pagination') ) {
815 $wpcQueryOrder = $currentOrder;
816 }
817
818 $wp_query->set( 'flrt_query_hash', md5($hash . $wpcQueryOrder ) );
819 }
820
821 return $wp_query;
822 }
823
824 private function getRequestUri()
825 {
826 $postData = Container::instance()->getThePost();
827 if( isset( $postData['flrt_ajax_link'] ) ){
828
829 $home_url = home_url();
830
831 if( flrt_wpml_active() ){
832 $home_url = apply_filters( 'wpml_home_url', home_url() );
833 }
834
835 $parts = explode( '?', $home_url );
836 $home_url = trim( $parts[0], '/' );
837
838 $res = str_replace( $home_url, '', $postData['flrt_ajax_link'] );
839
840 if( gettype( $res ) === 'string' ){
841 return $res;
842 }
843 }
844
845 $res = '';
846
847 if( gettype( $_SERVER['REQUEST_URI'] ) === 'string' ){
848 $res = $_SERVER['REQUEST_URI'];
849 }
850
851 return $res;
852 }
853
854 public function customParseRequest( $do_parse_request, $WP, $extra_query_vars ){
855 global $wp_rewrite;
856
857 // Another router (e.g. Brain\Cortex in WP User Manager) has already parsed
858 // this request and built the query — leave it alone.
859 if ( false === $do_parse_request ) {
860 return $do_parse_request;
861 }
862
863 $postData = Container::instance()->getThePost();
864
865 $WP->query_vars = array();
866 $post_type_query_vars = array();
867
868 if ( is_array( $extra_query_vars ) ) {
869 $WP->extra_query_vars = & $extra_query_vars;
870 } elseif ( ! empty( $extra_query_vars ) ) {
871 parse_str( $extra_query_vars, $WP->extra_query_vars );
872 }
873 // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
874
875 // Fetch the rewrite rules.
876 $rewrite = $wp_rewrite->wp_rewrite_rules();
877
878 if ( ! empty( $rewrite ) ) {
879 // If we match a rewrite rule, this will be cleared.
880 $error = '404';
881 $WP->did_permalink = true;
882
883 $pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
884 list( $pathinfo ) = explode( '?', $pathinfo );
885 $pathinfo = str_replace( '%', '%25', $pathinfo );
886
887 // Cleanup request path from filter segments
888 $request_uri = $this->getRequestUri();
889 $cleanedRequest = $this->requestParser->cleanUpRequestPathFromFilterSegments( $request_uri );
890
891 list( $req_uri ) = explode( '?', $cleanedRequest );
892 $self = $_SERVER['PHP_SELF'];
893
894 $home_path = parse_url( home_url(), PHP_URL_PATH );
895 $home_path_regex = '';
896 if ( is_string( $home_path ) && '' !== $home_path ) {
897 $home_path = trim( $home_path, '/' );
898 $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
899 }
900
901 /*
902 * Trim path info from the end and the leading home path from the front.
903 * For path info requests, this leaves us with the requesting filename, if any.
904 * For 404 requests, this leaves us with the requested permalink.
905 */
906 $req_uri = str_replace( $pathinfo, '', $req_uri );
907 $req_uri = trim( $req_uri, '/' );
908 $pathinfo = trim( $pathinfo, '/' );
909 $self = trim( $self, '/' );
910
911 if ( ! empty( $home_path_regex ) ) {
912 $req_uri = preg_replace( $home_path_regex, '', $req_uri );
913 $req_uri = trim( $req_uri, '/' );
914 $pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
915 $pathinfo = trim( $pathinfo, '/' );
916 $self = preg_replace( $home_path_regex, '', $self );
917 $self = trim( $self, '/' );
918 }
919
920 // The requested permalink is in $pathinfo for path info requests and
921 // $req_uri for other requests.
922 if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $wp_rewrite->index . '$|', $pathinfo ) ) {
923 $requested_path = $pathinfo;
924 } else {
925 // If the request uri is the index, blank it out so that we don't try to match it against a rule.
926 if ( $req_uri == $wp_rewrite->index ) {
927 $req_uri = '';
928 }
929 $requested_path = $req_uri;
930 }
931 $requested_file = $req_uri;
932
933 $WP->request = $requested_path;
934 $this->setQueryVar('wp_request', $requested_path);
935
936 if( $cleanedRequest === strtolower( $request_uri ) ){
937 // No filter request. Let's allow WordPress and plugins continue their work
938 return $do_parse_request;
939 }
940
941 $do_parse_request = false;
942
943 // Look for matches.
944 $request_match = $requested_path;
945 if ( empty( $request_match ) ) {
946 // An empty request could only match against ^$ regex.
947 if ( isset( $rewrite['$'] ) ) {
948 $WP->matched_rule = '$';
949 $query = $rewrite['$'];
950 $matches = array( '' );
951 }
952 } else {
953 foreach ( (array) $rewrite as $match => $query ) {
954 // If the requested file is the anchor of the match, prepend it to the path info.
955 if ( ! empty( $requested_file ) && strpos( $match, $requested_file ) === 0 && $requested_file != $requested_path ) {
956 $request_match = $requested_file . '/' . $requested_path;
957 }
958
959 if ( preg_match( "#^$match#", $request_match, $matches ) ||
960 preg_match( "#^$match#", urldecode( $request_match ), $matches ) ) {
961
962 if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
963 // This is a verbose page match, let's check to be sure about it.
964 $page = get_page_by_path( $matches[ $varmatch[1] ] );
965 if ( ! $page ) {
966 continue;
967 }
968
969 $post_status_obj = get_post_status_object( $page->post_status );
970 if ( ! $post_status_obj->public && ! $post_status_obj->protected
971 && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
972 continue;
973 }
974 }
975
976 // Got a match.
977 $WP->matched_rule = $match;
978 break;
979 }
980 }
981 }
982
983 if ( ! empty( $WP->matched_rule ) ) {
984 // Trim the query of everything up to the '?'.
985 $query = preg_replace( '!^.+\?!', '', $query );
986
987 // Substitute the substring matches into the query.
988 $query = addslashes( \WP_MatchesMapRegex::apply( $query, $matches ) );
989
990 $WP->matched_query = $query;
991
992 // Parse the query.
993 parse_str( $query, $perma_query_vars );
994
995 // If we're processing a 404 request, clear the error var since we found something.
996 if ( '404' == $error ) {
997 unset( $error, $_GET['error'] );
998 }
999 }
1000
1001 // If req_uri is empty or if it is a request for ourself, unset error.
1002 if ( empty( $requested_path ) || $requested_file == $self || strpos( $_SERVER['PHP_SELF'], 'wp-admin/' ) !== false ) {
1003 unset( $error, $_GET['error'] );
1004
1005 if (isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false && (! isset( $postData['flrt_ajax_link'] )) ) {
1006 unset($perma_query_vars);
1007 }
1008
1009 $WP->did_permalink = false;
1010 }
1011 } else {
1012 // if permalinks disabled let's allow WordPress and other plugins continue their work
1013 return $do_parse_request;
1014 }
1015
1016 /**
1017 * Filters the query variables allowed before processing.
1018 *
1019 * Allows (publicly allowed) query vars to be added, removed, or changed prior
1020 * to executing the query. Needed to allow custom rewrite rules using your own arguments
1021 * to work, or any other custom query variables you want to be publicly available.
1022 *
1023 * @since 1.5.0
1024 *
1025 * @param string[] $public_query_vars The array of allowed query variable names.
1026 */
1027 $WP->public_query_vars = apply_filters( 'query_vars', $WP->public_query_vars );
1028
1029 foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) {
1030 if ( is_post_type_viewable( $t ) && $t->query_var ) {
1031 $post_type_query_vars[ $t->query_var ] = $post_type;
1032 }
1033 }
1034
1035 foreach ( $WP->public_query_vars as $wpvar ) {
1036 if ( isset( $WP->extra_query_vars[ $wpvar ] ) ) {
1037 $WP->query_vars[ $wpvar ] = $WP->extra_query_vars[ $wpvar ];
1038 } elseif ( isset( $_GET[ $wpvar ] ) && isset( $postData[ $wpvar ] ) && $_GET[ $wpvar ] !== $postData[ $wpvar ] ) {
1039 wp_die( esc_html__( 'A variable mismatch has been detected.' ), esc_html__( 'Sorry, you are not allowed to view this item.' ), 400 );
1040 } elseif ( isset( $postData[ $wpvar ] ) ) {
1041 $WP->query_vars[ $wpvar ] = $postData[ $wpvar ];
1042 } elseif ( isset( $_GET[ $wpvar ] ) ) {
1043 $WP->query_vars[ $wpvar ] = $_GET[ $wpvar ];
1044 } elseif ( isset( $perma_query_vars[ $wpvar ] ) ) {
1045 $WP->query_vars[ $wpvar ] = $perma_query_vars[ $wpvar ];
1046 }
1047
1048 if ( ! empty( $WP->query_vars[ $wpvar ] ) ) {
1049 if ( ! is_array( $WP->query_vars[ $wpvar ] ) ) {
1050 $WP->query_vars[ $wpvar ] = (string) $WP->query_vars[ $wpvar ];
1051 } else {
1052 foreach ( $WP->query_vars[ $wpvar ] as $vkey => $v ) {
1053 if ( is_scalar( $v ) ) {
1054 $WP->query_vars[ $wpvar ][ $vkey ] = (string) $v;
1055 }
1056 }
1057 }
1058
1059 if ( isset( $post_type_query_vars[ $wpvar ] ) ) {
1060 $WP->query_vars['post_type'] = $post_type_query_vars[ $wpvar ];
1061 $WP->query_vars['name'] = $WP->query_vars[ $wpvar ];
1062 }
1063 }
1064 }
1065
1066 // Convert urldecoded spaces back into '+'.
1067 foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) {
1068 if ( $t->query_var && isset( $WP->query_vars[ $t->query_var ] ) ) {
1069 $WP->query_vars[ $t->query_var ] = str_replace( ' ', '+', $WP->query_vars[ $t->query_var ] );
1070 }
1071 }
1072
1073 // Don't allow non-publicly queryable taxonomies to be queried from the front end.
1074 if ( ! is_admin() ) {
1075 foreach ( get_taxonomies( array( 'publicly_queryable' => false ), 'objects' ) as $taxonomy => $t ) {
1076 /*
1077 * Disallow when set to the 'taxonomy' query var.
1078 * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy().
1079 */
1080 if ( isset( $WP->query_vars['taxonomy'] ) && $taxonomy === $WP->query_vars['taxonomy'] ) {
1081 unset( $WP->query_vars['taxonomy'], $WP->query_vars['term'] );
1082 }
1083 }
1084 }
1085
1086 // Limit publicly queried post_types to those that are 'publicly_queryable'.
1087 if ( isset( $WP->query_vars['post_type'] ) ) {
1088 $queryable_post_types = get_post_types( array( 'publicly_queryable' => true ) );
1089 if ( ! is_array( $WP->query_vars['post_type'] ) ) {
1090 if ( ! in_array( $WP->query_vars['post_type'], $queryable_post_types, true ) ) {
1091 unset( $WP->query_vars['post_type'] );
1092 }
1093 } else {
1094 $WP->query_vars['post_type'] = array_intersect( $WP->query_vars['post_type'], $queryable_post_types );
1095 }
1096 }
1097
1098 // Resolve conflicts between posts with numeric slugs and date archive queries.
1099 $WP->query_vars = wp_resolve_numeric_slug_conflicts( $WP->query_vars );
1100
1101 foreach ( (array) $WP->private_query_vars as $var ) {
1102 if ( isset( $WP->extra_query_vars[ $var ] ) ) {
1103 $WP->query_vars[ $var ] = $WP->extra_query_vars[ $var ];
1104 }
1105 }
1106
1107 if ( isset( $error ) ) {
1108 $WP->query_vars['error'] = $error;
1109 }
1110
1111 /**
1112 * Filters the array of parsed query variables.
1113 *
1114 * @since 2.1.0
1115 *
1116 * @param array $query_vars The array of requested query variables.
1117 */
1118 $WP->query_vars = apply_filters( 'request', $WP->query_vars );
1119
1120 /**
1121 * Fires once all query variables for the current request have been parsed.
1122 *
1123 * @since 2.1.0
1124 *
1125 * @param WP $wp Current WordPress environment instance (passed by reference).
1126 */
1127 do_action_ref_array( 'parse_request', array( &$WP ) );
1128
1129 $WP->query_posts();
1130 $WP->handle_404();
1131 $WP->register_globals();
1132
1133 return $do_parse_request;
1134 }
1135
1136 private function prepareRequest(){
1137 global $wp_rewrite;
1138
1139 $pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
1140 list( $pathinfo ) = explode( '?', $pathinfo );
1141 $pathinfo = str_replace( '%', '%25', $pathinfo );
1142
1143 list( $req_uri ) = explode( '?', $this->getRequestUri() );
1144
1145 $home_path = parse_url( home_url(), PHP_URL_PATH );
1146 $home_path_regex = '';
1147
1148 if ( is_string( $home_path ) && '' !== $home_path ) {
1149 $home_path = trim( $home_path, '/' );
1150 $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
1151 }
1152 /*
1153 * Trim path info from the end and the leading home path from the front.
1154 * For path info requests, this leaves us with the requesting filename, if any.
1155 * For 404 requests, this leaves us with the requested permalink.
1156 */
1157 $req_uri = str_replace( $pathinfo, '', $req_uri );
1158 $req_uri = trim( $req_uri, '/' );
1159 $pathinfo = trim( $pathinfo, '/' );
1160
1161 if ( ! empty( $home_path_regex ) ) {
1162 $req_uri = preg_replace( $home_path_regex, '', $req_uri );
1163 $req_uri = trim( $req_uri, '/' );
1164 $pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
1165 $pathinfo = trim( $pathinfo, '/' );
1166 }
1167
1168 // The requested permalink is in $pathinfo for path info requests and
1169 // $req_uri for other requests.
1170 if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $wp_rewrite->index . '$|', $pathinfo ) ) {
1171 $requested_path = $pathinfo;
1172 } else {
1173 // If the request uri is the index, blank it out so that we don't try to match it against a rule.
1174 if ( $req_uri == $wp_rewrite->index ) {
1175 $req_uri = '';
1176 }
1177 $requested_path = $req_uri;
1178 }
1179
1180 return $requested_path;
1181 }
1182
1183 }