Tribe__Rewrite::get_canonical_url( string $url, bool $force = false )
Returns the canonical URLs associated with a ugly link.
Contents
This method will handle "our" URLs to go from their ugly form, filled with query vars, to the "pretty" one, if possible.
Parameters
- $url
-
(string) (Required) The URL to try and translate into its canonical form.
- $force
-
(bool) (Optional) Whether to try and use the cache or force a new canonical URL conversion.
Default value: false
Return
(string) The canonical URL, or the input URL if it could not be resolved to a canonical one.
Source
File: src/Tribe/Rewrite.php
public function get_canonical_url( $url, $force = false ) {
if ( get_class( $this ) === Tribe__Rewrite::class ) {
throw new BadMethodCallException(
'Method get_canonical_url should only be called on extending classes.'
);
}
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();
}
/**
* Filters the canonical URL for an input URL before any kind of logic runs.
*
* @since 4.9.11
*
* @param string|null $canonical_url The canonical URL, defaults to `null`; returning a non `null` value will
* make the logic bail and return the value.
* @param string $url The input URL to resolve to a canonical one.
* @param Tribe__Rewrite $this This rewrite object.
*/
$canonical_url = apply_filters( 'tribe_rewrite_pre_canonical_url', null, $url );
if ( null !== $canonical_url ) {
return $canonical_url;
}
$home_url = home_url();
// It's not a path we, or WP, could possibly handle.
$has_http_scheme = (bool) parse_url( $url, PHP_URL_SCHEME );
if (
$home_url === $url
|| ( $has_http_scheme && false === strpos( $url, $home_url ) )
) {
return $url;
}
$canonical_url = $url;
// To avoid issues with missing `path` component let's always add a trailing '/'.
if ( false !== strpos( $url, '?' ) ) {
$canonical_url = preg_replace( '~(\\/)*\\?~', '/?', $canonical_url );
} elseif ( false !== strpos( $url, '#' ) ) {
$canonical_url = preg_replace( '~(\\/)*#~', '/#', $canonical_url );
}
// Canonical URLs are supposed to contain the home URL.
if ( false === strpos( $canonical_url, $home_url ) ) {
$canonical_url = home_url( $canonical_url );
}
if ( empty( $canonical_url ) ) {
return $home_url;
}
if ( ! $force ) {
$this->warmup_cache(
'canonical_url',
WEEK_IN_SECONDS,
Listener::TRIGGER_GENERATE_REWRITE_RULES
);
if ( isset( $this->canonical_url_cache[ $url ] ) ) {
return $this->canonical_url_cache[ $url ];
}
}
$query = (string) parse_url( $url, PHP_URL_QUERY );
wp_parse_str( $query, $query_vars );
// Remove the `paged` query var if it's 1.
if ( isset( $query_vars['paged'] ) && 1 === (int) $query_vars['paged'] ) {
unset( $query_vars['paged'] );
}
ksort( $query_vars );
$our_rules = $this->get_handled_rewrite_rules();
$handled_query_vars = $this->get_rules_query_vars( $our_rules );
if (
empty( $our_rules )
|| ! in_array( Arr::get( $query_vars, 'post_type', 'post' ), $this->get_post_types(), true )
) {
$wp_canonical = redirect_canonical( $canonical_url, false );
if ( empty( $wp_canonical ) ) {
$wp_canonical = $canonical_url;
}
$this->canonical_url_cache[ $url ] = $wp_canonical;
return $wp_canonical;
}
$bases = (array) $this->get_bases();
ksort( $bases );
$localized_matchers = $this->get_localized_matchers();
$dynamic_matchers = $this->get_dynamic_matchers( $query_vars );
// Try to match only on the query vars we're actually handling.
$matched_vars = array_intersect_key( $query_vars, array_combine( $handled_query_vars, $handled_query_vars ) );
$unmatched_vars = array_diff_key( $query_vars, array_combine( $handled_query_vars, $handled_query_vars ) );
if ( empty( $matched_vars ) ) {
// The URL does contain query vars, but none we handle.
$wp_canonical = trailingslashit( redirect_canonical( $url, false ) );
$this->canonical_url_cache[ $url ] = $wp_canonical;
return $wp_canonical;
}
$found = false;
foreach ( $our_rules as $link_template => $index_path ) {
wp_parse_str( (string) parse_url( $index_path, PHP_URL_QUERY ), $link_vars );
ksort( $link_vars );
if ( array_keys( $link_vars ) !== array_keys( $matched_vars ) ) {
continue;
}
if ( ! (
Arr::get( $matched_vars, 'post_type', '' ) === Arr::get( $link_vars, 'post_type', '' )
&& Arr::get( $matched_vars, 'eventDisplay', '' ) === Arr::get( $link_vars, 'eventDisplay', '' )
) ) {
continue;
}
$replace = array_map( function ( $localized_matcher ) use ( $matched_vars ) {
if ( ! is_array( $localized_matcher ) ) {
// For the dates.
return isset( $matched_vars[ $localized_matcher ] )
? $matched_vars[ $localized_matcher ]
: '';
}
$query_var = $localized_matcher['query_var'];
$query_vars = [ $query_var ];
if ( $query_var === 'name' ) {
$query_vars = array_merge( $query_vars, $this->get_post_types() );
}
if ( ! array_intersect( array_keys( $matched_vars ), $query_vars ) ) {
return '';
}
/*
* We use `end` as, by default, the localized version of the slug in the current language will be at the
* end of the array.
* @todo here we should keep a map, that has to generated at permalink flush time, to map locales/slugs.
*/
return end( $localized_matcher['localized_slugs'] );
}, $localized_matchers );
// Include dynamic matchers now.
$replace = array_merge( $dynamic_matchers, $replace );
$replaced = str_replace( array_keys( $replace ), $replace, $link_template );
// Remove trailing chars.
$path = rtrim( $replaced, '?$' );
$resolved = trailingslashit( home_url( $path ) );
$found = true;
break;
}
if ( empty( $resolved ) ) {
$wp_canonical = redirect_canonical( $canonical_url, false );
$resolved = empty( $wp_canonical ) ? $canonical_url : $wp_canonical;
}
if ( $canonical_url !== $resolved ) {
// Be sure to add a trailing slash to the URL; before `?` or `#`.
$resolved = preg_replace( '/(?<!\\/)(#|\\?)/u', '/$1', $resolved );
}
if ( count( $unmatched_vars ) ) {
$resolved = add_query_arg( $unmatched_vars, $resolved );
}
/**
* Filters the resolved canonical URL to allow third party code to modify it.
*
* Mind that the value will be cached and hence this filter will fire once per URL per request and, second, this
* filter will fire after all the logic to resolve the URL ran. If you want to filter the canonical URL before
* the logic runs then use the `tribe_rewrite_pre_canonical_url` filter.
*
* @since 4.9.11
*
* @param string $resolved The resolved, canonical URL.
* @param string $url The original URL to resolve.
* @param Tribe__Rewrite $this This object.
*/
$resolved = apply_filters( 'tribe_rewrite_canonical_url', $resolved, $url, $this );
if ( $found ) {
// Since we're caching let's not cache unmatched rules to allow for their later, valid resolution.
$this->canonical_url_cache[ $url ] = $resolved;
}
return $resolved;
}
Changelog
| Version | Description |
|---|---|
| 4.9.11 | Introduced. |