Commit 464b99d173 for wordpress.org

commit 464b99d1736e48334e03dbef30b270ee0dccd2aa
Author: mcsf <mcsf@git.wordpress.org>
Date:   Mon Sep 21 13:06:52 2026 +0000

    Support random content redirects via ?random qarg

    Add opt-in support for random content redirects, so that a page request with the `?random` query argument set will return a 302 redirect to a randomly selected published post.

    The pool of eligible posts may be filtered with two additional query arguments:
    - `random_post_type`
    - `random_cat_id`

    The feature may be opted into using:

    {{{
    add_filter( 'enable_random_content_redirect', '__return_true' );
    }}}

    Developed in: https://github.com/WordPress/wordpress-develop/pull/13022

    Props mlaetitia.
    Fixes #64498.


    Built from https://develop.svn.wordpress.org/trunk@63767


    git-svn-id: http://core.svn.wordpress.org/trunk@62939 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-includes/default-filters.php b/wp-includes/default-filters.php
index 025a371781..c8b77e96d4 100644
--- a/wp-includes/default-filters.php
+++ b/wp-includes/default-filters.php
@@ -492,6 +492,9 @@ add_action( 'attachment_updated', 'wp_check_for_changed_slugs', 12, 3 );
 add_action( 'post_updated', 'wp_check_for_changed_dates', 12, 3 );
 add_action( 'attachment_updated', 'wp_check_for_changed_dates', 12, 3 );

+// Redirect random content requests (disabled by default, see 'enable_random_content_redirect').
+add_action( 'template_redirect', 'wp_random_content_redirect' );
+
 // Nonce check for post previews.
 add_action( 'init', '_show_post_preview' );

diff --git a/wp-includes/query.php b/wp-includes/query.php
index 42592002c1..4bcf602fd6 100644
--- a/wp-includes/query.php
+++ b/wp-includes/query.php
@@ -1239,6 +1239,122 @@ function _find_post_by_old_date( $post_type ) {
 	return $id;
 }

+/**
+ * Redirects requests for random content to a randomly selected published post.
+ *
+ * Handles requests using the `random` query parameter, e.g. `example.com/?random`.
+ * The `random_post_type` parameter restricts the pick to a post type (default `post`),
+ * and the `random_cat_id` parameter restricts it to a category (for post types using
+ * the `category` taxonomy). Only published, non-password-protected content from
+ * viewable post types is considered, and only GET/HEAD requests are handled.
+ *
+ * Disabled by default. To enable:
+ *
+ *     add_filter( 'enable_random_content_redirect', '__return_true' );
+ *
+ * @since 7.2.0
+ */
+function wp_random_content_redirect() {
+	// The `random` parameter is a flag, present with or without a value.
+	if ( ! isset( $_GET['random'] ) ) {
+		return;
+	}
+
+	/**
+	 * Filters whether random content redirects are enabled.
+	 *
+	 * @since 7.2.0
+	 *
+	 * @param bool $enabled Whether `?random` requests redirect to random content. Default false.
+	 */
+	if ( ! apply_filters( 'enable_random_content_redirect', false ) ) {
+		return;
+	}
+
+	$request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( $_SERVER['REQUEST_METHOD'] ) : '';
+
+	if ( ! in_array( $request_method, array( 'GET', 'HEAD' ), true ) ) {
+		return;
+	}
+
+	$post_type = 'post';
+
+	if ( isset( $_GET['random_post_type'] ) ) {
+		$post_type = sanitize_key( wp_unslash( $_GET['random_post_type'] ) );
+	}
+
+	$post_type_object = get_post_type_object( $post_type );
+
+	if ( ! $post_type_object || ! is_post_type_viewable( $post_type_object ) ) {
+		return;
+	}
+
+	$args = array(
+		'post_type'              => $post_type,
+		'post_status'            => 'publish',
+		'has_password'           => false,
+		'posts_per_page'         => 1,
+		'orderby'                => 'ID',
+		'order'                  => 'ASC',
+		'ignore_sticky_posts'    => true,
+		'update_post_term_cache' => false,
+		'update_post_meta_cache' => false,
+	);
+
+	if ( isset( $_GET['random_cat_id'] ) ) {
+		$cat_id = (int) wp_unslash( $_GET['random_cat_id'] );
+
+		if ( $cat_id < 1 ) {
+			return;
+		}
+
+		$args['cat'] = $cat_id;
+	}
+
+	// Pick via COUNT plus a random OFFSET rather than `ORDER BY RAND()`,
+	// which randomizes and sorts every candidate row on each request.
+	$query      = new WP_Query( $args );
+	$post_count = (int) $query->found_posts;
+
+	if ( $post_count > 1 ) {
+		$offset = wp_rand( 0, $post_count - 1 );
+
+		if ( $offset > 0 ) {
+			$args['offset']        = $offset;
+			$args['no_found_rows'] = true;
+			$args['cache_results'] = false;
+
+			$query = new WP_Query( $args );
+		}
+	}
+
+	if ( empty( $query->posts ) ) {
+		return;
+	}
+
+	$link = get_permalink( $query->posts[0] );
+
+	/**
+	 * Filters the random content redirect URL.
+	 *
+	 * Returning a falsey value cancels the redirect.
+	 *
+	 * @since 7.2.0
+	 *
+	 * @param string $link The redirect URL.
+	 */
+	$link = apply_filters( 'random_content_redirect_url', $link );
+
+	if ( ! $link ) {
+		return;
+	}
+
+	// Temporary redirect, so clients and intermediary caches do not cache the randomly picked target.
+	nocache_headers();
+	wp_safe_redirect( $link, 302 );
+	exit;
+}
+
 /**
  * Set up global post data.
  *
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 076fa84050..460931f708 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-alpha-63766';
+$wp_version = '7.2-alpha-63767';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.