PluginProbe
Filter Everything — WordPress & WooCommerce Filters / trunk
Filter Everything — WordPress & WooCommerce Filters vtrunk
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 1.6.3 All 51 releases
filter-everything / src / WpManager.php

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

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