Title: redirect_canonical
Published: April 25, 2014
Last modified: February 24, 2026

---

# redirect_canonical( string $requested_url = null, bool $do_redirect = true ): string|void

## In this article

 * [Description](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#description)
 * [Parameters](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#source)
 * [Hooks](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#hooks)
 * [Related](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#changelog)
 * [User Contributed Notes](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#user-contributed-notes)

[ Back to top](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#wp--skip-link--target)

Redirects incoming links to the proper URL based on the site url.

## 󠀁[Description](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#description)󠁿

Search engines consider www.somedomain.com and somedomain.com to be two different
URLs when they both go to the same location. This SEO enhancement prevents penalty
for duplicate content by redirecting all incoming links to one or the other.

Prevents redirection for feeds, trackbacks, searches, and admin URLs. Does not redirect
on non-pretty-permalink-supporting IIS 7+, page/post previews, WP admin, Trackbacks,
robots.txt, favicon.ico, searches, or on POST requests.

Will also attempt to find the correct link when a user enters a URL that does not
exist based on exact WordPress query. Will instead try to parse the URL or query
in an attempt to figure the correct page to go to.

## 󠀁[Parameters](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#parameters)󠁿

 `$requested_url`stringoptional

The URL that was requested, used to figure if redirect is needed.

Default:`null`

`$do_redirect`booloptional

Redirect to the new URL.

Default:`true`

## 󠀁[Return](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#return)󠁿

 string|void The string of the URL, if redirect needed.

## 󠀁[Source](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#source)󠁿

    ```php
    function redirect_canonical( $requested_url = null, $do_redirect = true ) {
    	global $wp_rewrite, $is_IIS, $wp_query, $wpdb, $wp;

    	if ( isset( $_SERVER['REQUEST_METHOD'] ) && ! in_array( strtoupper( $_SERVER['REQUEST_METHOD'] ), array( 'GET', 'HEAD' ), true ) ) {
    		return;
    	}

    	/*
    	 * If we're not in wp-admin and the post has been published and preview nonce
    	 * is non-existent or invalid then no need for preview in query.
    	 */
    	if ( is_preview() && get_query_var( 'p' ) && 'publish' === get_post_status( get_query_var( 'p' ) ) ) {
    		if ( ! isset( $_GET['preview_id'] )
    			|| ! isset( $_GET['preview_nonce'] )
    			|| ! wp_verify_nonce( $_GET['preview_nonce'], 'post_preview_' . (int) $_GET['preview_id'] )
    		) {
    			$wp_query->is_preview = false;
    		}
    	}

    	if ( is_admin() || is_search() || is_preview() || is_trackback() || is_favicon()
    		|| ( $is_IIS && ! iis7_supports_permalinks() )
    	) {
    		return;
    	}

    	if ( ! $requested_url && isset( $_SERVER['HTTP_HOST'] ) ) {
    		// Build the URL in the address bar.
    		$requested_url  = is_ssl() ? 'https://' : 'http://';
    		$requested_url .= $_SERVER['HTTP_HOST'];
    		$requested_url .= $_SERVER['REQUEST_URI'];
    	}

    	$original = parse_url( $requested_url );
    	if ( false === $original ) {
    		return;
    	}

    	// Notice fixing.
    	$original += array(
    		'host'   => '',
    		'path'   => '',
    		'query'  => '',
    		'scheme' => '',
    	);

    	$redirect     = $original;
    	$redirect_url = false;
    	$redirect_obj = false;

    	/*
    	 * If the original URL ended with non-breaking spaces, they were almost
    	 * certainly inserted by accident. Let's remove them, so the reader doesn't
    	 * see a 404 error with no obvious cause.
    	 */
    	$redirect['path'] = preg_replace( '|(%C2%A0)+$|i', '', $redirect['path'] );

    	// It's not a preview, so remove it from URL.
    	if ( get_query_var( 'preview' ) ) {
    		$redirect['query'] = remove_query_arg( 'preview', $redirect['query'] );
    	}

    	$post_id = get_query_var( 'p' );

    	if ( is_feed() && $post_id ) {
    		$redirect_url = get_post_comments_feed_link( $post_id, get_query_var( 'feed' ) );
    		$redirect_obj = get_post( $post_id );

    		if ( $redirect_url ) {
    			$redirect['query'] = _remove_qs_args_if_not_in_url(
    				$redirect['query'],
    				array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type', 'feed' ),
    				$redirect_url
    			);

    			$redirect['path'] = parse_url( $redirect_url, PHP_URL_PATH );
    		}
    	}

    	if ( is_singular() && $wp_query->post_count < 1 && $post_id ) {

    		$vars = $wpdb->get_results( $wpdb->prepare( "SELECT post_type, post_parent FROM $wpdb->posts WHERE ID = %d", $post_id ) );

    		if ( ! empty( $vars[0] ) ) {
    			$vars = $vars[0];

    			if ( 'revision' === $vars->post_type && $vars->post_parent > 0 ) {
    				$post_id = $vars->post_parent;
    			}

    			$redirect_url = get_permalink( $post_id );
    			$redirect_obj = get_post( $post_id );

    			if ( $redirect_url ) {
    				$redirect['query'] = _remove_qs_args_if_not_in_url(
    					$redirect['query'],
    					array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ),
    					$redirect_url
    				);
    			}
    		}
    	}

    	// These tests give us a WP-generated permalink.
    	if ( is_404() ) {

    		// Redirect ?page_id, ?p=, ?attachment_id= to their respective URLs.
    		$post_id = max( get_query_var( 'p' ), get_query_var( 'page_id' ), get_query_var( 'attachment_id' ) );

    		$redirect_post = $post_id ? get_post( $post_id ) : false;

    		if ( $redirect_post ) {
    			$post_type_obj = get_post_type_object( $redirect_post->post_type );

    			if ( $post_type_obj && $post_type_obj->public && 'auto-draft' !== $redirect_post->post_status ) {
    				$redirect_url = get_permalink( $redirect_post );
    				$redirect_obj = get_post( $redirect_post );

    				$redirect['query'] = _remove_qs_args_if_not_in_url(
    					$redirect['query'],
    					array( 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ),
    					$redirect_url
    				);
    			}
    		}

    		$year  = get_query_var( 'year' );
    		$month = get_query_var( 'monthnum' );
    		$day   = get_query_var( 'day' );

    		if ( $year && $month && $day ) {
    			$date = sprintf( '%04d-%02d-%02d', $year, $month, $day );

    			if ( ! wp_checkdate( $month, $day, $year, $date ) ) {
    				$redirect_url = get_month_link( $year, $month );

    				$redirect['query'] = _remove_qs_args_if_not_in_url(
    					$redirect['query'],
    					array( 'year', 'monthnum', 'day' ),
    					$redirect_url
    				);
    			}
    		} elseif ( $year && $month && $month > 12 ) {
    			$redirect_url = get_year_link( $year );

    			$redirect['query'] = _remove_qs_args_if_not_in_url(
    				$redirect['query'],
    				array( 'year', 'monthnum' ),
    				$redirect_url
    			);
    		}

    		// Strip off non-existing <!--nextpage--> links from single posts or pages.
    		if ( get_query_var( 'page' ) ) {
    			$post_id = 0;

    			if ( $wp_query->queried_object instanceof WP_Post ) {
    				$post_id = $wp_query->queried_object->ID;
    			} elseif ( $wp_query->post ) {
    				$post_id = $wp_query->post->ID;
    			}

    			if ( $post_id ) {
    				$redirect_url = get_permalink( $post_id );
    				$redirect_obj = get_post( $post_id );

    				$redirect['path']  = rtrim( $redirect['path'], (int) get_query_var( 'page' ) . '/' );
    				$redirect['query'] = remove_query_arg( 'page', $redirect['query'] );
    			}
    		}

    		if ( ! $redirect_url ) {
    			$redirect_url = redirect_guess_404_permalink();

    			if ( $redirect_url ) {
    				$redirect['query'] = _remove_qs_args_if_not_in_url(
    					$redirect['query'],
    					array( 'page', 'feed', 'p', 'page_id', 'attachment_id', 'pagename', 'name', 'post_type' ),
    					$redirect_url
    				);
    			}
    		}
    	} elseif ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) {

    		// Rewriting of old ?p=X, ?m=2004, ?m=200401, ?m=20040101.
    		if ( is_attachment()
    			&& ! array_diff( array_keys( $wp->query_vars ), array( 'attachment', 'attachment_id' ) )
    			&& ! $redirect_url
    		) {
    			if ( ! empty( $_GET['attachment_id'] ) ) {
    				$redirect_url = get_attachment_link( get_query_var( 'attachment_id' ) );
    				$redirect_obj = get_post( get_query_var( 'attachment_id' ) );

    				if ( $redirect_url ) {
    					$redirect['query'] = remove_query_arg( 'attachment_id', $redirect['query'] );
    				}
    			} else {
    				$redirect_url = get_attachment_link();
    				$redirect_obj = get_post();
    			}
    		} elseif ( is_single() && ! empty( $_GET['p'] ) && ! $redirect_url ) {
    			$redirect_url = get_permalink( get_query_var( 'p' ) );
    			$redirect_obj = get_post( get_query_var( 'p' ) );

    			if ( $redirect_url ) {
    				$redirect['query'] = remove_query_arg( array( 'p', 'post_type' ), $redirect['query'] );
    			}
    		} elseif ( is_single() && ! empty( $_GET['name'] ) && ! $redirect_url ) {
    			$redirect_url = get_permalink( $wp_query->get_queried_object_id() );
    			$redirect_obj = get_post( $wp_query->get_queried_object_id() );

    			if ( $redirect_url ) {
    				$redirect['query'] = remove_query_arg( 'name', $redirect['query'] );
    			}
    		} elseif ( is_page() && ! empty( $_GET['page_id'] ) && ! $redirect_url ) {
    			$redirect_url = get_permalink( get_query_var( 'page_id' ) );
    			$redirect_obj = get_post( get_query_var( 'page_id' ) );

    			if ( $redirect_url ) {
    				$redirect['query'] = remove_query_arg( 'page_id', $redirect['query'] );
    			}
    		} elseif ( is_page() && ! is_feed() && ! $redirect_url
    			&& 'page' === get_option( 'show_on_front' ) && get_queried_object_id() === (int) get_option( 'page_on_front' )
    		) {
    			$redirect_url = home_url( '/' );
    		} elseif ( is_home() && ! empty( $_GET['page_id'] ) && ! $redirect_url
    			&& 'page' === get_option( 'show_on_front' ) && get_query_var( 'page_id' ) === (int) get_option( 'page_for_posts' )
    		) {
    			$redirect_url = get_permalink( get_option( 'page_for_posts' ) );
    			$redirect_obj = get_post( get_option( 'page_for_posts' ) );

    			if ( $redirect_url ) {
    				$redirect['query'] = remove_query_arg( 'page_id', $redirect['query'] );
    			}
    		} elseif ( ! empty( $_GET['m'] ) && ( is_year() || is_month() || is_day() ) ) {
    			$m = get_query_var( 'm' );

    			switch ( strlen( $m ) ) {
    				case 4: // Yearly.
    					$redirect_url = get_year_link( $m );
    					break;
    				case 6: // Monthly.
    					$redirect_url = get_month_link( substr( $m, 0, 4 ), substr( $m, 4, 2 ) );
    					break;
    				case 8: // Daily.
    					$redirect_url = get_day_link( substr( $m, 0, 4 ), substr( $m, 4, 2 ), substr( $m, 6, 2 ) );
    					break;
    			}

    			if ( $redirect_url ) {
    				$redirect['query'] = remove_query_arg( 'm', $redirect['query'] );
    			}
    			// Now moving on to non ?m=X year/month/day links.
    		} elseif ( is_date() ) {
    			$year  = get_query_var( 'year' );
    			$month = get_query_var( 'monthnum' );
    			$day   = get_query_var( 'day' );

    			if ( is_day() && $year && $month && ! empty( $_GET['day'] ) ) {
    				$redirect_url = get_day_link( $year, $month, $day );

    				if ( $redirect_url ) {
    					$redirect['query'] = remove_query_arg( array( 'year', 'monthnum', 'day' ), $redirect['query'] );
    				}
    			} elseif ( is_month() && $year && ! empty( $_GET['monthnum'] ) ) {
    				$redirect_url = get_month_link( $year, $month );

    				if ( $redirect_url ) {
    					$redirect['query'] = remove_query_arg( array( 'year', 'monthnum' ), $redirect['query'] );
    				}
    			} elseif ( is_year() && ! empty( $_GET['year'] ) ) {
    				$redirect_url = get_year_link( $year );

    				if ( $redirect_url ) {
    					$redirect['query'] = remove_query_arg( 'year', $redirect['query'] );
    				}
    			}
    		} elseif ( is_author() && ! empty( $_GET['author'] )
    			&& is_string( $_GET['author'] ) && preg_match( '|^[0-9]+$|', $_GET['author'] )
    		) {
    			$author = get_userdata( get_query_var( 'author' ) );

    			if ( false !== $author
    				&& $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE $wpdb->posts.post_author = %d AND $wpdb->posts.post_status = 'publish' LIMIT 1", $author->ID ) )
    			) {
    				$redirect_url = get_author_posts_url( $author->ID, $author->user_nicename );
    				$redirect_obj = $author;

    				if ( $redirect_url ) {
    					$redirect['query'] = remove_query_arg( 'author', $redirect['query'] );
    				}
    			}
    		} elseif ( is_category() || is_tag() || is_tax() ) { // Terms (tags/categories).
    			$term_count = 0;

    			foreach ( $wp_query->tax_query->queried_terms as $tax_query ) {
    				if ( isset( $tax_query['terms'] ) && is_countable( $tax_query['terms'] ) ) {
    					$term_count += count( $tax_query['terms'] );
    				}
    			}

    			$obj = $wp_query->get_queried_object();

    			if ( $term_count <= 1 && ! empty( $obj->term_id ) ) {
    				$tax_url = get_term_link( (int) $obj->term_id, $obj->taxonomy );

    				if ( $tax_url && ! is_wp_error( $tax_url ) ) {
    					if ( ! empty( $redirect['query'] ) ) {
    						// Strip taxonomy query vars off the URL.
    						$qv_remove = array( 'term', 'taxonomy' );

    						if ( is_category() ) {
    							$qv_remove[] = 'category_name';
    							$qv_remove[] = 'cat';
    						} elseif ( is_tag() ) {
    							$qv_remove[] = 'tag';
    							$qv_remove[] = 'tag_id';
    						} else {
    							// Custom taxonomies will have a custom query var, remove those too.
    							$tax_obj = get_taxonomy( $obj->taxonomy );
    							if ( false !== $tax_obj->query_var ) {
    								$qv_remove[] = $tax_obj->query_var;
    							}
    						}

    						$rewrite_vars = array_diff( array_keys( $wp_query->query ), array_keys( $_GET ) );

    						// Check to see if all the query vars are coming from the rewrite, none are set via $_GET.
    						if ( ! array_diff( $rewrite_vars, array_keys( $_GET ) ) ) {
    							// Remove all of the per-tax query vars.
    							$redirect['query'] = remove_query_arg( $qv_remove, $redirect['query'] );

    							// Create the destination URL for this taxonomy.
    							$tax_url = parse_url( $tax_url );

    							if ( ! empty( $tax_url['query'] ) ) {
    								// Taxonomy accessible via ?taxonomy=...&term=... or any custom query var.
    								parse_str( $tax_url['query'], $query_vars );
    								$redirect['query'] = add_query_arg( $query_vars, $redirect['query'] );
    							} else {
    								// Taxonomy is accessible via a "pretty URL".
    								$redirect['path'] = $tax_url['path'];
    							}
    						} else {
    							// Some query vars are set via $_GET. Unset those from $_GET that exist via the rewrite.
    							foreach ( $qv_remove as $_qv ) {
    								if ( isset( $rewrite_vars[ $_qv ] ) ) {
    									$redirect['query'] = remove_query_arg( $_qv, $redirect['query'] );
    								}
    							}
    						}
    					}
    				}
    			}
    		} elseif ( is_single() && str_contains( $wp_rewrite->permalink_structure, '%category%' ) ) {
    			$category_name = get_query_var( 'category_name' );

    			if ( $category_name ) {
    				$category = get_category_by_path( $category_name );

    				if ( ! $category || is_wp_error( $category )
    					|| ! has_term( $category->term_id, 'category', $wp_query->get_queried_object_id() )
    				) {
    					$redirect_url = get_permalink( $wp_query->get_queried_object_id() );
    					$redirect_obj = get_post( $wp_query->get_queried_object_id() );
    				}
    			}
    		}

    		// Post paging.
    		if ( is_singular() && get_query_var( 'page' ) ) {
    			$page = get_query_var( 'page' );

    			if ( ! $redirect_url ) {
    				$redirect_url = get_permalink( get_queried_object_id() );
    				$redirect_obj = get_post( get_queried_object_id() );
    			}

    			if ( $page > 1 ) {
    				$redirect_url = trailingslashit( $redirect_url );

    				if ( is_front_page() ) {
    					$redirect_url .= user_trailingslashit( "$wp_rewrite->pagination_base/$page", 'paged' );
    				} else {
    					$redirect_url .= user_trailingslashit( $page, 'single_paged' );
    				}
    			}

    			$redirect['query'] = remove_query_arg( 'page', $redirect['query'] );
    		}

    		if ( get_query_var( 'sitemap' ) ) {
    			$redirect_url      = get_sitemap_url( get_query_var( 'sitemap' ), get_query_var( 'sitemap-subtype' ), get_query_var( 'paged' ) );
    			$redirect['query'] = remove_query_arg( array( 'sitemap', 'sitemap-subtype', 'paged' ), $redirect['query'] );
    		} elseif ( get_query_var( 'paged' ) || is_feed() || get_query_var( 'cpage' ) ) {
    			// Paging and feeds.
    			$paged = get_query_var( 'paged' );
    			$feed  = get_query_var( 'feed' );
    			$cpage = get_query_var( 'cpage' );

    			while ( preg_match( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", $redirect['path'] )
    				|| preg_match( '#/(comments/?)?(feed|rss2?|rdf|atom)(/+)?$#', $redirect['path'] )
    				|| preg_match( "#/{$wp_rewrite->comments_pagination_base}-[0-9]+(/+)?$#", $redirect['path'] )
    			) {
    				// Strip off any existing paging.
    				$redirect['path'] = preg_replace( "#/$wp_rewrite->pagination_base/?[0-9]+?(/+)?$#", '/', $redirect['path'] );
    				// Strip off feed endings.
    				$redirect['path'] = preg_replace( '#/(comments/?)?(feed|rss2?|rdf|atom)(/+|$)#', '/', $redirect['path'] );
    				// Strip off any existing comment paging.
    				$redirect['path'] = preg_replace( "#/{$wp_rewrite->comments_pagination_base}-[0-9]+?(/+)?$#", '/', $redirect['path'] );
    			}

    			$addl_path    = '';
    			$default_feed = get_default_feed();

    			if ( is_feed() && in_array( $feed, $wp_rewrite->feeds, true ) ) {
    				$addl_path = ! empty( $addl_path ) ? trailingslashit( $addl_path ) : '';

    				if ( ! is_singular() && get_query_var( 'withcomments' ) ) {
    					$addl_path .= 'comments/';
    				}

    				if ( ( 'rss' === $default_feed && 'feed' === $feed ) || 'rss' === $feed ) {
    					$format = ( 'rss2' === $default_feed ) ? '' : 'rss2';
    				} else {
    					$format = ( $default_feed === $feed || 'feed' === $feed ) ? '' : $feed;
    				}

    				$addl_path .= user_trailingslashit( 'feed/' . $format, 'feed' );

    				$redirect['query'] = remove_query_arg( 'feed', $redirect['query'] );
    			} elseif ( is_feed() && 'old' === $feed ) {
    				$old_feed_files = array(
    					'wp-atom.php'         => 'atom',
    					'wp-commentsrss2.php' => 'comments_rss2',
    					'wp-feed.php'         => $default_feed,
    					'wp-rdf.php'          => 'rdf',
    					'wp-rss.php'          => 'rss2',
    					'wp-rss2.php'         => 'rss2',
    				);

    				if ( isset( $old_feed_files[ basename( $redirect['path'] ) ] ) ) {
    					$redirect_url = get_feed_link( $old_feed_files[ basename( $redirect['path'] ) ] );

    					wp_redirect( $redirect_url, 301 );
    					die();
    				}
    			}

    			if ( $paged > 0 ) {
    				$redirect['query'] = remove_query_arg( 'paged', $redirect['query'] );

    				if ( ! is_feed() ) {
    					if ( ! is_single() ) {
    						$addl_path = ! empty( $addl_path ) ? trailingslashit( $addl_path ) : '';

    						if ( $paged > 1 ) {
    							$addl_path .= user_trailingslashit( "$wp_rewrite->pagination_base/$paged", 'paged' );
    						}
    					}
    				} elseif ( $paged > 1 ) {
    					$redirect['query'] = add_query_arg( 'paged', $paged, $redirect['query'] );
    				}
    			}

    			$default_comments_page = get_option( 'default_comments_page' );

    			if ( get_option( 'page_comments' )
    				&& ( 'newest' === $default_comments_page && $cpage > 0
    					|| 'newest' !== $default_comments_page && $cpage > 1 )
    			) {
    				$addl_path  = ( ! empty( $addl_path ) ? trailingslashit( $addl_path ) : '' );
    				$addl_path .= user_trailingslashit( $wp_rewrite->comments_pagination_base . '-' . $cpage, 'commentpaged' );

    				$redirect['query'] = remove_query_arg( 'cpage', $redirect['query'] );
    			}

    			// Strip off trailing /index.php/.
    			$redirect['path'] = preg_replace( '|/' . preg_quote( $wp_rewrite->index, '|' ) . '/?$|', '/', $redirect['path'] );
    			$redirect['path'] = user_trailingslashit( $redirect['path'] );

    			if ( ! empty( $addl_path )
    				&& $wp_rewrite->using_index_permalinks()
    				&& ! str_contains( $redirect['path'], '/' . $wp_rewrite->index . '/' )
    			) {
    				$redirect['path'] = trailingslashit( $redirect['path'] ) . $wp_rewrite->index . '/';
    			}

    			if ( ! empty( $addl_path ) ) {
    				$redirect['path'] = trailingslashit( $redirect['path'] ) . $addl_path;
    			}

    			$redirect_url = $redirect['scheme'] . '://' . $redirect['host'] . $redirect['path'];
    		}

    		if ( 'wp-register.php' === basename( $redirect['path'] ) ) {
    			if ( is_multisite() ) {
    				/** This filter is documented in wp-login.php */
    				$redirect_url = apply_filters( 'wp_signup_location', network_site_url( 'wp-signup.php' ) );
    			} else {
    				$redirect_url = wp_registration_url();
    			}

    			wp_redirect( $redirect_url, 301 );
    			die();
    		}
    	}

    	$is_attachment_redirect = false;

    	if ( is_attachment() && ! get_option( 'wp_attachment_pages_enabled' ) ) {
    		$attachment_id        = get_query_var( 'attachment_id' );
    		$attachment_post      = get_post( $attachment_id );
    		$attachment_parent_id = $attachment_post ? $attachment_post->post_parent : 0;
    		$attachment_url       = wp_get_attachment_url( $attachment_id );

    		if ( $attachment_url !== $redirect_url ) {
    			/*
    			 * If an attachment is attached to a post, it inherits the parent post's status.
    			 * Fetch the parent post to check its status later.
    			 */
    			if ( $attachment_parent_id ) {
    				$redirect_obj = get_post( $attachment_parent_id );
    			}

    			$redirect_url = $attachment_url;
    		}

    		$is_attachment_redirect = true;
    	}

    	$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );

    	// Tack on any additional query vars.
    	if ( $redirect_url && ! empty( $redirect['query'] ) ) {
    		parse_str( $redirect['query'], $_parsed_query );
    		$redirect = parse_url( $redirect_url );

    		if ( ! empty( $_parsed_query['name'] ) && ! empty( $redirect['query'] ) ) {
    			parse_str( $redirect['query'], $_parsed_redirect_query );

    			if ( empty( $_parsed_redirect_query['name'] ) ) {
    				unset( $_parsed_query['name'] );
    			}
    		}

    		$_parsed_query = array_combine(
    			rawurlencode_deep( array_keys( $_parsed_query ) ),
    			rawurlencode_deep( array_values( $_parsed_query ) )
    		);

    		$redirect_url = add_query_arg( $_parsed_query, $redirect_url );
    	}

    	if ( $redirect_url ) {
    		$redirect = parse_url( $redirect_url );
    	}

    	// www.example.com vs. example.com
    	$user_home = parse_url( home_url() );

    	if ( ! empty( $user_home['host'] ) ) {
    		$redirect['host'] = $user_home['host'];
    	}

    	if ( empty( $user_home['path'] ) ) {
    		$user_home['path'] = '/';
    	}

    	// Handle ports.
    	if ( ! empty( $user_home['port'] ) ) {
    		$redirect['port'] = $user_home['port'];
    	} else {
    		unset( $redirect['port'] );
    	}

    	// Notice prevention after new parse_url( $redirect_url ) calls
    	$redirect += array(
    		'host'   => '',
    		'path'   => '',
    		'query'  => '',
    		'scheme' => '',
    	);

    	// Trailing /index.php.
    	$redirect['path'] = preg_replace( '|/' . preg_quote( $wp_rewrite->index, '|' ) . '/*?$|', '/', $redirect['path'] );

    	$punctuation_pattern = implode(
    		'|',
    		array_map(
    			'preg_quote',
    			array(
    				' ',
    				'%20',  // Space.
    				'!',
    				'%21',  // Exclamation mark.
    				'"',
    				'%22',  // Double quote.
    				"'",
    				'%27',  // Single quote.
    				'(',
    				'%28',  // Opening bracket.
    				')',
    				'%29',  // Closing bracket.
    				',',
    				'%2C',  // Comma.
    				'.',
    				'%2E',  // Period.
    				';',
    				'%3B',  // Semicolon.
    				'{',
    				'%7B',  // Opening curly bracket.
    				'}',
    				'%7D',  // Closing curly bracket.
    				'%E2%80%9C', // Opening curly quote.
    				'%E2%80%9D', // Closing curly quote.
    			)
    		)
    	);

    	// Remove trailing spaces and end punctuation from the path.
    	$redirect['path'] = preg_replace( "#($punctuation_pattern)+$#", '', $redirect['path'] );

    	if ( ! empty( $redirect['query'] ) ) {
    		// Remove trailing spaces and end punctuation from certain terminating query string args.
    		$redirect['query'] = preg_replace( "#((^|&)(p|page_id|cat|tag)=[^&]*?)($punctuation_pattern)+$#", '$1', $redirect['query'] );

    		// Clean up empty query strings.
    		$redirect['query'] = trim( preg_replace( '#(^|&)(p|page_id|cat|tag)=?(&|$)#', '&', $redirect['query'] ), '&' );

    		// Redirect obsolete feeds.
    		$redirect['query'] = preg_replace( '#(^|&)feed=rss(&|$)#', '$1feed=rss2$2', $redirect['query'] );

    		// Remove redundant leading ampersands.
    		$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
    	}

    	// Strip /index.php/ when we're not using PATHINFO permalinks.
    	if ( ! $wp_rewrite->using_index_permalinks() ) {
    		$redirect['path'] = str_replace( '/' . $wp_rewrite->index . '/', '/', $redirect['path'] );
    	}

    	// Trailing slashes.
    	if ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks()
    		&& ! $is_attachment_redirect
    		&& ! is_404() && ( ! is_front_page() || is_front_page() && get_query_var( 'paged' ) > 1 )
    	) {
    		$user_ts_type = '';

    		if ( get_query_var( 'paged' ) > 0 ) {
    			$user_ts_type = 'paged';
    		} else {
    			foreach ( array( 'single', 'category', 'page', 'day', 'month', 'year', 'home' ) as $type ) {
    				$func = 'is_' . $type;
    				if ( call_user_func( $func ) ) {
    					$user_ts_type = $type;
    					break;
    				}
    			}
    		}

    		$redirect['path'] = user_trailingslashit( $redirect['path'], $user_ts_type );
    	} elseif ( is_front_page() ) {
    		$redirect['path'] = trailingslashit( $redirect['path'] );
    	}

    	// Remove trailing slash for robots.txt or sitemap requests.
    	if ( is_robots()
    		|| ! empty( get_query_var( 'sitemap' ) ) || ! empty( get_query_var( 'sitemap-stylesheet' ) )
    	) {
    		$redirect['path'] = untrailingslashit( $redirect['path'] );
    	}

    	// Strip multiple slashes out of the URL.
    	if ( str_contains( $redirect['path'], '//' ) ) {
    		$redirect['path'] = preg_replace( '|/+|', '/', $redirect['path'] );
    	}

    	// Always trailing slash the Front Page URL.
    	if ( trailingslashit( $redirect['path'] ) === trailingslashit( $user_home['path'] ) ) {
    		$redirect['path'] = trailingslashit( $redirect['path'] );
    	}

    	$original_host_low = strtolower( $original['host'] );
    	$redirect_host_low = strtolower( $redirect['host'] );

    	/*
    	 * Ignore differences in host capitalization, as this can lead to infinite redirects.
    	 * Only redirect no-www <=> yes-www.
    	 */
    	if ( $original_host_low === $redirect_host_low
    		|| ( 'www.' . $original_host_low !== $redirect_host_low
    			&& 'www.' . $redirect_host_low !== $original_host_low )
    	) {
    		$redirect['host'] = $original['host'];
    	}

    	$compare_original = array( $original['host'], $original['path'] );

    	if ( ! empty( $original['port'] ) ) {
    		$compare_original[] = $original['port'];
    	}

    	if ( ! empty( $original['query'] ) ) {
    		$compare_original[] = $original['query'];
    	}

    	$compare_redirect = array( $redirect['host'], $redirect['path'] );

    	if ( ! empty( $redirect['port'] ) ) {
    		$compare_redirect[] = $redirect['port'];
    	}

    	if ( ! empty( $redirect['query'] ) ) {
    		$compare_redirect[] = $redirect['query'];
    	}

    	if ( $compare_original !== $compare_redirect ) {
    		$redirect_url = $redirect['scheme'] . '://' . $redirect['host'];

    		if ( ! empty( $redirect['port'] ) ) {
    			$redirect_url .= ':' . $redirect['port'];
    		}

    		$redirect_url .= $redirect['path'];

    		if ( ! empty( $redirect['query'] ) ) {
    			$redirect_url .= '?' . $redirect['query'];
    		}
    	}

    	if ( ! $redirect_url || $redirect_url === $requested_url ) {
    		return;
    	}

    	// Hex-encoded octets are case-insensitive.
    	if ( str_contains( $requested_url, '%' ) ) {
    		if ( ! function_exists( 'lowercase_octets' ) ) {
    			/**
    			 * Converts the first hex-encoded octet match to lowercase.
    			 *
    			 * @since 3.1.0
    			 * @ignore
    			 *
    			 * @param array $matches Hex-encoded octet matches for the requested URL.
    			 * @return string Lowercased version of the first match.
    			 */
    			function lowercase_octets( $matches ) {
    				return strtolower( $matches[0] );
    			}
    		}

    		$requested_url = preg_replace_callback( '|%[a-fA-F0-9][a-fA-F0-9]|', 'lowercase_octets', $requested_url );
    	}

    	if ( $redirect_obj instanceof WP_Post ) {
    		$post_status_obj = get_post_status_object( get_post_status( $redirect_obj ) );
    		/*
    		 * Unset the redirect object and URL if they are not readable by the user.
    		 * This condition is a little confusing as the condition needs to pass if
    		 * the post is not readable by the user. That's why there are ! (not) conditions
    		 * throughout.
    		 */
    		if (
    			// Private post statuses only redirect if the user can read them.
    			! (
    				$post_status_obj->private &&
    				current_user_can( 'read_post', $redirect_obj->ID )
    			) &&
    			// For other posts, only redirect if publicly viewable.
    			! is_post_publicly_viewable( $redirect_obj )
    		) {
    			$redirect_obj = false;
    			$redirect_url = false;
    		}
    	}

    	/**
    	 * Filters the canonical redirect URL.
    	 *
    	 * Returning false to this filter will cancel the redirect.
    	 *
    	 * @since 2.3.0
    	 *
    	 * @param string $redirect_url  The redirect URL.
    	 * @param string $requested_url The requested URL.
    	 */
    	$redirect_url = apply_filters( 'redirect_canonical', $redirect_url, $requested_url );

    	// Yes, again -- in case the filter aborted the request.
    	if ( ! $redirect_url || strip_fragment_from_url( $redirect_url ) === strip_fragment_from_url( $requested_url ) ) {
    		return;
    	}

    	if ( $do_redirect ) {
    		// Protect against chained redirects.
    		if ( ! redirect_canonical( $redirect_url, false ) ) {
    			wp_redirect( $redirect_url, 301 );
    			exit;
    		} else {
    			// Debug.
    			// die("1: $redirect_url<br />2: " . redirect_canonical( $redirect_url, false ) );
    			return;
    		}
    	} else {
    		return $redirect_url;
    	}
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-includes/canonical.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/6.9.4/src/wp-includes/canonical.php#L42)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/6.9.4/src/wp-includes/canonical.php#L42-L849)

## 󠀁[Hooks](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#hooks)󠁿

 [apply_filters( ‘redirect_canonical’, string $redirect_url, string $requested_url )](https://developer.wordpress.org/reference/hooks/redirect_canonical/)

Filters the canonical redirect URL.

 [apply_filters( ‘wp_signup_location’, string $sign_up_url )](https://developer.wordpress.org/reference/hooks/wp_signup_location/)

Filters the Multisite sign up URL.

## 󠀁[Related](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#related)󠁿

| Uses | Description | 
| [is_post_publicly_viewable()](https://developer.wordpress.org/reference/functions/is_post_publicly_viewable/)`wp-includes/post.php` |

Determines whether a post is publicly viewable.

  | 
| [get_sitemap_url()](https://developer.wordpress.org/reference/functions/get_sitemap_url/)`wp-includes/sitemaps.php` |

Retrieves the full URL for a sitemap.

  | 
| [is_favicon()](https://developer.wordpress.org/reference/functions/is_favicon/)`wp-includes/query.php` |

Is the query for the favicon.ico file?

  | 
| [strip_fragment_from_url()](https://developer.wordpress.org/reference/functions/strip_fragment_from_url/)`wp-includes/canonical.php` |

Strips the #fragment from a URL, if one is present.

  | 
| [has_term()](https://developer.wordpress.org/reference/functions/has_term/)`wp-includes/category-template.php` |

Checks if the current post has any of given terms.

  | 
| [rawurlencode_deep()](https://developer.wordpress.org/reference/functions/rawurlencode_deep/)`wp-includes/formatting.php` |

Navigates through an array, object, or scalar, and raw-encodes the values to be used in a URL.

  | 
| [untrailingslashit()](https://developer.wordpress.org/reference/functions/untrailingslashit/)`wp-includes/formatting.php` |

Removes trailing forward slashes and backslashes if they exist.

  | 
| [wp_verify_nonce()](https://developer.wordpress.org/reference/functions/wp_verify_nonce/)`wp-includes/pluggable.php` |

Verifies that a correct security nonce was used with time limit.

  | 
| [wp_redirect()](https://developer.wordpress.org/reference/functions/wp_redirect/)`wp-includes/pluggable.php` |

Redirects to another page.

  | 
| [wp_registration_url()](https://developer.wordpress.org/reference/functions/wp_registration_url/)`wp-includes/general-template.php` |

Returns the URL that allows the user to register on the site.

  | 
| [WP_Query::get_queried_object_id()](https://developer.wordpress.org/reference/classes/wp_query/get_queried_object_id/)`wp-includes/class-wp-query.php` |

Retrieves the ID of the currently queried object.

  | 
| [WP_Query::get_queried_object()](https://developer.wordpress.org/reference/classes/wp_query/get_queried_object/)`wp-includes/class-wp-query.php` |

Retrieves the currently queried object.

  | 
| [is_preview()](https://developer.wordpress.org/reference/functions/is_preview/)`wp-includes/query.php` |

Determines whether the query is for a post or page preview.

  | 
| [is_search()](https://developer.wordpress.org/reference/functions/is_search/)`wp-includes/query.php` |

Determines whether the query is for a search.

  | 
| [is_trackback()](https://developer.wordpress.org/reference/functions/is_trackback/)`wp-includes/query.php` |

Determines whether the query is for a trackback endpoint call.

  | 
| [is_singular()](https://developer.wordpress.org/reference/functions/is_singular/)`wp-includes/query.php` |

Determines whether the query is for an existing single post of any post type (post, attachment, page, custom post types).

  | 
| [is_404()](https://developer.wordpress.org/reference/functions/is_404/)`wp-includes/query.php` |

Determines whether the query has resulted in a 404 (returns no results).

  | 
| [is_single()](https://developer.wordpress.org/reference/functions/is_single/)`wp-includes/query.php` |

Determines whether the query is for an existing single post.

  | 
| [is_year()](https://developer.wordpress.org/reference/functions/is_year/)`wp-includes/query.php` |

Determines whether the query is for an existing year archive.

  | 
| [is_robots()](https://developer.wordpress.org/reference/functions/is_robots/)`wp-includes/query.php` |

Is the query for the robots.txt file?

  | 
| [is_feed()](https://developer.wordpress.org/reference/functions/is_feed/)`wp-includes/query.php` |

Determines whether the query is for a feed.

  | 
| [is_attachment()](https://developer.wordpress.org/reference/functions/is_attachment/)`wp-includes/query.php` |

Determines whether the query is for an existing attachment page.

  | 
| [is_page()](https://developer.wordpress.org/reference/functions/is_page/)`wp-includes/query.php` |

Determines whether the query is for an existing single page.

  | 
| [is_month()](https://developer.wordpress.org/reference/functions/is_month/)`wp-includes/query.php` |

Determines whether the query is for an existing month archive.

  | 
| [is_day()](https://developer.wordpress.org/reference/functions/is_day/)`wp-includes/query.php` |

Determines whether the query is for an existing day archive.

  | 
| [is_home()](https://developer.wordpress.org/reference/functions/is_home/)`wp-includes/query.php` |

Determines whether the query is for the blog homepage.

  | 
| [is_date()](https://developer.wordpress.org/reference/functions/is_date/)`wp-includes/query.php` |

Determines whether the query is for an existing date archive.

  | 
| [is_author()](https://developer.wordpress.org/reference/functions/is_author/)`wp-includes/query.php` |

Determines whether the query is for an existing author archive page.

  | 
| [is_category()](https://developer.wordpress.org/reference/functions/is_category/)`wp-includes/query.php` |

Determines whether the query is for an existing category archive page.

  | 
| [is_tag()](https://developer.wordpress.org/reference/functions/is_tag/)`wp-includes/query.php` |

Determines whether the query is for an existing tag archive page.

  | 
| [is_tax()](https://developer.wordpress.org/reference/functions/is_tax/)`wp-includes/query.php` |

Determines whether the query is for an existing custom taxonomy archive page.

  | 
| [is_front_page()](https://developer.wordpress.org/reference/functions/is_front_page/)`wp-includes/query.php` |

Determines whether the query is for the front page of the site.

  | 
| [get_query_var()](https://developer.wordpress.org/reference/functions/get_query_var/)`wp-includes/query.php` |

Retrieves the value of a query variable in the [WP_Query](https://developer.wordpress.org/reference/classes/wp_query/) class.

  | 
| [get_queried_object_id()](https://developer.wordpress.org/reference/functions/get_queried_object_id/)`wp-includes/query.php` |

Retrieves the ID of the currently queried object.

  | 
| [get_category_by_path()](https://developer.wordpress.org/reference/functions/get_category_by_path/)`wp-includes/category.php` |

Retrieves a category based on URL containing the category slug.

  | 
| [wp_checkdate()](https://developer.wordpress.org/reference/functions/wp_checkdate/)`wp-includes/functions.php` |

Tests if the supplied date is valid for the Gregorian calendar.

  | 
| [is_ssl()](https://developer.wordpress.org/reference/functions/is_ssl/)`wp-includes/load.php` |

Determines if SSL is used.

  | 
| [iis7_supports_permalinks()](https://developer.wordpress.org/reference/functions/iis7_supports_permalinks/)`wp-includes/functions.php` |

Checks if IIS 7+ supports pretty permalinks.

  | 
| [remove_query_arg()](https://developer.wordpress.org/reference/functions/remove_query_arg/)`wp-includes/functions.php` |

Removes an item or items from a query string.

  | 
| [get_term_link()](https://developer.wordpress.org/reference/functions/get_term_link/)`wp-includes/taxonomy.php` |

Generates a permalink for a taxonomy term archive.

  | 
| [network_site_url()](https://developer.wordpress.org/reference/functions/network_site_url/)`wp-includes/link-template.php` |

Retrieves the site URL for the current network.

  | 
| [get_post_comments_feed_link()](https://developer.wordpress.org/reference/functions/get_post_comments_feed_link/)`wp-includes/link-template.php` |

Retrieves the permalink for the post comments feed.

  | 
| [get_month_link()](https://developer.wordpress.org/reference/functions/get_month_link/)`wp-includes/link-template.php` |

Retrieves the permalink for the month archives with year.

  | 
| [get_day_link()](https://developer.wordpress.org/reference/functions/get_day_link/)`wp-includes/link-template.php` |

Retrieves the permalink for the day archives with year and month.

  | 
| [get_feed_link()](https://developer.wordpress.org/reference/functions/get_feed_link/)`wp-includes/link-template.php` |

Retrieves the permalink for the feed type.

  | 
| [get_year_link()](https://developer.wordpress.org/reference/functions/get_year_link/)`wp-includes/link-template.php` |

Retrieves the permalink for the year archives.

  | 
| [get_attachment_link()](https://developer.wordpress.org/reference/functions/get_attachment_link/)`wp-includes/link-template.php` |

Retrieves the permalink for an attachment.

  | 
| [user_trailingslashit()](https://developer.wordpress.org/reference/functions/user_trailingslashit/)`wp-includes/link-template.php` |

Retrieves a trailing-slashed string if the site is set for adding trailing slashes.

  | 
| [get_default_feed()](https://developer.wordpress.org/reference/functions/get_default_feed/)`wp-includes/feed.php` |

Retrieves the default feed.

  | 
| [wp_get_attachment_url()](https://developer.wordpress.org/reference/functions/wp_get_attachment_url/)`wp-includes/post.php` |

Retrieves the URL for an attachment.

  | 
| [get_post_status()](https://developer.wordpress.org/reference/functions/get_post_status/)`wp-includes/post.php` |

Retrieves the post status based on the post ID.

  | 
| [get_post_status_object()](https://developer.wordpress.org/reference/functions/get_post_status_object/)`wp-includes/post.php` |

Retrieves a post status object by name.

  | 
| [WP_Rewrite::using_index_permalinks()](https://developer.wordpress.org/reference/classes/wp_rewrite/using_index_permalinks/)`wp-includes/class-wp-rewrite.php` |

Determines whether permalinks are being used and rewrite module is not enabled.

  | 
| [_remove_qs_args_if_not_in_url()](https://developer.wordpress.org/reference/functions/_remove_qs_args_if_not_in_url/)`wp-includes/canonical.php` |

Removes arguments from a query string if they are not present in a URL DO NOT use this in plugin code.

  | 
| [redirect_guess_404_permalink()](https://developer.wordpress.org/reference/functions/redirect_guess_404_permalink/)`wp-includes/canonical.php` |

Attempts to guess the correct URL for a 404 request based on query vars.

  | 
| [WP_Rewrite::using_permalinks()](https://developer.wordpress.org/reference/classes/wp_rewrite/using_permalinks/)`wp-includes/class-wp-rewrite.php` |

Determines whether permalinks are being used.

  | 
| [redirect_canonical()](https://developer.wordpress.org/reference/functions/redirect_canonical/)`wp-includes/canonical.php` |

Redirects incoming links to the proper URL based on the site url.

  | 
| [get_author_posts_url()](https://developer.wordpress.org/reference/functions/get_author_posts_url/)`wp-includes/author-template.php` |

Retrieves the URL to the author page for the user with the ID provided.

  | 
| [current_user_can()](https://developer.wordpress.org/reference/functions/current_user_can/)`wp-includes/capabilities.php` |

Returns whether the current user has the specified capability.

  | 
| [trailingslashit()](https://developer.wordpress.org/reference/functions/trailingslashit/)`wp-includes/formatting.php` |

Appends a trailing slash.

  | 
| [get_userdata()](https://developer.wordpress.org/reference/functions/get_userdata/)`wp-includes/pluggable.php` |

Retrieves user info by user ID.

  | 
| [is_admin()](https://developer.wordpress.org/reference/functions/is_admin/)`wp-includes/load.php` |

Determines whether the current request is for an administrative interface page.

  | 
| [is_multisite()](https://developer.wordpress.org/reference/functions/is_multisite/)`wp-includes/load.php` |

Determines whether Multisite is enabled.

  | 
| [add_query_arg()](https://developer.wordpress.org/reference/functions/add_query_arg/)`wp-includes/functions.php` |

Retrieves a modified URL query string.

  | 
| [get_taxonomy()](https://developer.wordpress.org/reference/functions/get_taxonomy/)`wp-includes/taxonomy.php` |

Retrieves the taxonomy object of $taxonomy.

  | 
| [home_url()](https://developer.wordpress.org/reference/functions/home_url/)`wp-includes/link-template.php` |

Retrieves the URL for the current site where the front end is accessible.

  | 
| [get_permalink()](https://developer.wordpress.org/reference/functions/get_permalink/)`wp-includes/link-template.php` |

Retrieves the full permalink for the current post or post ID.

  | 
| [apply_filters()](https://developer.wordpress.org/reference/functions/apply_filters/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to a filter hook.

  | 
| [get_option()](https://developer.wordpress.org/reference/functions/get_option/)`wp-includes/option.php` |

Retrieves an option value based on an option name.

  | 
| [get_post()](https://developer.wordpress.org/reference/functions/get_post/)`wp-includes/post.php` |

Retrieves post data given a post ID or post object.

  | 
| [get_post_type_object()](https://developer.wordpress.org/reference/functions/get_post_type_object/)`wp-includes/post.php` |

Retrieves a post type object by name.

  | 
| [wpdb::get_results()](https://developer.wordpress.org/reference/classes/wpdb/get_results/)`wp-includes/class-wpdb.php` |

Retrieves an entire SQL result set from the database (i.e., many rows).

  | 
| [wpdb::get_var()](https://developer.wordpress.org/reference/classes/wpdb/get_var/)`wp-includes/class-wpdb.php` |

Retrieves one value from the database.

  | 
| [wpdb::prepare()](https://developer.wordpress.org/reference/classes/wpdb/prepare/)`wp-includes/class-wpdb.php` |

Prepares a SQL query for safe execution.

  | 
| [is_wp_error()](https://developer.wordpress.org/reference/functions/is_wp_error/)`wp-includes/load.php` |

Checks whether the given variable is a WordPress Error.

  |

[Show 70 more](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#)

| Used by | Description | 
| [redirect_canonical()](https://developer.wordpress.org/reference/functions/redirect_canonical/)`wp-includes/canonical.php` |

Redirects incoming links to the proper URL based on the site url.

  |

## 󠀁[Changelog](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#changelog)󠁿

| Version | Description | 
| [2.3.0](https://developer.wordpress.org/reference/since/2.3.0/) | Introduced. |

## 󠀁[User Contributed Notes](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#user-contributed-notes)󠁿

 1.   [Skip to note 3 content](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#comment-content-6106)
 2.    [Mishra Vinay](https://profiles.wordpress.org/misvinay/)  [  4 years ago  ](https://developer.wordpress.org/reference/functions/redirect_canonical/#comment-6106)
 3.  [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fredirect_canonical%2F%23comment-6106)
     Vote results for this note: 1[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fredirect_canonical%2F%23comment-6106)
 4.      ```php
         /**
          * Creates 301 redirects canonical
          */
     
         function wpdocs_redirect_can() {
            // Is single Post
            if ( is_single() ) {
               global $wp;
               $wp->parse_request();
     
               $current_url = trim( home_url( $wp->request ), '/' );
               $redirect = get_permalink();
               $surl = trim( $redirect, '/' );
     
               if ( $current_url !== $surl ) {
                  wp_redirect( $redirect, 301 );
                  exit;
               }
            } 
         }
         add_action( 'template_redirect', 'wpdocs_redirect_can' );
         ```
     
 5.  I got multiple emails about canonical issue. If I have 2 categories both category
     URL was indexed with proper one canonical tag and both pages able to access.
 6.  This has not been automatically done by WP. Many paid plugins are available but
     programmatically I have done above code and working.
 7.   [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fredirect_canonical%2F%3Freplytocom%3D6106%23feedback-editor-6106)
 8.   [Skip to note 4 content](https://developer.wordpress.org/reference/functions/redirect_canonical/?output_format=md#comment-content-2068)
 9.    [Khoi Pro](https://profiles.wordpress.org/khoipro/)  [  9 years ago  ](https://developer.wordpress.org/reference/functions/redirect_canonical/#comment-2068)
 10. [You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fredirect_canonical%2F%23comment-2068)
     Vote results for this note: 0[You must log in to vote on the helpfulness of this note](https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fredirect_canonical%2F%23comment-2068)
 11. Remove Redirect for public var like ‘year’ in Custom Taxonomy.
 12. For example, a link: /?event_category=xxx?year=2017
      If you don’t add this filter:–
     It redirects to /2016/ If you use this redirect: – It remains at page /?event_category
     =xxx
 13. This code is helpful for creating a filter in Taxonomies.
 14.     ```php
             add_filter( 'redirect_canonical', 'pick_event_year_redirect', 10 );
         	function pick_event_year_redirect( $redirect_url ) {
         		if ( is_tax( 'event_category' ) && is_year() ) {
         			return '';
         		}
     
         		return $redirect_url;
         	}
         ```
     
 15.  [Log in to add feedback](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fredirect_canonical%2F%3Freplytocom%3D2068%23feedback-editor-2068)

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fredirect_canonical%2F)
before being able to contribute a note or feedback.