From 74ec54ed402d368f129f7f3100348ad38204e60c Mon Sep 17 00:00:00 2001 From: Aryan Jasala Date: Fri, 23 Oct 2026 01:31:14 +0530 Subject: [PATCH 1/9] Rewrite Rules: Sort only post IDs when selecting random content. Random content requests force WP_Query not to split the request, so ORDER BY RAND() runs on full wp_posts rows. The database copies every eligible row, including post_content, into a temporary table to sort it. Let the request split as usual. The random order then applies to post IDs and the selected post is loaded by ID, from the object cache when available. Queries ordered by RAND() are never cached by WP_Query, so each request still selects a new post. With 200,000 posts (about 640 MB of content) on MariaDB 11.4 with the data in the buffer pool, ten requests to /random/ took 5.0 to 7.8 seconds (median 5.9) before and 0.22 to 0.54 seconds (median 0.23) after. See #64498. --- src/wp-includes/default-filters.php | 1 - src/wp-includes/query.php | 21 ------- .../tests/query/randomContentRedirect.php | 57 +++++++++++++------ 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index c229fbfcb85e0..da9f60cfd42db 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -496,7 +496,6 @@ add_action( 'attachment_updated', 'wp_check_for_changed_dates', 12, 3 ); // Random content redirects, see WP::handle_random(). -add_filter( 'split_the_query', 'wp_random_content_split_the_query', 10, 2 ); add_action( 'wp_after_insert_post', 'wp_random_content_flush_rewrite_rules_for_post', 10, 4 ); add_action( 'after_delete_post', 'wp_random_content_flush_rewrite_rules_for_post', 10, 2 ); diff --git a/src/wp-includes/query.php b/src/wp-includes/query.php index 212ac1619e87f..4cafca3d7c068 100644 --- a/src/wp-includes/query.php +++ b/src/wp-includes/query.php @@ -1461,27 +1461,6 @@ function wp_random_content_post_limits( $limits, WP_Query $query ): string { return (string) $limits; } -/** - * Prevents the random content query from being split into multiple database queries. - * - * Randomly ordered queries are not cached, so there is no benefit to querying the post - * IDs separately to the post objects. Disabling the split allows the random post to be - * retrieved in a single database query. - * - * @since 7.2.0 - * - * @param bool $split_the_query Whether or not to split the query. - * @param WP_Query $query The WP_Query instance. - * @return bool Whether or not to split the query. - */ -function wp_random_content_split_the_query( $split_the_query, WP_Query $query ): bool { - if ( wp_is_random_content_query( $query ) ) { - return false; - } - - return (bool) $split_the_query; -} - /** * Redirects random content requests to the randomly selected post. * diff --git a/tests/phpunit/tests/query/randomContentRedirect.php b/tests/phpunit/tests/query/randomContentRedirect.php index d8854593000f6..a29a8f3239537 100644 --- a/tests/phpunit/tests/query/randomContentRedirect.php +++ b/tests/phpunit/tests/query/randomContentRedirect.php @@ -15,7 +15,6 @@ * @covers ::wp_is_random_content_query * @covers ::wp_get_random_content_post_types * @covers ::wp_random_content_flush_rewrite_rules_for_post - * @covers ::wp_random_content_split_the_query * @covers ::wp_is_random_content_redirect_enabled */ class Tests_Query_RandomContentRedirect extends WP_UnitTestCase { @@ -1489,26 +1488,45 @@ static function ( string $location ) use ( $wp, &$redirected_before_wp ): string * Database queries. */ - public function test_random_post_is_selected_with_a_single_database_query(): void { + /** + * The random order is applied to post IDs only, so the database sorts IDs rather than + * full rows, including post content, of every eligible post. + * + * @global wpdb $wpdb WordPress database abstraction object. + */ + public function test_random_post_is_selected_by_a_single_random_id_query(): void { + global $wpdb; + $this->go_to_and_record_queries( home_url( '/random/' ) ); - $this->assertNotNull( $this->redirect_location, 'The single database query request did not redirect.' ); - $this->assertCount( 1, $this->queries, "Only one database query should be made to select the random post:\n" . implode( "\n", $this->queries ) ); - $this->assertStringContainsString( 'RAND()', $this->queries[0], 'The random query should be the only query made.' ); + $this->assertNotNull( $this->redirect_location, 'The request did not redirect.' ); + + $random_queries = array_values( preg_grep( '/RAND\(\)/', $this->queries ) ); + $this->assertCount( 1, $random_queries, "Exactly one random query should be made:\n" . implode( "\n", $this->queries ) ); + $this->assertMatchesRegularExpression( "/^\s*SELECT\s+{$wpdb->posts}\.ID\s+FROM/", $random_queries[0], 'The random query should select post IDs only.' ); + $this->assertMatchesRegularExpression( '/ORDER BY RAND\(\)/', $random_queries[0], 'The query should use a random order.' ); + $this->assertMatchesRegularExpression( '/LIMIT 0, 1\s*$/', $random_queries[0], 'The query should select a single post.' ); + $this->assertStringNotContainsString( 'SQL_CALC_FOUND_ROWS', $random_queries[0], 'The query should not count found rows.' ); } /** + * At most one more query is made, to load the selected post by its ID. + * * @global wpdb $wpdb WordPress database abstraction object. */ - public function test_random_query_selects_a_single_full_post_row(): void { + public function test_random_post_is_loaded_by_id_after_the_random_query(): void { global $wpdb; + wp_cache_flush(); + $this->go_to_and_record_queries( home_url( '/random/' ) ); - $this->assertMatchesRegularExpression( "/SELECT\s+{$wpdb->posts}\.\*/", $this->queries[0], 'The query should not be split into an ID query and a post query.' ); - $this->assertMatchesRegularExpression( '/ORDER BY RAND\(\)/', $this->queries[0], 'The query should use a random order.' ); - $this->assertMatchesRegularExpression( '/LIMIT 0, 1\s*$/', $this->queries[0], 'The query should select a single post.' ); - $this->assertStringNotContainsString( 'SQL_CALC_FOUND_ROWS', $this->queries[0], 'The query should not count found rows.' ); + $this->assertLessThanOrEqual( 2, count( $this->queries ), "No more than two database queries should be made to select the random post:\n" . implode( "\n", $this->queries ) ); + $this->assertStringContainsString( 'RAND()', $this->queries[0], 'The random query should be made first.' ); + + if ( isset( $this->queries[1] ) ) { + $this->assertMatchesRegularExpression( "/^\s*SELECT\s+{$wpdb->posts}\.\*\s+FROM\s+{$wpdb->posts}\s+WHERE\s+ID\s+IN\s+\(\d+\)/", $this->queries[1], 'The second query should load the selected post by its ID.' ); + } } /** @@ -1526,19 +1544,24 @@ public function test_random_query_does_not_prime_meta_or_term_caches(): void { } } - public function test_random_query_is_not_split_with_persistent_object_cache(): void { + /** + * The random ID query must never be served from the query cache, or the same post + * would be selected until the cache is invalidated. + */ + public function test_random_query_is_not_cached_with_persistent_object_cache(): void { $using_ext_cache = wp_using_ext_object_cache( true ); $this->go_to_and_record_queries( home_url( '/random/' ) ); + $first_request_queries = $this->queries; - wp_using_ext_object_cache( $using_ext_cache ); + $this->queries = array(); + $this->redirect_location = null; + $this->go_to_and_record_queries( home_url( '/random/' ) ); - $this->assertCount( 1, $this->queries, "Only one database query should be made with a persistent object cache:\n" . implode( "\n", $this->queries ) ); - } + wp_using_ext_object_cache( $using_ext_cache ); - public function test_split_the_query_is_unchanged_for_other_queries(): void { - $this->assertTrue( wp_random_content_split_the_query( true, new WP_Query() ), 'Splitting should remain enabled for non-random queries.' ); - $this->assertFalse( wp_random_content_split_the_query( false, new WP_Query() ), 'Splitting should remain disabled for non-random queries.' ); + $this->assertCount( 1, preg_grep( '/RAND\(\)/', $first_request_queries ), 'The first request should run the random query.' ); + $this->assertCount( 1, preg_grep( '/RAND\(\)/', $this->queries ), "The second request should run the random query again rather than reuse a cached result:\n" . implode( "\n", $this->queries ) ); } public function test_random_selection_varies_between_requests(): void { From 96bd9a3876ee8078a0b542b62c108e98d49d9589 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 08:45:18 +1100 Subject: [PATCH 2/9] Remove extra line break. --- tests/phpunit/tests/query/randomContentRedirect.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/phpunit/tests/query/randomContentRedirect.php b/tests/phpunit/tests/query/randomContentRedirect.php index 36144869b8fdd..65cc8ff86b7b8 100644 --- a/tests/phpunit/tests/query/randomContentRedirect.php +++ b/tests/phpunit/tests/query/randomContentRedirect.php @@ -245,7 +245,6 @@ protected function create_post( array $args = array() ): int { * * @param int[] $post_ids Allowed post IDs. * @param string $message Message to display on failure. - * * @phpstan-assert !null $this->redirect_location */ From c812430fda820caf5184245847e6fc4370d460a8 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 09:49:03 +1100 Subject: [PATCH 3/9] Docblock all methods. --- .../tests/query/randomContentRedirect.php | 308 ++++++++++++++++++ 1 file changed, 308 insertions(+) diff --git a/tests/phpunit/tests/query/randomContentRedirect.php b/tests/phpunit/tests/query/randomContentRedirect.php index 65cc8ff86b7b8..8248908453426 100644 --- a/tests/phpunit/tests/query/randomContentRedirect.php +++ b/tests/phpunit/tests/query/randomContentRedirect.php @@ -96,6 +96,11 @@ class Tests_Query_RandomContentRedirect extends WP_UnitTestCase { */ protected $recording_queries = false; + /** + * Creates shared user, category and post fixtures. + * + * @param WP_UnitTest_Factory $factory Test factory. + */ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ): void { self::$editor = $factory->user->create( array( @@ -131,6 +136,9 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ): void ); } + /** + * Sets up pretty permalinks and redirect capturing before each test. + */ public function set_up(): void { parent::set_up(); @@ -148,6 +156,9 @@ public function set_up(): void { add_filter( 'wp_redirect', array( $this, 'filter_wp_redirect' ), 10, 2 ); } + /** + * Unregisters the test post types and taxonomy after each test. + */ public function tear_down(): void { unregister_post_type( 'wptests_book' ); unregister_post_type( 'wptests_hidden' ); @@ -280,6 +291,8 @@ protected function assertQueryIsNotRandomized( WP_Query $query, string $message */ /** + * Ensure random content URLs redirect to a published post. + * * @dataProvider data_random_urls * * @param string $path Random content request path. @@ -305,18 +318,27 @@ public function data_random_urls(): array { ); } + /** + * Ensure redirect uses HTTP 302 Temporary Redirect status. + */ public function test_random_redirect_uses_a_temporary_redirect(): void { $this->go_to( home_url( '/random/' ) ); $this->assertSame( 302, $this->redirect_status, 'Random redirects must not be permanent.' ); } + /** + * Ensure redirect location header matches the permalink of the selected post. + */ public function test_random_redirect_location_is_the_permalink(): void { $this->go_to( home_url( '/random/category/arts/' ) ); $this->assertSame( get_permalink( self::$arts_post ), $this->redirect_location, 'The redirect location should be the permalink of the selected post.' ); } + /** + * Ensure random redirects work with plain permalinks. + */ public function test_random_query_string_redirects_with_plain_permalinks(): void { $this->set_permalink_structure( '' ); @@ -326,6 +348,9 @@ public function test_random_query_string_redirects_with_plain_permalinks(): void $this->assertStringContainsString( '?p=', $this->redirect_location, 'The redirect should use the plain permalink.' ); } + /** + * Ensure random redirects work with pathinfo (/index.php/...) permalinks. + */ public function test_random_redirect_with_pathinfo_permalinks(): void { $this->set_permalink_structure( '/index.php/%postname%/' ); @@ -334,12 +359,18 @@ public function test_random_redirect_with_pathinfo_permalinks(): void { $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'The random URL should redirect with PATHINFO permalinks.' ); } + /** + * Ensure random redirects respect the selected category. + */ public function test_random_category_url_only_selects_posts_in_the_category(): void { $this->go_to( home_url( '/random/category/sport/' ) ); $this->assertSame( get_permalink( self::$sport_post ), $this->redirect_location, 'The random category URL should only select posts in the category.' ); } + /** + * Ensure random redirects respect the selected nested category. + */ public function test_random_child_category_url_selects_posts_in_the_child_category(): void { $child = self::factory()->category->create( array( @@ -354,6 +385,9 @@ public function test_random_child_category_url_selects_posts_in_the_child_catego $this->assertSame( get_permalink( $post_id ), $this->redirect_location, 'The random child category URL should select posts in the child category.' ); } + /** + * Ensure random redirects include posts in the selected category's sub-categories. + */ public function test_random_category_url_includes_posts_in_child_categories(): void { $child = self::factory()->category->create( array( @@ -368,18 +402,27 @@ public function test_random_category_url_includes_posts_in_child_categories(): v $this->assertRedirectedToOneOf( array( self::$sport_post, $child_post ), 'Category archives include child categories.' ); } + /** + * Ensure random redirects respect the `?cat` URL parameter. + */ public function test_random_cat_query_string_only_selects_posts_in_the_category(): void { $this->go_to( add_query_arg( 'cat', self::$arts_category, home_url( '/?random' ) ) ); $this->assertSame( get_permalink( self::$arts_post ), $this->redirect_location, 'The random cat query string should only select posts in the category.' ); } + /** + * Ensure random redirects respect the selected tag. + */ public function test_random_tag_url_only_selects_posts_with_the_tag(): void { $this->go_to( home_url( '/random/tag/impressionism/' ) ); $this->assertSame( get_permalink( self::$arts_post ), $this->redirect_location, 'The random tag URL should only select posts with the tag.' ); } + /** + * Ensure random redirects respect URLs specifying terms from multiple taxonomies. + */ public function test_random_combined_taxonomy_query_selects_posts_matching_all_terms(): void { $impressionist_sport = $this->create_post( array( @@ -394,24 +437,36 @@ public function test_random_combined_taxonomy_query_selects_posts_matching_all_t $this->assertSame( get_permalink( $impressionist_sport ), $this->redirect_location, 'The combined taxonomy query should only select posts matching all terms.' ); } + /** + * Ensure random redirects respect the selected author. + */ public function test_random_author_url_only_selects_posts_by_the_author(): void { $this->go_to( home_url( '/random/author/random-editor/' ) ); $this->assertSame( get_permalink( self::$sport_post ), $this->redirect_location, 'The random author URL should only select posts by the author.' ); } + /** + * Ensure random redirects respect the selected date. + */ public function test_random_date_archive_only_selects_posts_from_the_date(): void { $this->go_to( home_url( '/1844/?random' ) ); $this->assertSame( get_permalink( self::$arts_post ), $this->redirect_location, 'The random date archive should only select posts from the date.' ); } + /** + * Ensure random redirects respect the selected search query. + */ public function test_random_search_only_selects_matching_posts(): void { $this->go_to( home_url( '/?s=Baseball&random' ) ); $this->assertSame( get_permalink( self::$sport_post ), $this->redirect_location, 'The random search should only select matching posts.' ); } + /** + * Ensure random redirects respect the selected post type. + */ public function test_random_post_type_archive_url_only_selects_posts_of_the_type(): void { register_post_type( 'wptests_book', @@ -429,6 +484,9 @@ public function test_random_post_type_archive_url_only_selects_posts_of_the_type $this->assertSame( get_permalink( $book ), $this->redirect_location, 'The random post type archive URL should only select posts of the type.' ); } + /** + * Ensure random redirects respect the randomable post type parameter regardless of archive setting. + */ public function test_random_post_type_rewrite_slug_url_selects_posts_of_a_randomable_type_without_an_archive(): void { register_post_type( 'wptests_book', @@ -448,6 +506,9 @@ public function test_random_post_type_rewrite_slug_url_selects_posts_of_a_random $this->assertSame( get_permalink( $book ), $this->redirect_location, 'The random rewrite slug URL should select posts of a randomable type without an archive.' ); } + /** + * Ensure random redirects respect the selected post type using plain permalinks. + */ public function test_random_post_type_query_string_selects_posts_of_the_type(): void { register_post_type( 'wptests_book', @@ -468,6 +529,9 @@ public function test_random_post_type_query_string_selects_posts_of_the_type(): * Randomable post types. */ + /** + * Ensure pages are not randomable. + */ public function test_no_redirect_for_pages(): void { $this->create_post( array( 'post_type' => 'page' ) ); @@ -476,6 +540,9 @@ public function test_no_redirect_for_pages(): void { $this->assertNotRedirected( 'Pages should not be randomable by default.' ); } + /** + * Ensure main query for pages is not modified by random query string parameter. + */ public function test_main_query_is_unchanged_for_pages(): void { $this->create_post( array( 'post_type' => 'page' ) ); @@ -484,6 +551,9 @@ public function test_main_query_is_unchanged_for_pages(): void { $this->assertQueryIsNotRandomized( $this->get_main_query(), 'Requests for non-randomable post types should not be randomized.' ); } + /** + * Ensure pages are randomable if registration arguments enable the feature. + */ public function test_pages_redirect_when_made_randomable(): void { add_filter( 'register_post_type_args', array( $this, 'filter_make_pages_randomable' ), 10, 2 ); create_initial_post_types(); @@ -510,6 +580,9 @@ public function filter_make_pages_randomable( array $args, string $post_type ): return $args; } + /** + * Ensure post types registered as not randomable do not redirect. + */ public function test_no_redirect_for_post_type_that_is_not_randomable(): void { register_post_type( 'wptests_book', @@ -526,6 +599,9 @@ public function test_no_redirect_for_post_type_that_is_not_randomable(): void { $this->assertNotRedirected( 'Post types registered as not randomable should not redirect.' ); } + /** + * Ensure archives of post types registered as not randomable do not redirect. + */ public function test_no_redirect_for_post_type_archive_that_is_not_randomable(): void { register_post_type( 'wptests_book', @@ -545,6 +621,9 @@ public function test_no_redirect_for_post_type_archive_that_is_not_randomable(): $this->assertTrue( is_post_type_archive( 'wptests_book' ), 'The archive should be displayed.' ); } + /** + * Ensure only randomable post types are selected when multiple post types are requested. + */ public function test_random_redirect_with_multiple_post_types_only_selects_randomable_types(): void { register_post_type( 'wptests_book', @@ -562,6 +641,9 @@ public function test_random_redirect_with_multiple_post_types_only_selects_rando $this->assertSame( get_permalink( $book ), $this->redirect_location, 'Only randomable post types should be selected from multiple post types.' ); } + /** + * Ensure random searches do not select pages. + */ public function test_random_search_only_selects_randomable_post_types(): void { $this->create_post( array( @@ -575,6 +657,9 @@ public function test_random_search_only_selects_randomable_post_types(): void { $this->assertSame( get_permalink( self::$sport_post ), $this->redirect_location, 'Pages should not be selected from search results.' ); } + /** + * Ensure random searches include randomable custom post types. + */ public function test_random_search_includes_randomable_custom_post_types(): void { register_post_type( 'wptests_book', @@ -596,6 +681,9 @@ public function test_random_search_includes_randomable_custom_post_types(): void $this->assertSame( get_permalink( $book ), $this->redirect_location, 'Randomable custom post types should be selected from search results.' ); } + /** + * Ensure random custom taxonomy archives only select randomable post types. + */ public function test_random_custom_taxonomy_archive_only_selects_randomable_post_types(): void { register_post_type( 'wptests_book', @@ -624,6 +712,9 @@ public function test_random_custom_taxonomy_archive_only_selects_randomable_post $this->assertSame( get_permalink( $book ), $this->redirect_location, 'Only randomable post types should be selected from a custom taxonomy archive.' ); } + /** + * Ensure archives of taxonomies used only by pages do not redirect. + */ public function test_no_redirect_for_taxonomy_used_only_by_pages(): void { register_taxonomy( 'wptests_genre', @@ -645,6 +736,8 @@ public function test_no_redirect_for_taxonomy_used_only_by_pages(): void { } /** + * Ensure the eligible post types match the request. + * * @dataProvider data_wp_get_random_content_post_types * * @param string $url URL to request. @@ -698,6 +791,9 @@ public function data_wp_get_random_content_post_types(): array { ); } + /** + * Ensure the random URL only selects posts by default. + */ public function test_random_url_defaults_to_posts(): void { $this->create_post( array( 'post_type' => 'page' ) ); @@ -706,6 +802,9 @@ public function test_random_url_defaults_to_posts(): void { $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'Pages should not be selected without requesting them.' ); } + /** + * Ensure the random URL redirects to a post when a static front page is set. + */ public function test_random_url_with_static_front_page_redirects_to_a_post(): void { $front = $this->create_post( array( 'post_type' => 'page' ) ); update_option( 'show_on_front', 'page' ); @@ -716,6 +815,9 @@ public function test_random_url_with_static_front_page_redirects_to_a_post(): vo $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'The random URL should redirect to a post when a static front page is set.' ); } + /** + * Ensure pagination does not affect the random selection. + */ public function test_random_redirect_ignores_pagination(): void { $this->go_to( home_url( '/random/category/arts/?paged=5' ) ); @@ -727,6 +829,8 @@ public function test_random_redirect_ignores_pagination(): void { */ /** + * Ensure unpublished and password protected posts are not selected, even for administrators. + * * @dataProvider data_ineligible_posts * * @param array $args Post arguments. @@ -764,6 +868,8 @@ public function data_ineligible_posts(): array { } /** + * Ensure sticky posts are not prepended to the random selection. + * * @global wpdb $wpdb WordPress database abstraction object. */ public function test_random_redirect_ignores_sticky_posts(): void { @@ -803,6 +909,9 @@ static function ( array $clauses, WP_Query $query ) use ( $sticky_orderby ): arr * Requests that are not random content requests. */ + /** + * Ensure the home page does not redirect without the random query variable. + */ public function test_no_redirect_without_random_query_var(): void { $this->go_to( home_url( '/' ) ); @@ -810,6 +919,9 @@ public function test_no_redirect_without_random_query_var(): void { $this->assertQueryTrue( 'is_home', 'is_front_page' ); } + /** + * Ensure archives are not randomized without the random query variable. + */ public function test_archives_are_unchanged_without_random_query_var(): void { $this->go_to( home_url( '/category/arts/' ) ); @@ -817,6 +929,9 @@ public function test_archives_are_unchanged_without_random_query_var(): void { $this->assertQueryIsNotRandomized( $this->get_main_query(), 'The archive order should not be modified.' ); } + /** + * Ensure singular posts do not redirect with the random query variable. + */ public function test_no_redirect_for_singular_post_with_random_query_var(): void { $this->go_to( add_query_arg( 'random', '', get_permalink( self::$arts_post ) ) ); @@ -825,6 +940,9 @@ public function test_no_redirect_for_singular_post_with_random_query_var(): void $this->assertSame( self::$arts_post, get_queried_object_id(), 'The singular post should be queried despite the random query variable.' ); } + /** + * Ensure requests for a post ID do not redirect with the random query variable. + */ public function test_no_redirect_for_post_id_with_random_query_var(): void { $this->go_to( home_url( '/?random&p=' . self::$sport_post ) ); @@ -832,6 +950,9 @@ public function test_no_redirect_for_post_id_with_random_query_var(): void { $this->assertSame( self::$sport_post, get_queried_object_id(), 'The post ID should be queried despite the random query variable.' ); } + /** + * Ensure pages do not redirect with the random query variable. + */ public function test_no_redirect_for_page_with_random_query_var(): void { $page = $this->create_post( array( @@ -846,6 +967,9 @@ public function test_no_redirect_for_page_with_random_query_var(): void { $this->assertSame( $page, get_queried_object_id(), 'The page should be queried despite the random query variable.' ); } + /** + * Ensure the static front page does not redirect with the random query variable. + */ public function test_no_redirect_for_static_front_page_with_random_query_var_from_extra_vars(): void { $front = $this->create_post( array( 'post_type' => 'page' ) ); update_option( 'show_on_front', 'page' ); @@ -858,6 +982,8 @@ public function test_no_redirect_for_static_front_page_with_random_query_var_fro } /** + * Ensure feeds do not redirect with the random query variable. + * * @dataProvider data_feed_urls * * @param string $path Feed path. @@ -882,6 +1008,9 @@ public function data_feed_urls(): array { ); } + /** + * Ensure embeds do not redirect with the random query variable. + */ public function test_no_redirect_for_embeds(): void { $this->go_to( home_url( '/cassatt/embed/?random' ) ); @@ -889,6 +1018,9 @@ public function test_no_redirect_for_embeds(): void { $this->assertTrue( is_embed(), 'The embed should be displayed despite the random query variable.' ); } + /** + * Ensure random requests for a nonexistent category return a 404 rather than redirecting. + */ public function test_no_redirect_for_nonexistent_category(): void { $this->go_to( home_url( '/random/category/does-not-exist/' ) ); @@ -896,6 +1028,9 @@ public function test_no_redirect_for_nonexistent_category(): void { $this->assertTrue( is_404(), 'A random request for a nonexistent term should 404.' ); } + /** + * Ensure random requests for an empty category return a 404 rather than redirecting. + */ public function test_no_redirect_for_empty_category(): void { $this->go_to( home_url( '/random/category/empty/' ) ); @@ -903,6 +1038,9 @@ public function test_no_redirect_for_empty_category(): void { $this->assertQueryTrue( 'is_404' ); } + /** + * Ensure random requests without eligible posts return a 404 rather than redirecting. + */ public function test_no_redirect_when_no_posts_are_eligible(): void { add_filter( 'posts_where', @@ -920,6 +1058,8 @@ static function ( string $where, WP_Query $query ): string { } /** + * Ensure requests using HTTP methods other than GET or HEAD do not redirect. + * * @dataProvider data_non_redirecting_http_methods * * @param string $method HTTP request method. @@ -946,6 +1086,9 @@ public function data_non_redirecting_http_methods(): array { ); } + /** + * Ensure requests without an HTTP method do not redirect. + */ public function test_no_redirect_without_request_method(): void { unset( $_SERVER['REQUEST_METHOD'] ); @@ -955,6 +1098,8 @@ public function test_no_redirect_without_request_method(): void { } /** + * Ensure GET and HEAD requests redirect, regardless of case. + * * @dataProvider data_redirecting_http_methods * * @param string $method HTTP request method. @@ -1020,6 +1165,8 @@ public function test_page_with_slug_beginning_with_random_base_does_not_conflict } /** + * Ensure the random URL redirects when a page slug begins with the random base. + * * @dataProvider data_permalink_structures * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. @@ -1090,6 +1237,9 @@ public function data_permalink_structures(): array { ); } + /** + * Ensure random archives redirect when a page named "random" exists. + */ public function test_random_archives_redirect_when_a_page_named_random_exists(): void { $this->create_post( array( @@ -1103,6 +1253,9 @@ public function test_random_archives_redirect_when_a_page_named_random_exists(): $this->assertSame( get_permalink( self::$arts_post ), $this->redirect_location, 'Random archives should redirect when a page named random exists.' ); } + /** + * Ensure the random query string redirects when a page named "random" exists. + */ public function test_random_query_string_redirects_when_a_page_named_random_exists(): void { $this->create_post( array( @@ -1116,6 +1269,9 @@ public function test_random_query_string_redirects_when_a_page_named_random_exis $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'The random query string should redirect when a page named random exists.' ); } + /** + * Ensure a draft page named "random" does not take precedence over random content redirects. + */ public function test_draft_page_named_random_does_not_take_precedence(): void { $this->create_post( array( @@ -1131,6 +1287,8 @@ public function test_draft_page_named_random_does_not_take_precedence(): void { } /** + * Ensure random content redirects resume once a page named "random" no longer conflicts. + * * @dataProvider data_page_named_random_changes * * @param callable $change Callback to change the page so it no longer conflicts. @@ -1202,6 +1360,9 @@ static function ( int $page_id ): void { ); } + /** + * Ensure publishing a draft page named "random" takes precedence over random content redirects. + */ public function test_publishing_a_draft_page_named_random_takes_precedence(): void { $page = $this->create_post( array( @@ -1219,6 +1380,9 @@ public function test_publishing_a_draft_page_named_random_takes_precedence(): vo $this->assertSame( $page, get_queried_object_id(), 'A newly published page named random should be queried.' ); } + /** + * Ensure saving pages and posts not at the random base does not flush the rewrite rules. + */ public function test_saving_unrelated_pages_does_not_flush_rewrite_rules(): void { $flushes = new MockAction(); add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); @@ -1245,6 +1409,9 @@ public function test_saving_unrelated_pages_does_not_flush_rewrite_rules(): void * Opting out. */ + /** + * Ensure random content requests do not redirect when the feature is disabled. + */ public function test_no_redirect_when_disabled(): void { add_filter( 'wp_enable_random_content_redirect', '__return_false' ); @@ -1254,6 +1421,9 @@ public function test_no_redirect_when_disabled(): void { $this->assertQueryTrue( 'is_home', 'is_front_page' ); } + /** + * Ensure the main query is not randomized or limited when the feature is disabled. + */ public function test_main_query_is_unchanged_when_disabled(): void { add_filter( 'wp_enable_random_content_redirect', '__return_false' ); @@ -1263,6 +1433,9 @@ public function test_main_query_is_unchanged_when_disabled(): void { $this->assertSame( 2, $this->get_main_query()->post_count, 'The main query should not be limited when disabled.' ); } + /** + * Ensure the random URL is not routed when the feature is disabled. + */ public function test_random_url_is_not_routed_when_disabled(): void { add_filter( 'wp_enable_random_content_redirect', '__return_false' ); flush_rewrite_rules(); @@ -1277,6 +1450,9 @@ public function test_random_url_is_not_routed_when_disabled(): void { * Extensibility. */ + /** + * Ensure the `pre_get_posts` action can change the eligible post type. + */ public function test_pre_get_posts_can_change_the_eligible_post_type(): void { register_post_type( 'wptests_book', @@ -1301,6 +1477,9 @@ static function ( WP_Query $query ): void { $this->assertSame( get_permalink( $book ), $this->redirect_location, 'The pre_get_posts action should be able to change the eligible post type.' ); } + /** + * Ensure the `pre_get_posts` action cannot add non-randomable post types. + */ public function test_pre_get_posts_cannot_add_non_randomable_post_types(): void { $this->create_post( array( 'post_type' => 'page' ) ); @@ -1318,6 +1497,9 @@ static function ( WP_Query $query ): void { $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'The pre_get_posts action should not be able to add non-randomable post types.' ); } + /** + * Ensure the `pre_get_posts` action can exclude posts from the random selection. + */ public function test_pre_get_posts_can_exclude_posts(): void { add_action( 'pre_get_posts', @@ -1333,6 +1515,9 @@ static function ( WP_Query $query ): void { $this->assertSame( get_permalink( self::$sport_post ), $this->redirect_location, 'The pre_get_posts action should be able to exclude posts.' ); } + /** + * Ensure theme customizations of the archive order and limit do not override the random query. + */ public function test_pre_get_posts_archive_customizations_do_not_override_the_random_order(): void { // Typical theme customization of the main query for archives. add_action( @@ -1354,6 +1539,9 @@ static function ( WP_Query $query ): void { $this->assertStringContainsString( 'LIMIT 0, 1', $request, 'Only one post should be selected when archive customizations set the number of posts.' ); } + /** + * Ensure secondary queries are not random content queries. + */ public function test_secondary_queries_are_not_random_content_queries(): void { $this->go_to( home_url( '/random/' ) ); @@ -1363,6 +1551,9 @@ public function test_secondary_queries_are_not_random_content_queries(): void { $this->assertQueryIsNotRandomized( $query, 'Secondary queries should not be randomized.' ); } + /** + * Ensure the main query for the random URL is a random content query. + */ public function test_wp_is_random_content_query_for_main_query(): void { $this->go_to( home_url( '/random/' ) ); @@ -1370,6 +1561,8 @@ public function test_wp_is_random_content_query_for_main_query(): void { } /** + * Ensure the `is_random()` conditional tag matches the request. + * * @dataProvider data_is_random * * @covers ::is_random @@ -1407,6 +1600,8 @@ public function data_is_random(): array { } /** + * Ensure secondary queries with the random query variable are for random content. + * * @covers WP_Query::is_random */ public function test_secondary_query_is_random_with_the_random_query_var(): void { @@ -1417,6 +1612,8 @@ public function test_secondary_query_is_random_with_the_random_query_var(): void } /** + * Ensure the query is not for random content once it is set to a 404. + * * @covers WP_Query::is_random */ public function test_is_random_is_reset_when_the_query_is_a_404(): void { @@ -1428,6 +1625,8 @@ public function test_is_random_is_reset_when_the_query_is_a_404(): void { } /** + * Ensure the `is_random()` conditional tag returns false before the query is run. + * * @covers ::is_random * * @expectedIncorrectUsage is_random @@ -1438,6 +1637,9 @@ public function test_is_random_before_the_query_is_run(): void { $this->assertFalse( is_random(), 'The is_random() conditional tag should return false before the query is run.' ); } + /** + * Ensure the main query is not randomized in the admin. + */ public function test_main_query_is_not_randomized_in_the_admin(): void { set_current_screen( 'edit.php' ); @@ -1452,6 +1654,9 @@ public function test_main_query_is_not_randomized_in_the_admin(): void { $this->assertQueryIsNotRandomized( $this->get_main_query(), 'Admin queries should not be randomized.' ); } + /** + * Ensure the request redirects when the `the_posts` filter returns a non-list array. + */ public function test_redirect_when_the_posts_filter_returns_a_non_list_array(): void { add_filter( 'the_posts', @@ -1465,6 +1670,9 @@ static function ( array $posts ): array { $this->assertSame( get_permalink( self::$arts_post ), $this->redirect_location, 'A non-list array returned by the posts filter should still redirect.' ); } + /** + * Ensure the request does not redirect when the permalink is empty. + */ public function test_no_redirect_when_the_permalink_is_empty(): void { add_filter( 'post_link', '__return_empty_string' ); @@ -1473,6 +1681,9 @@ public function test_no_redirect_when_the_permalink_is_empty(): void { $this->assertNotRedirected( 'An empty permalink should not redirect.' ); } + /** + * Ensure the redirect happens before the `wp` action fires. + */ public function test_redirect_happens_before_the_wp_action(): void { $wp = new MockAction(); add_action( 'wp', array( $wp, 'action' ) ); @@ -1538,6 +1749,8 @@ public function test_random_post_is_loaded_by_id_after_the_random_query(): void } /** + * Ensure the random query does not prime the post meta or term caches. + * * @global wpdb $wpdb WordPress database abstraction object. */ public function test_random_query_does_not_prime_meta_or_term_caches(): void { @@ -1572,6 +1785,9 @@ public function test_random_query_is_not_cached_with_persistent_object_cache(): $this->assertCount( 1, preg_grep( '/RAND\(\)/', $this->queries ), "The second request should run the random query again rather than reuse a cached result:\n" . implode( "\n", $this->queries ) ); } + /** + * Ensure different posts are selected across random requests. + */ public function test_random_selection_varies_between_requests(): void { for ( $i = 0; $i < 8; $i++ ) { $this->create_post(); @@ -1593,6 +1809,8 @@ public function test_random_selection_varies_between_requests(): void { */ /** + * Ensure the random query selects a single post when a theme overrides the limit. + * * @dataProvider data_query_vars_overriding_the_limit * * @param string $path Request path. @@ -1645,6 +1863,9 @@ public function data_query_vars_overriding_the_limit(): array { return $data; } + /** + * Ensure an offset set by a theme does not prevent the redirect. + */ public function test_random_redirect_ignores_an_offset_set_by_a_theme(): void { add_action( 'pre_get_posts', @@ -1664,6 +1885,9 @@ static function ( WP_Query $query ): void { * Redirect locations. */ + /** + * Ensure the request does not redirect to a permalink on another site. + */ public function test_no_redirect_when_the_permalink_is_on_another_site(): void { add_filter( 'post_link', @@ -1677,6 +1901,9 @@ static function (): string { $this->assertNotRedirected( 'Off-site permalinks must not fall back to a redirect to the dashboard.' ); } + /** + * Ensure the request redirects to a permalink on an allowed redirect host. + */ public function test_redirect_to_a_permalink_on_an_allowed_host(): void { add_filter( 'allowed_redirect_hosts', @@ -1697,6 +1924,9 @@ static function (): string { $this->assertSame( 'https://cdn.example.org/post/', $this->redirect_location, 'Permalinks on an allowed host should be redirected to.' ); } + /** + * Ensure the request does not redirect to a global post when the main query has no post. + */ public function test_no_redirect_when_the_main_query_has_no_post(): void { add_filter( 'the_posts', '__return_empty_array' ); $this->go_to( home_url( '/random/' ) ); @@ -1717,6 +1947,9 @@ public function test_no_redirect_when_the_main_query_has_no_post(): void { * Randomable post types: edge cases. */ + /** + * Ensure random searches do not select randomable post types excluded from search. + */ public function test_random_search_excludes_randomable_post_types_excluded_from_search(): void { register_post_type( 'wptests_unsearchable', @@ -1738,6 +1971,9 @@ public function test_random_search_excludes_randomable_post_types_excluded_from_ $this->assertSame( get_permalink( self::$sport_post ), $this->redirect_location, 'Random search results should match the search results.' ); } + /** + * Ensure randomable post types excluded from search can be requested directly. + */ public function test_randomable_post_type_excluded_from_search_can_be_requested_directly(): void { register_post_type( 'wptests_unsearchable', @@ -1754,6 +1990,9 @@ public function test_randomable_post_type_excluded_from_search_can_be_requested_ $this->assertSame( get_permalink( $post_id ), $this->redirect_location, 'Randomable post types excluded from search should be selectable directly.' ); } + /** + * Ensure randomable attachments are eligible for taxonomies registered for attachment MIME types. + */ public function test_random_post_types_include_attachments_for_attachment_mime_type_taxonomies(): void { $filter = static function ( array $args, string $post_type ): array { if ( 'attachment' === $post_type ) { @@ -1780,6 +2019,9 @@ public function test_random_post_types_include_attachments_for_attachment_mime_t $this->assertSame( array( 'attachment' ), $post_types, 'Attachments should be eligible for attachment MIME type taxonomies.' ); } + /** + * Ensure non-string post types set by plugins are ignored. + */ public function test_non_string_post_types_set_by_plugins_are_ignored(): void { add_action( 'pre_get_posts', @@ -1800,6 +2042,8 @@ static function ( WP_Query $query ): void { */ /** + * Ensure the enabled filter value is cast to a boolean. + * * @dataProvider data_enabled_filter_values * * @param mixed $value Value returned by the filter. @@ -1832,6 +2076,9 @@ public function data_enabled_filter_values(): array { ); } + /** + * Ensure stale rewrite rules do not redirect or randomize the query when the feature is disabled. + */ public function test_no_redirect_when_disabled_without_flushing_the_rewrite_rules(): void { add_filter( 'wp_enable_random_content_redirect', '__return_false' ); @@ -1845,6 +2092,9 @@ public function test_no_redirect_when_disabled_without_flushing_the_rewrite_rule * Conflicts with pages: lifecycle guards. */ + /** + * Ensure creating a page named "random" flushes the rewrite rules once. + */ public function test_creating_a_page_named_random_flushes_the_rewrite_rules(): void { $flushes = new MockAction(); add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); @@ -1859,6 +2109,9 @@ public function test_creating_a_page_named_random_flushes_the_rewrite_rules(): v $this->assertSame( 1, $flushes->get_call_count(), 'Creating a page named random should flush the rewrite rules once.' ); } + /** + * Ensure a page named "random" does not flush the rewrite rules with plain permalinks. + */ public function test_page_named_random_does_not_flush_rewrite_rules_with_plain_permalinks(): void { $this->set_permalink_structure( '' ); $flushes = new MockAction(); @@ -1874,6 +2127,9 @@ public function test_page_named_random_does_not_flush_rewrite_rules_with_plain_p $this->assertSame( 0, $flushes->get_call_count(), 'Plain permalinks have no rewrite rules to update.' ); } + /** + * Ensure a page named "random" does not flush the rewrite rules when the feature is disabled. + */ public function test_page_named_random_does_not_flush_rewrite_rules_when_disabled(): void { add_filter( 'wp_enable_random_content_redirect', '__return_false' ); $flushes = new MockAction(); @@ -1890,6 +2146,8 @@ public function test_page_named_random_does_not_flush_rewrite_rules_when_disable } /** + * Ensure a page at a custom random base takes precedence over random content redirects. + * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. */ public function test_page_at_custom_random_base_takes_precedence(): void { @@ -1912,6 +2170,8 @@ public function test_page_at_custom_random_base_takes_precedence(): void { } /** + * Ensure a page named "random" does not conflict with a custom random base. + * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. */ public function test_page_named_random_does_not_conflict_with_a_custom_random_base(): void { @@ -1935,6 +2195,9 @@ public function test_page_named_random_does_not_conflict_with_a_custom_random_ba $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'A page named random should not conflict with a custom random base.' ); } + /** + * Ensure a private page named "random" does not take precedence over random content redirects. + */ public function test_private_page_named_random_does_not_take_precedence(): void { $this->create_post( array( @@ -1949,6 +2212,9 @@ public function test_private_page_named_random_does_not_take_precedence(): void $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'Pages visitors cannot view should not replace random redirects.' ); } + /** + * Ensure a password protected page named "random" takes precedence over random content redirects. + */ public function test_password_protected_page_named_random_takes_precedence(): void { $page = $this->create_post( array( @@ -1969,6 +2235,8 @@ public function test_password_protected_page_named_random_takes_precedence(): vo */ /** + * Ensure paths beneath the random base without random rules do not redirect. + * * @dataProvider data_unsupported_random_paths * * @global WP $wp Current WordPress environment instance. @@ -1996,6 +2264,9 @@ public function data_unsupported_random_paths(): array { ); } + /** + * Ensure random content requests without a post send a 404 status. + */ public function test_random_requests_without_a_post_send_a_404_status(): void { $status = new MockAction(); add_filter( 'status_header', array( $status, 'filter' ), 10, 2 ); @@ -2013,6 +2284,9 @@ public function test_random_requests_without_a_post_send_a_404_status(): void { * WP::handle_random(). */ + /** + * Ensure `WP::handle_random()` ignores requests without the random query variable. + */ public function test_handle_random_ignores_requests_without_the_random_query_var(): void { $wp = new WP(); $wp->query_vars = array( 'category_name' => 'arts' ); @@ -2020,6 +2294,9 @@ public function test_handle_random_ignores_requests_without_the_random_query_var $this->assertFalse( $wp->handle_random(), 'Requests without the random query variable should not be handled.' ); } + /** + * Ensure `WP::handle_random()` ignores random content requests when the feature is disabled. + */ public function test_handle_random_ignores_random_requests_when_disabled(): void { add_filter( 'wp_enable_random_content_redirect', '__return_false' ); @@ -2029,6 +2306,9 @@ public function test_handle_random_ignores_random_requests_when_disabled(): void $this->assertFalse( $wp->handle_random(), 'Random content requests should not be handled when the feature is disabled.' ); } + /** + * Ensure `WP::handle_random()` runs the main query for random content requests. + */ public function test_handle_random_runs_the_main_query_for_random_requests(): void { $wp = new WP(); $wp->query_vars = array( 'random' => '' ); @@ -2040,6 +2320,8 @@ public function test_handle_random_runs_the_main_query_for_random_requests(): vo } /** + * Ensure the main query is only run once for random content requests. + * * @dataProvider data_random_requests * * @param string $path Path to request. @@ -2065,6 +2347,9 @@ public function data_random_requests(): array { ); } + /** + * Ensure the random content query callbacks are removed after the main query. + */ public function test_random_content_callbacks_are_removed_after_the_main_query(): void { $this->go_to( home_url( '/random/' ) ); @@ -2073,6 +2358,9 @@ public function test_random_content_callbacks_are_removed_after_the_main_query() $this->assertFalse( has_filter( 'post_limits', 'wp_random_content_post_limits' ), 'The post_limits callback should be removed after the main query.' ); } + /** + * Ensure the `posts_orderby` and `post_limits` filters do not override the random order or limit. + */ public function test_sql_customizations_do_not_override_the_random_order_or_limit(): void { add_filter( 'posts_orderby', @@ -2095,6 +2383,9 @@ static function (): string { $this->assertStringContainsString( 'LIMIT 0, 1', $request, 'The post_limits filter should not override the random limit.' ); } + /** + * Ensure suppressing filters does not bypass the random order or limit. + */ public function test_suppressed_filters_do_not_bypass_the_random_order_or_limit(): void { add_action( 'pre_get_posts', @@ -2118,6 +2409,8 @@ static function ( WP_Query $query ): void { */ /** + * Ensure a post named "random" takes precedence over random content redirects. + * * @dataProvider data_post_name_at_the_root_structures * * @global WP_Rewrite $wp_rewrite WordPress rewrite component. @@ -2153,6 +2446,9 @@ public function data_post_name_at_the_root_structures(): array { ); } + /** + * Ensure random archives redirect when a post named "random" exists. + */ public function test_random_archives_redirect_when_a_post_named_random_exists(): void { $this->create_post( array( 'post_name' => 'random' ) ); @@ -2161,6 +2457,9 @@ public function test_random_archives_redirect_when_a_post_named_random_exists(): $this->assertSame( get_permalink( self::$sport_post ), $this->redirect_location, 'Random archives should redirect when a post named random exists.' ); } + /** + * Ensure a post named "random" does not conflict when posts have a blog prefix. + */ public function test_post_named_random_does_not_conflict_with_a_blog_prefix(): void { $this->set_permalink_structure( '/blog/%postname%/' ); create_initial_taxonomies(); @@ -2173,6 +2472,9 @@ public function test_post_named_random_does_not_conflict_with_a_blog_prefix(): v $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post, $post ), 'Random content requests should redirect when posts have a blog prefix.' ); } + /** + * Ensure creating a post named "random" flushes the rewrite rules once. + */ public function test_creating_a_post_named_random_flushes_the_rewrite_rules(): void { $flushes = new MockAction(); add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); @@ -2182,6 +2484,9 @@ public function test_creating_a_post_named_random_flushes_the_rewrite_rules(): v $this->assertSame( 1, $flushes->get_call_count(), 'Creating a post named random should flush the rewrite rules once.' ); } + /** + * Ensure a post named "random" does not flush the rewrite rules when posts have a blog prefix. + */ public function test_post_named_random_does_not_flush_rewrite_rules_with_a_blog_prefix(): void { $this->set_permalink_structure( '/blog/%postname%/' ); $flushes = new MockAction(); @@ -2192,6 +2497,9 @@ public function test_post_named_random_does_not_flush_rewrite_rules_with_a_blog_ $this->assertSame( 0, $flushes->get_call_count(), 'A post named random should not flush the rewrite rules when posts have a blog prefix.' ); } + /** + * Ensure random content redirects resume when a post named "random" is unpublished. + */ public function test_unpublishing_a_post_named_random_resumes_random_content_redirects(): void { $post = $this->create_post( array( 'post_name' => 'random' ) ); From c73c33e1a8d2053b88a4c4507538d1cca1771bce Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 09:53:57 +1100 Subject: [PATCH 4/9] Remove cache flushing handled by base test suite. --- tests/phpunit/tests/query/randomContentRedirect.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/phpunit/tests/query/randomContentRedirect.php b/tests/phpunit/tests/query/randomContentRedirect.php index 8248908453426..a636206a1fc1c 100644 --- a/tests/phpunit/tests/query/randomContentRedirect.php +++ b/tests/phpunit/tests/query/randomContentRedirect.php @@ -1736,8 +1736,6 @@ public function test_random_post_is_selected_by_a_single_random_id_query(): void public function test_random_post_is_loaded_by_id_after_the_random_query(): void { global $wpdb; - wp_cache_flush(); - $this->go_to_and_record_queries( home_url( '/random/' ) ); $this->assertLessThanOrEqual( 2, count( $this->queries ), "No more than two database queries should be made to select the random post:\n" . implode( "\n", $this->queries ) ); From baf147730e3615270505ea772cea50ff4eae142e Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 09:59:28 +1100 Subject: [PATCH 5/9] Fix testing persistent object cache. --- tests/phpunit/tests/query/randomContentRedirect.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/query/randomContentRedirect.php b/tests/phpunit/tests/query/randomContentRedirect.php index a636206a1fc1c..2042bb2a5e7b9 100644 --- a/tests/phpunit/tests/query/randomContentRedirect.php +++ b/tests/phpunit/tests/query/randomContentRedirect.php @@ -1768,7 +1768,9 @@ public function test_random_query_does_not_prime_meta_or_term_caches(): void { * would be selected until the cache is invalidated. */ public function test_random_query_is_not_cached_with_persistent_object_cache(): void { - $using_ext_cache = wp_using_ext_object_cache( true ); + if ( ! wp_using_ext_object_cache() ) { + $this->markTestSkipped( 'This test requires an external object cache.' ); + } $this->go_to_and_record_queries( home_url( '/random/' ) ); $first_request_queries = $this->queries; @@ -1777,8 +1779,6 @@ public function test_random_query_is_not_cached_with_persistent_object_cache(): $this->redirect_location = null; $this->go_to_and_record_queries( home_url( '/random/' ) ); - wp_using_ext_object_cache( $using_ext_cache ); - $this->assertCount( 1, preg_grep( '/RAND\(\)/', $first_request_queries ), 'The first request should run the random query.' ); $this->assertCount( 1, preg_grep( '/RAND\(\)/', $this->queries ), "The second request should run the random query again rather than reuse a cached result:\n" . implode( "\n", $this->queries ) ); } From b2bf3488619bf4359ee63ec3aa434ff9e4f66c56 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 10:20:44 +1100 Subject: [PATCH 6/9] Remove flawed cache test: go_to() flushes the cache. --- .../tests/query/randomContentRedirect.php | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/tests/phpunit/tests/query/randomContentRedirect.php b/tests/phpunit/tests/query/randomContentRedirect.php index 2042bb2a5e7b9..be730c977ae23 100644 --- a/tests/phpunit/tests/query/randomContentRedirect.php +++ b/tests/phpunit/tests/query/randomContentRedirect.php @@ -1763,26 +1763,6 @@ public function test_random_query_does_not_prime_meta_or_term_caches(): void { } } - /** - * The random ID query must never be served from the query cache, or the same post - * would be selected until the cache is invalidated. - */ - public function test_random_query_is_not_cached_with_persistent_object_cache(): void { - if ( ! wp_using_ext_object_cache() ) { - $this->markTestSkipped( 'This test requires an external object cache.' ); - } - - $this->go_to_and_record_queries( home_url( '/random/' ) ); - $first_request_queries = $this->queries; - - $this->queries = array(); - $this->redirect_location = null; - $this->go_to_and_record_queries( home_url( '/random/' ) ); - - $this->assertCount( 1, preg_grep( '/RAND\(\)/', $first_request_queries ), 'The first request should run the random query.' ); - $this->assertCount( 1, preg_grep( '/RAND\(\)/', $this->queries ), "The second request should run the random query again rather than reuse a cached result:\n" . implode( "\n", $this->queries ) ); - } - /** * Ensure different posts are selected across random requests. */ From 44e79215a34c68920c8512a306e0a0651b04c9ce Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 10:22:28 +1100 Subject: [PATCH 7/9] Introduce tests specifically for `WP::handle_random()`. --- tests/phpunit/tests/wp/handleRandom.php | 172 ++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 tests/phpunit/tests/wp/handleRandom.php diff --git a/tests/phpunit/tests/wp/handleRandom.php b/tests/phpunit/tests/wp/handleRandom.php new file mode 100644 index 0000000000000..fbe3ac31d448a --- /dev/null +++ b/tests/phpunit/tests/wp/handleRandom.php @@ -0,0 +1,172 @@ +post->create_many( 5 ); + } + + /** + * Captures redirects before each test. + */ + public function set_up() { + parent::set_up(); + + $this->redirect_location = null; + + // Capture redirects and prevent `exit` from ending the test run. + add_filter( 'wp_redirect', array( $this, 'filter_wp_redirect' ) ); + } + + /** + * Captures the redirect and prevents it from being sent. + * + * @param string $location Redirect location. + * @return false + */ + public function filter_wp_redirect( $location ) { + $this->redirect_location = $location; + + return false; + } + + /** + * Handles a random content request with a new main query. + * + * Unlike WP_UnitTestCase_Base::go_to(), the request is handled without flushing the + * cache or running the rest of WP::main(). + * + * @param array $query_vars Query variables for the request. + * @return bool Whether the main query was run for a random content request. + */ + protected function handle_random( array $query_vars ): bool { + $GLOBALS['wp_the_query'] = new WP_Query(); + $GLOBALS['wp_query'] = $GLOBALS['wp_the_query']; + + $wp = new WP(); + $wp->query_vars = $query_vars; + + return $wp->handle_random(); + } + + /** + * Ensure random content queries are not served from the query cache. + * + * If the ID query were cached, the same post would be selected until the cache is + * invalidated. + * + * @ticket 64498 + */ + public function test_random_content_queries_are_not_cached() { + $queries = new MockAction(); + add_filter( 'query', array( $queries, 'filter' ) ); + + $this->handle_random( array( 'random' => '' ) ); + $this->handle_random( array( 'random' => '' ) ); + + $random_queries = preg_grep( '/RAND\(\)/', array_column( $queries->get_args(), 0 ) ); + + $this->assertCount( 2, $random_queries, 'The random ID query should run for each request rather than reuse a cached result.' ); + } + + /** + * Ensure the main query runs unchanged for requests with the random query variable + * that are not random content requests. + * + * The main query must not be run again by WP::main() and any 404 is left to + * WP::handle_404(). + * + * @ticket 64498 + * + * @dataProvider data_requests_that_are_not_random_content_requests + * + * @param array $query_vars Query variables for the request. + * @param string $request_method HTTP request method. + */ + public function test_main_query_runs_unchanged_for_requests_that_are_not_random_content_requests( array $query_vars, string $request_method ) { + $_SERVER['REQUEST_METHOD'] = $request_method; + + $handled = $this->handle_random( $query_vars ); + + $request = $GLOBALS['wp_the_query']->request; + + $this->assertTrue( $handled, 'The main query should be reported as run.' ); + $this->assertIsString( $request, 'The main query was not run.' ); + $this->assertStringNotContainsString( 'RAND()', $request, 'The main query should not be randomized.' ); + $this->assertNull( $this->redirect_location, 'The request should not redirect.' ); + $this->assertFalse( is_404(), 'The request should not be set to a 404.' ); + } + + /** + * Data provider. + * + * @return array, 1: string}> + */ + public function data_requests_that_are_not_random_content_requests(): array { + return array( + 'post request' => array( array( 'random' => '' ), 'POST' ), + 'non-randomable without posts' => array( + array( + 'random' => '', + 'post_type' => 'page', + ), + 'GET', + ), + ); + } + + /** + * Ensure the request continues with the selected post when it cannot be redirected to. + * + * @ticket 64498 + * + * @dataProvider data_permalinks_that_cannot_be_redirected_to + * + * @param string $permalink Permalink of the selected post. + */ + public function test_request_continues_with_the_selected_post_when_it_is_not_redirected( string $permalink ) { + add_filter( + 'post_link', + static function () use ( $permalink ): string { + return $permalink; + } + ); + + $handled = $this->handle_random( array( 'random' => '' ) ); + + $this->assertTrue( $handled, 'The main query should be reported as run.' ); + $this->assertNull( $this->redirect_location, 'The request should not redirect.' ); + $this->assertInstanceOf( WP_Post::class, $GLOBALS['wp_the_query']->post, 'The selected post should remain in the main query.' ); + $this->assertFalse( is_404(), 'The request should not be set to a 404.' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_permalinks_that_cannot_be_redirected_to(): array { + return array( + 'empty permalink' => array( '' ), + 'off-site permalink' => array( 'https://elsewhere.example/post/' ), + ); + } +} From ac755bab7695dde1a1b04765e028379a2b2decdc Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 11:09:10 +1100 Subject: [PATCH 8/9] Add tests for handle_random returning false. --- tests/phpunit/tests/wp/handleRandom.php | 44 +++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/phpunit/tests/wp/handleRandom.php b/tests/phpunit/tests/wp/handleRandom.php index fbe3ac31d448a..bfe772859483f 100644 --- a/tests/phpunit/tests/wp/handleRandom.php +++ b/tests/phpunit/tests/wp/handleRandom.php @@ -67,6 +67,50 @@ protected function handle_random( array $query_vars ): bool { return $wp->handle_random(); } + /** + * Ensure requests without the random query variable are not handled. + * + * @ticket 64498 + * + * @dataProvider data_requests_without_the_random_query_var + * + * @param array $query_vars Query variables for the request. + */ + public function test_requests_without_the_random_query_var_are_not_handled( array $query_vars ) { + $handled = $this->handle_random( $query_vars ); + + $this->assertFalse( $handled, 'Requests without the random query variable should not be handled.' ); + $this->assertNull( $GLOBALS['wp_the_query']->request, 'The main query should be left for WP::main() to run.' ); + $this->assertNull( $this->redirect_location, 'The request should not redirect.' ); + } + + /** + * Data provider. + * + * @return array}> + */ + public function data_requests_without_the_random_query_var(): array { + return array( + 'no query vars' => array( array() ), + 'other query vars' => array( array( 'post_type' => 'post' ) ), + ); + } + + /** + * Ensure random content requests are not handled when the feature is disabled. + * + * @ticket 64498 + */ + public function test_random_content_requests_are_not_handled_when_disabled() { + add_filter( 'wp_enable_random_content_redirect', '__return_false' ); + + $handled = $this->handle_random( array( 'random' => '' ) ); + + $this->assertFalse( $handled, 'Random content requests should not be handled when the feature is disabled.' ); + $this->assertNull( $GLOBALS['wp_the_query']->request, 'The main query should be left for WP::main() to run.' ); + $this->assertNull( $this->redirect_location, 'The request should not redirect.' ); + } + /** * Ensure random content queries are not served from the query cache. * From 0d9c1584b17910124c7b3bc0a3d3607bc3dbd7e2 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Fri, 30 Oct 2026 11:36:24 +1100 Subject: [PATCH 9/9] Types in tests. --- .../tests/query/randomContentRedirect.php | 97 ++++++++++--------- tests/phpunit/tests/wp/handleRandom.php | 28 +++--- 2 files changed, 65 insertions(+), 60 deletions(-) diff --git a/tests/phpunit/tests/query/randomContentRedirect.php b/tests/phpunit/tests/query/randomContentRedirect.php index be730c977ae23..5798c699d65a0 100644 --- a/tests/phpunit/tests/query/randomContentRedirect.php +++ b/tests/phpunit/tests/query/randomContentRedirect.php @@ -175,7 +175,7 @@ public function tear_down(): void { * @param int $status Redirect status. * @return false */ - public function filter_wp_redirect( $location, $status ) { + public function filter_wp_redirect( string $location, int $status ) { $this->redirect_location = $location; $this->redirect_status = $status; $this->recording_queries = false; @@ -196,7 +196,7 @@ public function start_recording_queries(): void { * @param string $query Database query. * @return string Unmodified database query. */ - public function record_query( $query ) { + public function record_query( string $query ) { if ( $this->recording_queries ) { $this->queries[] = $query; } @@ -209,7 +209,7 @@ public function record_query( $query ) { * * @param string $url URL to request. */ - protected function go_to_and_record_queries( $url ): void { + protected function go_to_and_record_queries( string $url ): void { add_action( 'parse_request', array( $this, 'start_recording_queries' ), PHP_INT_MAX ); add_filter( 'query', array( $this, 'record_query' ) ); @@ -297,16 +297,16 @@ protected function assertQueryIsNotRandomized( WP_Query $query, string $message * * @param string $path Random content request path. */ - public function test_random_url_redirects_to_a_published_post( $path ): void { + public function test_random_url_redirects_to_a_published_post( string $path ): void { $this->go_to( home_url( $path ) ); $this->assertRedirectedToOneOf( array( self::$arts_post, self::$sport_post ), 'The random URL should redirect to a published post.' ); } /** - * Data provider. + * Data provider for {@see self::test_random_url_redirects_to_a_published_post()}. * - * @return array + * @return array */ public function data_random_urls(): array { return array( @@ -743,7 +743,7 @@ public function test_no_redirect_for_taxonomy_used_only_by_pages(): void { * @param string $url URL to request. * @param string[] $expected Expected post types. */ - public function test_wp_get_random_content_post_types( $url, $expected ): void { + public function test_wp_get_random_content_post_types( string $url, array $expected ): void { register_post_type( 'wptests_book', array( @@ -772,9 +772,9 @@ public function test_wp_get_random_content_post_types( $url, $expected ): void { } /** - * Data provider. + * Data provider for {@see self::test_wp_get_random_content_post_types()}. * - * @return array + * @return array }> */ public function data_wp_get_random_content_post_types(): array { return array( @@ -835,7 +835,7 @@ public function test_random_redirect_ignores_pagination(): void { * * @param array $args Post arguments. */ - public function test_random_redirect_excludes_ineligible_posts( $args ): void { + public function test_random_redirect_excludes_ineligible_posts( array $args ): void { $category = self::factory()->category->create(); $this->create_post( array_merge( array( 'post_category' => array( $category ) ), $args ) ); @@ -847,9 +847,9 @@ public function test_random_redirect_excludes_ineligible_posts( $args ): void { } /** - * Data provider. + * Data provider for {@see self::test_random_redirect_excludes_ineligible_posts()}. * - * @return array}> + * @return array }> */ public function data_ineligible_posts(): array { return array( @@ -988,7 +988,7 @@ public function test_no_redirect_for_static_front_page_with_random_query_var_fro * * @param string $path Feed path. */ - public function test_no_redirect_for_feeds( $path ): void { + public function test_no_redirect_for_feeds( string $path ): void { $this->go_to( home_url( $path ) ); $this->assertNotRedirected( 'Feeds should not redirect.' ); @@ -996,9 +996,9 @@ public function test_no_redirect_for_feeds( $path ): void { } /** - * Data provider. + * Data provider for {@see self::test_no_redirect_for_feeds()}. * - * @return array + * @return array */ public function data_feed_urls(): array { return array( @@ -1064,7 +1064,7 @@ static function ( string $where, WP_Query $query ): string { * * @param string $method HTTP request method. */ - public function test_no_redirect_for_non_get_requests( $method ): void { + public function test_no_redirect_for_non_get_requests( string $method ): void { $_SERVER['REQUEST_METHOD'] = $method; $this->go_to( home_url( '/random/' ) ); @@ -1073,9 +1073,9 @@ public function test_no_redirect_for_non_get_requests( $method ): void { } /** - * Data provider. + * Data provider for {@see self::test_no_redirect_for_non_get_requests()}. * - * @return array + * @return array */ public function data_non_redirecting_http_methods(): array { return array( @@ -1104,7 +1104,7 @@ public function test_no_redirect_without_request_method(): void { * * @param string $method HTTP request method. */ - public function test_redirect_for_get_and_head_requests( $method ): void { + public function test_redirect_for_get_and_head_requests( string $method ): void { $_SERVER['REQUEST_METHOD'] = $method; $this->go_to( home_url( '/random/' ) ); @@ -1113,9 +1113,9 @@ public function test_redirect_for_get_and_head_requests( $method ): void { } /** - * Data provider. + * Data provider for {@see self::test_redirect_for_get_and_head_requests()}. * - * @return array + * @return array */ public function data_redirecting_http_methods(): array { return array( @@ -1139,7 +1139,7 @@ public function data_redirecting_http_methods(): array { * * @param string $structure Permalink structure. */ - public function test_page_with_slug_beginning_with_random_base_does_not_conflict( $structure ): void { + public function test_page_with_slug_beginning_with_random_base_does_not_conflict( string $structure ): void { global $wp; $this->set_permalink_structure( $structure ); @@ -1173,7 +1173,7 @@ public function test_page_with_slug_beginning_with_random_base_does_not_conflict * * @param string $structure Permalink structure. */ - public function test_random_url_redirects_when_a_page_slug_begins_with_random_base( $structure ): void { + public function test_random_url_redirects_when_a_page_slug_begins_with_random_base( string $structure ): void { global $wp_rewrite; $this->set_permalink_structure( $structure ); @@ -1201,7 +1201,7 @@ public function test_random_url_redirects_when_a_page_slug_begins_with_random_ba * * @param string $structure Permalink structure. */ - public function test_page_named_random_takes_precedence_over_random_content_redirects( $structure ): void { + public function test_page_named_random_takes_precedence_over_random_content_redirects( string $structure ): void { global $wp_rewrite; $this->set_permalink_structure( $structure ); @@ -1224,9 +1224,10 @@ public function test_page_named_random_takes_precedence_over_random_content_redi } /** - * Data provider. + * Data provider for {@see self::test_page_with_slug_beginning_with_random_base_does_not_conflict()}, {@see self::test_random_url_redirects_when_a_page_slug_begins_with_random_base()}, + * and {@see self::test_page_named_random_takes_precedence_over_random_content_redirects()}. * - * @return array + * @return array */ public function data_permalink_structures(): array { return array( @@ -1293,7 +1294,7 @@ public function test_draft_page_named_random_does_not_take_precedence(): void { * * @param callable $change Callback to change the page so it no longer conflicts. */ - public function test_random_content_redirects_resume_when_the_page_no_longer_conflicts( $change ): void { + public function test_random_content_redirects_resume_when_the_page_no_longer_conflicts( callable $change ): void { $page = $this->create_post( array( 'post_type' => 'page', @@ -1311,9 +1312,9 @@ public function test_random_content_redirects_resume_when_the_page_no_longer_con } /** - * Data provider. + * Data provider for {@see self::test_random_content_redirects_resume_when_the_page_no_longer_conflicts()}. * - * @return array + * @return array */ public function data_page_named_random_changes(): array { return array( @@ -1571,7 +1572,7 @@ public function test_wp_is_random_content_query_for_main_query(): void { * @param string $path Path to request. * @param bool $expected Expected result. */ - public function test_is_random( $path, $expected ): void { + public function test_is_random( string $path, bool $expected ): void { $this->go_to( home_url( $path ) ); $this->assertSame( $expected, is_random(), 'The is_random() conditional tag returned an unexpected value.' ); @@ -1579,9 +1580,9 @@ public function test_is_random( $path, $expected ): void { } /** - * Data provider. + * Data provider for {@see self::test_is_random()}. * - * @return array + * @return array */ public function data_is_random(): array { return array( @@ -1795,7 +1796,7 @@ public function test_random_selection_varies_between_requests(): void { * @param string $query_var Query variable set by a theme. * @param mixed $value Query variable value. */ - public function test_random_query_is_limited_to_one_post_when_a_theme_overrides_the_limit( $path, $query_var, $value ): void { + public function test_random_query_is_limited_to_one_post_when_a_theme_overrides_the_limit( string $path, string $query_var, $value ): void { add_action( 'pre_get_posts', static function ( WP_Query $query ) use ( $query_var, $value ): void { @@ -1814,11 +1815,11 @@ static function ( WP_Query $query ) use ( $query_var, $value ): void { } /** - * Data provider. + * Data provider for {@see self::test_random_query_is_limited_to_one_post_when_a_theme_overrides_the_limit()}. * * The limit is applied differently to the home page and archives, see WP_Query::get_posts(). * - * @return array + * @return array */ public function data_query_vars_overriding_the_limit(): array { $overrides = array( @@ -1834,7 +1835,11 @@ public function data_query_vars_overriding_the_limit(): array { 'archive' => '/random/category/arts/', ) as $context => $path ) { foreach ( $overrides as $name => $override ) { - $data[ "{$context}: {$name}" ] = array( $path, $override[0], $override[1] ); + $data[ "{$context}: {$name}" ] = array( + 'path' => $path, + 'query_var' => $override[0], + 'value' => $override[1], + ); } } @@ -2027,7 +2032,7 @@ static function ( WP_Query $query ): void { * @param mixed $value Value returned by the filter. * @param bool $expected Expected result. */ - public function test_wp_is_random_content_redirect_enabled_returns_a_boolean( $value, $expected ): void { + public function test_wp_is_random_content_redirect_enabled_returns_a_boolean( $value, bool $expected ): void { add_filter( 'wp_enable_random_content_redirect', static function () use ( $value ) { @@ -2039,9 +2044,9 @@ static function () use ( $value ) { } /** - * Data provider. + * Data provider for {@see self::test_wp_is_random_content_redirect_enabled_returns_a_boolean()}. * - * @return array + * @return array */ public function data_enabled_filter_values(): array { return array( @@ -2221,7 +2226,7 @@ public function test_password_protected_page_named_random_takes_precedence(): vo * * @param string $path Request path. */ - public function test_no_redirect_for_paths_without_random_rules( $path ): void { + public function test_no_redirect_for_paths_without_random_rules( string $path ): void { global $wp; $this->go_to( home_url( $path ) ); @@ -2231,9 +2236,9 @@ public function test_no_redirect_for_paths_without_random_rules( $path ): void { } /** - * Data provider. + * Data provider for {@see self::test_no_redirect_for_paths_without_random_rules()}. * - * @return array + * @return array */ public function data_unsupported_random_paths(): array { return array( @@ -2314,9 +2319,9 @@ public function test_main_query_is_run_once_for_random_requests( string $path ): } /** - * Data provider for test_main_query_is_run_once_for_random_requests(). + * Data provider for {@see self::test_main_query_is_run_once_for_random_requests()}. * - * @return array + * @return array */ public function data_random_requests(): array { return array( @@ -2413,9 +2418,9 @@ public function test_post_named_random_takes_precedence_over_random_content_redi } /** - * Data provider. + * Data provider for {@see self::test_post_named_random_takes_precedence_over_random_content_redirects()}. * - * @return array + * @return array */ public function data_post_name_at_the_root_structures(): array { return array( diff --git a/tests/phpunit/tests/wp/handleRandom.php b/tests/phpunit/tests/wp/handleRandom.php index bfe772859483f..0e669fd36b186 100644 --- a/tests/phpunit/tests/wp/handleRandom.php +++ b/tests/phpunit/tests/wp/handleRandom.php @@ -20,14 +20,14 @@ class Tests_WP_HandleRandom extends WP_UnitTestCase { * * @param WP_UnitTest_Factory $factory Test factory. */ - public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { + public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ): void { $factory->post->create_many( 5 ); } /** * Captures redirects before each test. */ - public function set_up() { + public function set_up(): void { parent::set_up(); $this->redirect_location = null; @@ -42,7 +42,7 @@ public function set_up() { * @param string $location Redirect location. * @return false */ - public function filter_wp_redirect( $location ) { + public function filter_wp_redirect( string $location ) { $this->redirect_location = $location; return false; @@ -76,7 +76,7 @@ protected function handle_random( array $query_vars ): bool { * * @param array $query_vars Query variables for the request. */ - public function test_requests_without_the_random_query_var_are_not_handled( array $query_vars ) { + public function test_requests_without_the_random_query_var_are_not_handled( array $query_vars ): void { $handled = $this->handle_random( $query_vars ); $this->assertFalse( $handled, 'Requests without the random query variable should not be handled.' ); @@ -85,9 +85,9 @@ public function test_requests_without_the_random_query_var_are_not_handled( arra } /** - * Data provider. + * Data provider for {@see self::test_requests_without_the_random_query_var_are_not_handled()}. * - * @return array}> + * @return array }> */ public function data_requests_without_the_random_query_var(): array { return array( @@ -101,7 +101,7 @@ public function data_requests_without_the_random_query_var(): array { * * @ticket 64498 */ - public function test_random_content_requests_are_not_handled_when_disabled() { + public function test_random_content_requests_are_not_handled_when_disabled(): void { add_filter( 'wp_enable_random_content_redirect', '__return_false' ); $handled = $this->handle_random( array( 'random' => '' ) ); @@ -119,7 +119,7 @@ public function test_random_content_requests_are_not_handled_when_disabled() { * * @ticket 64498 */ - public function test_random_content_queries_are_not_cached() { + public function test_random_content_queries_are_not_cached(): void { $queries = new MockAction(); add_filter( 'query', array( $queries, 'filter' ) ); @@ -145,7 +145,7 @@ public function test_random_content_queries_are_not_cached() { * @param array $query_vars Query variables for the request. * @param string $request_method HTTP request method. */ - public function test_main_query_runs_unchanged_for_requests_that_are_not_random_content_requests( array $query_vars, string $request_method ) { + public function test_main_query_runs_unchanged_for_requests_that_are_not_random_content_requests( array $query_vars, string $request_method ): void { $_SERVER['REQUEST_METHOD'] = $request_method; $handled = $this->handle_random( $query_vars ); @@ -160,9 +160,9 @@ public function test_main_query_runs_unchanged_for_requests_that_are_not_random_ } /** - * Data provider. + * Data provider for {@see self::test_main_query_runs_unchanged_for_requests_that_are_not_random_content_requests()}. * - * @return array, 1: string}> + * @return array, 1: non-falsy-string }> */ public function data_requests_that_are_not_random_content_requests(): array { return array( @@ -186,7 +186,7 @@ public function data_requests_that_are_not_random_content_requests(): array { * * @param string $permalink Permalink of the selected post. */ - public function test_request_continues_with_the_selected_post_when_it_is_not_redirected( string $permalink ) { + public function test_request_continues_with_the_selected_post_when_it_is_not_redirected( string $permalink ): void { add_filter( 'post_link', static function () use ( $permalink ): string { @@ -203,9 +203,9 @@ static function () use ( $permalink ): string { } /** - * Data provider. + * Data provider for {@see self::test_request_continues_with_the_selected_post_when_it_is_not_redirected()}. * - * @return array + * @return array */ public function data_permalinks_that_cannot_be_redirected_to(): array { return array(