Tribe__Rewrite::parse_request( string $url, array $extra_query_vars = array(), bool $force = false )

Parses a URL to produce an array of query variables.

Most of this functionality was copied from WP::parse_request() method with some changes to avoid conflicts and removing non-required behaviors.


Parameters

$url

(string) (Required) The URLto parse.

$extra_query_vars

(array) (Optional) An associative array of extra query vars to use for the parsing. These vars will be read before the WordPress defined ones overriding them.

Default value: array()

$force

(bool) (Optional) Whether to try and use the cache or force a new canonical URL conversion.

Default value: false


Top ↑

Return

(array) An array of query vars, as parsed from the input URL.


Top ↑

Source

File: src/Tribe/Rewrite.php

	public function parse_request( $url, array $extra_query_vars = [], $force = false ) {
		if ( null === $this->rewrite ) {
			// We re-do this check here as the object might have been initialized before the global rewrite was set.
			$this->setup();
		}

		/**
		 * Allows short-circuiting the URL parsing.
		 *
		 * This filter will run before any logic runs, its result will not be cached and this filter will be called on
		 * each call to this method.
		 * Returning a non `null` value here will short-circuit this logic.
		 *
		 * @since 4.9.11
		 *
		 * @param array  $query_vars       The parsed query vars array.
		 * @param array  $extra_query_vars An associative array of extra query vars that will be processed before the
		 *                                 WordPress defined ones.
		 * @param string $url              The URL to parse.
		 */
		$parsed = apply_filters( 'tribe_rewrite_pre_parse_query_vars', null, $extra_query_vars, $url );
		if ( null !== $parsed ) {
			return $parsed;
		}

		if ( ! $force ) {
			$this->warmup_cache(
				'parse_request',
				WEEK_IN_SECONDS,
				Listener::TRIGGER_GENERATE_REWRITE_RULES
			);
			if ( isset( $this->parse_request_cache[ $url ] ) ) {
				return $this->parse_request_cache[ $url ];
			}
		}

		$query_vars           = [];
		$post_type_query_vars = [];
		$perma_query_vars     = [];
		$url_components = parse_url($url);
		$url_path = Arr::get( $url_components, 'path', '/' );
		$url_query = Arr::get( $url_components, 'query', '' );
		parse_str( $url_query, $url_query_vars );
		// Look for matches, removing leading `/` char.
		$request_match = ltrim( $url_path, '/' );

		// Fetch the rewrite rules.
		$rewrite_rules = $this->rewrite->wp_rewrite_rules();
		$matched_rule = false;

		if ( ! empty( $rewrite_rules ) ) {
			foreach ( (array) $rewrite_rules as $match => $query ) {
				$matches_regex = preg_match( "#^$match#", $request_match, $matches )
				                 || preg_match( "#^$match#", urldecode( $request_match ), $matches );

				if ( ! $matches_regex ) {
					continue;
				}

				if (
					$this->rewrite->use_verbose_page_rules
					&& preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch )
				) {
					// This is a verbose page match, let's check to be sure about it.
					$page = get_page_by_path( $matches[ $varmatch[1] ] );
					if ( ! $page ) {
						continue;
					}
					$post_status_obj = get_post_status_object( $page->post_status );
					if (
						! $post_status_obj->public
						&& ! $post_status_obj->protected
						&& ! $post_status_obj->private
						&& $post_status_obj->exclude_from_search
					) {
						continue;
					}
				}

				// Got a match.
				$matched_rule = $match;
				break;
			}

			if ( false !== $matched_rule ) {
				// Trim the query of everything up to the '?'.
				$query = preg_replace( '!^.+\?!', '', $query );
				// Substitute the substring matches into the query.
				$query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
				// Parse the query.
				parse_str( $query, $perma_query_vars );
			}
		}

		foreach ( get_post_types( [], 'objects' ) as $post_type => $t ) {
			if (
				is_post_type_viewable( $t )
				&& $t->query_var
			) {
				$post_type_query_vars[ $t->query_var ] = $post_type;
			}
		}

		global $wp;

		/*
		 * WordPress would apply this filter in the `parse_request` method to allow the registration of additional query
		 * vars. They might not have been registered at this point so we do this again making sure to avoid duplicates.
		 */
		$public_query_vars = array_unique( apply_filters( 'query_vars', $wp->public_query_vars ) );

		foreach ( $public_query_vars as $wpvar ) {
			if ( isset( $extra_query_vars[ $wpvar ] ) ) {
				$query_vars[ $wpvar ] = $extra_query_vars[ $wpvar ];
			} elseif ( isset( $perma_query_vars[ $wpvar ] ) ) {
				$query_vars[ $wpvar ] = $perma_query_vars[ $wpvar ];
			}
			if ( ! empty( $query_vars[ $wpvar ] ) ) {
				if ( ! is_array( $query_vars[ $wpvar ] ) ) {
					$query_vars[ $wpvar ] = (string) $query_vars[ $wpvar ];
				} else {
					foreach ( $query_vars[ $wpvar ] as $vkey => $v ) {
						if ( is_scalar( $v ) ) {
							$query_vars[ $wpvar ][ $vkey ] = (string) $v;
						}
					}
				}
				if ( isset( $post_type_query_vars[ $wpvar ] ) ) {
					$query_vars['post_type'] = $post_type_query_vars[ $wpvar ];
					$query_vars['name']      = $query_vars[ $wpvar ];
				}
			}
		}

		// Convert urldecoded spaces back into `+`.
		foreach ( get_taxonomies( [], 'objects' ) as $taxonomy => $t ) {
			if ( $t->query_var && isset( $query_vars[ $t->query_var ] ) ) {
				$query_vars[ $t->query_var ] = str_replace( ' ', '+', $query_vars[ $t->query_var ] );
			}
		}

		// Don't allow non-publicly queryable taxonomies to be queried from the front end.
		if ( ! is_admin() ) {
			foreach ( get_taxonomies( [ 'publicly_queryable' => false ], 'objects' ) as $taxonomy => $t ) {
				/*
				 * Disallow when set to the 'taxonomy' query var.
				 * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy().
				 */
				if ( isset( $query_vars['taxonomy'] ) && $taxonomy === $query_vars['taxonomy'] ) {
					unset( $query_vars['taxonomy'], $query_vars['term'] );
				}
			}
		}

		// Limit publicly queried post_types to those that are publicly_queryable
		if ( isset( $query_vars['post_type'] ) ) {
			$queryable_post_types = get_post_types( [ 'publicly_queryable' => true ] );
			if ( ! is_array( $query_vars['post_type'] ) ) {
				if ( ! in_array( $query_vars['post_type'], $queryable_post_types ) ) {
					unset( $query_vars['post_type'] );
				}
			} else {
				$query_vars['post_type'] = array_intersect( $query_vars['post_type'], $queryable_post_types );
			}
		}

		// Resolve conflicts between posts with numeric slugs and date archive queries.
		$query_vars = wp_resolve_numeric_slug_conflicts( $query_vars );

		foreach ( (array) $wp->private_query_vars as $var ) {
			if ( isset( $extra_query_vars[ $var ] ) ) {
				$query_vars[ $var ] = $extra_query_vars[ $var ];
			}
		}

		/*
		 * If we have both the `name` query var and the post type one, then let's remove the `name` one.
		 */
		if ( array_intersect( array_keys( $query_vars ), $this->get_post_types() ) ) {
			unset( $query_vars['name'] );
		}

		if ( ! empty( $url_query_vars ) ) {
			// If the URL did have query vars keep them if not overridden by our resolution.
			$query_vars = array_merge( $url_query_vars, $query_vars );
		}

		/**
		 * Filters the array of parsed query variables after the class logic has been applied to it.
		 *
		 * Due to the costly nature of this operation the results will be cached. The logic, and this filter, will
		 * not run a second time for the same URL in the context of the same request.
		 *
		 * @since 4.9.11
		 *
		 * @param array  $query_vars       The parsed query vars array.
		 * @param array  $extra_query_vars An associative array of extra query vars that will be processed before the
		 *                                 WordPress defined ones.
		 * @param string $url              The URL to parse.
		 */
		$query_vars = apply_filters( 'tribe_rewrite_parse_query_vars', $query_vars, $extra_query_vars, $url );

		if ( $matched_rule ) {
			// Since we're caching let's not cache unmatchec URLs to allow for their later, valid matching.
			$this->parse_request_cache[ $url ] = $query_vars;
		}

		return $query_vars;
	}

Top ↑

Changelog

Changelog
Version Description
4.9.11 Introduced.