Commit 6aaf57b341 for wordpress.org
commit 6aaf57b3419614b5a7a6d11183595d657ad3fca3
Author: jorbin <jorbin@git.wordpress.org>
Date: Sat Nov 14 03:58:01 2026 +0000
Rewrite Rules: Send the random content redirect on template_redirect.
The random content redirect was sent from `WP::handle_random()` before the `template_redirect` action fired. Plugins that restrict access to a site on that action never saw the request, so logged-out visitors to a locked site were still redirected to post URLs. The redirect is now sent on `template_redirect` at priority 100, and `redirect_canonical()` leaves these requests alone so they are not redirected twice.
Developed in: https://github.com/WordPress/wordpress-develop/pull/15912
Follow-up to r64402, r65440.
Props jorbin, renehermi, aryanjasala, rcwpdev.
Fixes #66661. See #64498.
Built from https://develop.svn.wordpress.org/trunk@65526
git-svn-id: http://core.svn.wordpress.org/trunk@64599 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/canonical.php b/wp-includes/canonical.php
index 2fb3d74bb9..5ec43f99c4 100644
--- a/wp-includes/canonical.php
+++ b/wp-includes/canonical.php
@@ -28,11 +28,12 @@
*
* @since 2.3.0
*
- * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
+ * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
* @global bool $is_IIS
- * @global WP_Query $wp_query WordPress Query object.
- * @global wpdb $wpdb WordPress database abstraction object.
- * @global WP $wp Current WordPress environment instance.
+ * @global WP_Query $wp_query WordPress Query object.
+ * @global WP_Query $wp_the_query WordPress main Query object.
+ * @global wpdb $wpdb WordPress database abstraction object.
+ * @global WP $wp Current WordPress environment instance.
*
* @param string $requested_url Optional. The URL that was requested, used to
* figure if redirect is needed.
@@ -41,12 +42,24 @@
* @phpstan-return ( $do_redirect is true ? null : string|null )
*/
function redirect_canonical( $requested_url = null, $do_redirect = true ) {
- global $wp_rewrite, $is_IIS, $wp_query, $wpdb, $wp;
+ global $wp_rewrite, $is_IIS, $wp_query, $wp_the_query, $wpdb, $wp;
if ( isset( $_SERVER['REQUEST_METHOD'] ) && ! in_array( strtoupper( $_SERVER['REQUEST_METHOD'] ), array( 'GET', 'HEAD' ), true ) ) {
return null;
}
+ /*
+ * Random content requests with a selected post are redirected to that post by
+ * wp_random_content_redirect() later on the `template_redirect` action. A canonical
+ * redirect would redirect the request twice and may drop the `random` query variable.
+ */
+ if ( $wp_the_query instanceof WP_Query
+ && wp_is_random_content_query( $wp_the_query )
+ && $wp_the_query->post instanceof WP_Post
+ ) {
+ return null;
+ }
+
/*
* 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.
diff --git a/wp-includes/class-wp.php b/wp-includes/class-wp.php
index d7c2add374..b9b86116d3 100644
--- a/wp-includes/class-wp.php
+++ b/wp-includes/class-wp.php
@@ -719,6 +719,10 @@ class WP {
* - {@see wp_random_content_posts_orderby()} on the {@see 'posts_orderby'} filter.
* - {@see wp_random_content_post_limits()} on the {@see 'post_limits'} filter.
*
+ * If a post is selected, the redirect is sent by {@see wp_random_content_redirect()}
+ * on the {@see 'template_redirect'} action at priority 100, so the request is set up
+ * and the {@see 'wp'} action has fired before the redirect.
+ *
* If no post is selected, for example on an empty archive, the request is a 404 as
* there is no post to redirect to. If a post is selected, the request ends with
* the redirect. Otherwise the request continues with the results of the main
@@ -748,9 +752,13 @@ class WP {
remove_filter( 'posts_orderby', 'wp_random_content_posts_orderby', 20 );
remove_filter( 'post_limits', 'wp_random_content_post_limits', 20 );
- wp_random_content_redirect();
+ if ( ! wp_is_random_content_query( $wp_the_query ) ) {
+ return true;
+ }
- if ( wp_is_random_content_query( $wp_the_query ) && ! $wp_the_query->post instanceof WP_Post ) {
+ if ( $wp_the_query->post instanceof WP_Post ) {
+ add_action( 'template_redirect', 'wp_random_content_redirect', 100 );
+ } else {
$wp_the_query->set_404();
status_header( 404 );
nocache_headers();
diff --git a/wp-includes/query.php b/wp-includes/query.php
index 7a21ba50df..a4ceff66f7 100644
--- a/wp-includes/query.php
+++ b/wp-includes/query.php
@@ -1464,10 +1464,14 @@ function wp_random_content_post_limits( $limits, WP_Query $query ): string {
/**
* Redirects random content requests to the randomly selected post.
*
- * Called by {@see WP::handle_random()} immediately after the main query selects the
- * random post, to avoid unnecessary processing before the redirect. The headers
- * preventing the response being cached or indexed are sent as soon as a post is
- * selected, before {@see WP::send_headers()}, so they are sent with the redirect.
+ * Added to the {@see 'template_redirect'} action at priority 100 by
+ * {@see WP::handle_random()} once the main query has selected the random post, so the
+ * redirect is sent after the request is set up and the {@see 'wp'} action has fired.
+ * The headers preventing the redirect being cached or indexed are sent with it.
+ *
+ * The post is read from the main query rather than the current query, so the redirect
+ * is still sent when an earlier callback replaces the current query, for example by
+ * calling {@see query_posts()}.
*
* The request ends once a post is selected. The redirect is to the post's permalink
* as returned by {@see get_permalink()}, including a permalink filtered to be on
@@ -1478,12 +1482,16 @@ function wp_random_content_post_limits( $limits, WP_Query $query ): string {
*
* @since 7.2.0
*
- * @global WP_Query $wp_query WordPress Query object.
+ * @global WP_Query $wp_the_query WordPress main Query object.
*/
function wp_random_content_redirect(): void {
- global $wp_query;
+ global $wp_the_query;
- if ( ! wp_is_random_content_query( $wp_query ) || ! $wp_query->post instanceof WP_Post ) {
+ if (
+ ! $wp_the_query instanceof WP_Query
+ || ! wp_is_random_content_query( $wp_the_query )
+ || ! $wp_the_query->post instanceof WP_Post
+ ) {
return;
}
@@ -1493,7 +1501,7 @@ function wp_random_content_redirect(): void {
header( 'X-Robots-Tag: noindex, follow' );
}
- $location = get_permalink( $wp_query->post );
+ $location = get_permalink( $wp_the_query->post );
wp_redirect( $location, 302 );
exit;
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 38d2c0162a..aaf3efbc3b 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-beta5-65525';
+$wp_version = '7.2-beta5-65526';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.