From 0065b1654e9a157d22f7df189af9aae15b20a513 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 15:11:23 -0700 Subject: [PATCH 01/16] Add preload paths filter introduced in https://github.com/WordPress/gutenberg/pull/77353 --- .../build/pages/options-connectors/page-wp-admin.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/wp-includes/build/pages/options-connectors/page-wp-admin.php b/src/wp-includes/build/pages/options-connectors/page-wp-admin.php index 3f3048b8fb98b..c3031a9c5b83d 100644 --- a/src/wp-includes/build/pages/options-connectors/page-wp-admin.php +++ b/src/wp-includes/build/pages/options-connectors/page-wp-admin.php @@ -93,6 +93,18 @@ function wp_options_connectors_wp_admin_preload_data() { array( '/wp/v2/settings', 'OPTIONS' ), ); + /** + * Filters the REST API paths preloaded for this page. + * + * Each entry is either a string path (GET) or a `[ path, method ]` tuple. + * Pages that know which requests their JS will issue on mount can add + * them here so the responses are embedded in the initial HTML rather + * than fetched over the network after hydration. + * + * @param string[] $preload_paths Paths to preload. + */ + $preload_paths = apply_filters( 'options-connectors-wp-admin_preload_paths', $preload_paths ); + // Use rest_preload_api_request to gather the preloaded data $preload_data = array_reduce( $preload_paths, From 1b0d88d6baaa50536e1e77737b1026616d58a33d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 15:11:50 -0700 Subject: [PATCH 02/16] Preload REST API requests used on the Connectors screen --- src/wp-admin/options-connectors.php | 39 +++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/wp-admin/options-connectors.php b/src/wp-admin/options-connectors.php index c67d857b2b60d..a04e3df58e094 100644 --- a/src/wp-admin/options-connectors.php +++ b/src/wp-admin/options-connectors.php @@ -32,6 +32,45 @@ // Set parent file for menu highlighting. $parent_file = 'options-general.php'; +/** + * Preloads the REST API responses the Connectors UI fetches on mount. + * + * Without this, the page does a network round-trip for site settings, + * plugin capability discovery, and each connector's plugin record after + * the JS hydrates, which noticeably delays first paint. + * + * @since 7.0.0 + * @access private + * + * @param string[] $preload_paths Paths already queued for preloading. + * @return string[] Paths with the Connectors-specific requests appended. + */ +function _wp_connectors_preload_paths( array $preload_paths ): array { + // getEntityRecord( 'root', 'site' ) in stage.tsx / use-connector-plugin.ts. + $preload_paths[] = '/wp/v2/settings'; + + // canUser( 'create', { kind: 'root', name: 'plugin' } ) in stage.tsx. + $preload_paths[] = array( '/wp/v2/plugins', 'OPTIONS' ); + + // AiPluginCallout in routes/connectors-home/ai-plugin-callout.tsx queries this + // hardcoded ID to check whether the WP AI plugin is installed/active. + $preload_paths[] = '/wp/v2/plugins/ai/ai?context=edit'; + + // getEntityRecord( 'root', 'plugin', ) per connector in use-connector-plugin.ts. + foreach ( wp_get_connectors() as $connector_data ) { + if ( empty( $connector_data['plugin']['file'] ) ) { + continue; + } + // core-data's plugin entity uses the basename with `.php` stripped + // as the record key (see routes/connectors-home/use-connector-plugin.ts). + $basename = preg_replace( '/\.php$/', '', plugin_basename( $connector_data['plugin']['file'] ) ); + $preload_paths[] = '/wp/v2/plugins/' . $basename . '?context=edit'; + } + + return $preload_paths; +} +add_filter( 'options-connectors-wp-admin_preload_paths', '_wp_connectors_preload_paths' ); + require_once ABSPATH . 'wp-admin/admin-header.php'; // Render the Connectors page. From 7f32ee46a732018c16f9bb6b69e82324300a24fd Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 15:56:35 -0700 Subject: [PATCH 03/16] Supply improved type for WP_HTTP_Response::$headers --- src/wp-includes/class-wp-http-response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-http-response.php b/src/wp-includes/class-wp-http-response.php index d102877885b7c..23395053f91af 100644 --- a/src/wp-includes/class-wp-http-response.php +++ b/src/wp-includes/class-wp-http-response.php @@ -27,7 +27,7 @@ class WP_HTTP_Response { * Response headers. * * @since 4.4.0 - * @var array + * @var array */ public $headers; From 9b38307b4269fd2afa24e1e3908a18fdeaff0c2b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 15:57:46 -0700 Subject: [PATCH 04/16] Harden rest_preload_api_request() and address PHPStan errors --- src/wp-includes/rest-api.php | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index 5548ecf5c6f45..ff1416c1bf9a1 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -2930,9 +2930,13 @@ function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { * * @since 5.0.0 * - * @param array $memo Reduce accumulator. - * @param string $path REST API path to preload. + * @param array $memo Reduce accumulator. + * @param string|array $path REST API path to preload. * @return array Modified reduce accumulator. + * + * @phpstan-param array, headers: array } | array, headers: array }> > $memo + * @phpstan-param string|array{ 0: string, 1?: 'GET'|'OPTIONS' } $path + * @phpstan-return array, headers: array } | array, headers: array }> > */ function rest_preload_api_request( $memo, $path ) { /* @@ -2948,10 +2952,13 @@ function rest_preload_api_request( $memo, $path ) { } $method = 'GET'; - if ( is_array( $path ) && 2 === count( $path ) ) { - $method = end( $path ); - $path = reset( $path ); - + if ( is_array( $path ) ) { + $path_array = $path; + $path = array_shift( $path_array ); + if ( ! is_string( $path ) ) { + return $memo; + } + $method = array_shift( $path_array ); if ( ! in_array( $method, array( 'GET', 'OPTIONS' ), true ) ) { $method = 'GET'; } @@ -2964,11 +2971,11 @@ function rest_preload_api_request( $memo, $path ) { } $path_parts = parse_url( $path ); - if ( false === $path_parts ) { + if ( false === $path_parts || ! isset( $path_parts['path'] ) ) { return $memo; } - if ( isset( $path_parts['path'] ) && '/' !== $path_parts['path'] ) { + if ( '/' !== $path_parts['path'] ) { // Remove trailing slashes from the "path" part of the REST API path. $path_parts['path'] = untrailingslashit( $path_parts['path'] ); $path = str_contains( $path, '?' ) ? @@ -2987,8 +2994,16 @@ function rest_preload_api_request( $memo, $path ) { $server = rest_get_server(); /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */ $response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $server, $request ); - $embed = $request->has_param( '_embed' ) ? rest_parse_embed_param( $request['_embed'] ) : false; - $data = (array) $server->response_to_data( $response, $embed ); + if ( ! $response instanceof WP_REST_Response ) { + return $memo; + } + + if ( $request->has_param( '_embed' ) && ( is_array( $request['_embed'] ) || is_string( $request['_embed'] ) ) ) { + $embed = rest_parse_embed_param( $request['_embed'] ); + } else { + $embed = false; + } + $data = (array) $server->response_to_data( $response, $embed ); if ( 'OPTIONS' === $method ) { $memo[ $method ][ $path ] = array( From d4b1ec01135fe50df6ef13e7453bf04e7ec1e1c6 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 16:13:13 -0700 Subject: [PATCH 05/16] Allow preloading REST API responses with non-OK statuses --- src/wp-admin/options-connectors.php | 4 ++-- src/wp-includes/rest-api.php | 14 +++++++++++--- tests/phpunit/tests/rest-api.php | 25 +++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/wp-admin/options-connectors.php b/src/wp-admin/options-connectors.php index a04e3df58e094..39ddb6f42d19e 100644 --- a/src/wp-admin/options-connectors.php +++ b/src/wp-admin/options-connectors.php @@ -54,7 +54,7 @@ function _wp_connectors_preload_paths( array $preload_paths ): array { // AiPluginCallout in routes/connectors-home/ai-plugin-callout.tsx queries this // hardcoded ID to check whether the WP AI plugin is installed/active. - $preload_paths[] = '/wp/v2/plugins/ai/ai?context=edit'; + $preload_paths[] = array( '/wp/v2/plugins/ai/ai?context=edit', 'GET', array( 200, 404 ) ); // getEntityRecord( 'root', 'plugin', ) per connector in use-connector-plugin.ts. foreach ( wp_get_connectors() as $connector_data ) { @@ -64,7 +64,7 @@ function _wp_connectors_preload_paths( array $preload_paths ): array { // core-data's plugin entity uses the basename with `.php` stripped // as the record key (see routes/connectors-home/use-connector-plugin.ts). $basename = preg_replace( '/\.php$/', '', plugin_basename( $connector_data['plugin']['file'] ) ); - $preload_paths[] = '/wp/v2/plugins/' . $basename . '?context=edit'; + $preload_paths[] = array( '/wp/v2/plugins/' . $basename . '?context=edit', 'GET', array( 200, 404 ) ); } return $preload_paths; diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index ff1416c1bf9a1..702134458ff86 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -2935,7 +2935,7 @@ function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { * @return array Modified reduce accumulator. * * @phpstan-param array, headers: array } | array, headers: array }> > $memo - * @phpstan-param string|array{ 0: string, 1?: 'GET'|'OPTIONS' } $path + * @phpstan-param string|array{ 0: string, 1?: 'GET'|'OPTIONS', 2?: int<100, 599>|int<100, 599>[] } $path * @phpstan-return array, headers: array } | array, headers: array }> > */ function rest_preload_api_request( $memo, $path ) { @@ -2951,7 +2951,8 @@ function rest_preload_api_request( $memo, $path ) { return $memo; } - $method = 'GET'; + $method = 'GET'; + $allowed_statuses = array( 200 ); if ( is_array( $path ) ) { $path_array = $path; $path = array_shift( $path_array ); @@ -2962,6 +2963,13 @@ function rest_preload_api_request( $memo, $path ) { if ( ! in_array( $method, array( 'GET', 'OPTIONS' ), true ) ) { $method = 'GET'; } + $statuses = array_shift( $path_array ); + if ( $statuses ) { + $statuses = array_filter( (array) $statuses, 'is_int' ); + if ( count( $statuses ) > 0 ) { + $allowed_statuses = $statuses; + } + } } // Remove trailing slashes at the end of the REST API path (query part). @@ -2990,7 +2998,7 @@ function rest_preload_api_request( $memo, $path ) { } $response = rest_do_request( $request ); - if ( 200 === $response->status ) { + if ( in_array( $response->status, $allowed_statuses, true ) ) { $server = rest_get_server(); /** This filter is documented in wp-includes/rest-api/class-wp-rest-server.php */ $response = apply_filters( 'rest_post_dispatch', rest_ensure_response( $response ), $server, $request ); diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 90de3e13eecea..7c3e737b80f10 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -938,12 +938,24 @@ public function test_register_rest_route_without_server() { $this->assertSame( $routes['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/test-ns/test'][0]['methods'], array( 'GET' => true ) ); } - public function test_rest_preload_api_request_with_method() { + /** + * @ticket 65215 + */ + public function test_rest_preload_api_request_with_method_and_allowed_statuses() { $rest_server = $GLOBALS['wp_rest_server']; $GLOBALS['wp_rest_server'] = null; + $exiting_post_id = self::factory()->post->create(); + $missing_post1_id = 10001; + $missing_post2_id = 10001; + $this->assertNull( get_post( $missing_post1_id ), "Expected post with ID $missing_post1_id to not exist." ); + $this->assertNull( get_post( $missing_post2_id ), "Expected post with ID $missing_post1_id to not exist." ); + $preload_paths = array( '/wp/v2/types', + array( "/wp/v2/posts/$exiting_post_id", 'GET', array( 200 ) ), + array( "/wp/v2/posts/$missing_post1_id", 'GET', array( 200, 404 ) ), + array( "/wp/v2/posts/$missing_post2_id", 'GET' ), array( '/wp/v2/media', 'OPTIONS' ), ); @@ -953,9 +965,18 @@ public function test_rest_preload_api_request_with_method() { array() ); - $this->assertSame( array_keys( $preload_data ), array( '/wp/v2/types', 'OPTIONS' ) ); + $this->assertSame( array_keys( $preload_data ), array( '/wp/v2/types', "/wp/v2/posts/$exiting_post_id", "/wp/v2/posts/$missing_post1_id", 'OPTIONS' ) ); $this->assertArrayHasKey( '/wp/v2/media', $preload_data['OPTIONS'] ); + $existing_post_response_data = $preload_data[ "/wp/v2/posts/$exiting_post_id" ]; + $this->assertTrue( isset( $existing_post_response_data['body']['id'] ), 'Expected body.id to be exist.' ); + $this->assertSame( $exiting_post_id, $existing_post_response_data['body']['id'] ); + + $missing_post_response_data = $preload_data[ "/wp/v2/posts/$missing_post1_id" ]; + $this->assertTrue( isset( $missing_post_response_data['body']['code'], $missing_post_response_data['body']['data']['status'] ), 'Expected body.code and body.data.status to exist.' ); + $this->assertSame( 'rest_post_invalid_id', $missing_post_response_data['body']['code'] ); + $this->assertSame( 404, $missing_post_response_data['body']['data']['status'] ); + $GLOBALS['wp_rest_server'] = $rest_server; } From 03527068961ffdc556399efc4ec4b2bd6e3994c9 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 17:04:12 -0700 Subject: [PATCH 06/16] Update phpdoc for _wp_connectors_preload_paths() --- src/wp-admin/options-connectors.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-admin/options-connectors.php b/src/wp-admin/options-connectors.php index 39ddb6f42d19e..5cb5ba60d78ad 100644 --- a/src/wp-admin/options-connectors.php +++ b/src/wp-admin/options-connectors.php @@ -42,8 +42,8 @@ * @since 7.0.0 * @access private * - * @param string[] $preload_paths Paths already queued for preloading. - * @return string[] Paths with the Connectors-specific requests appended. + * @param array|int<100, 599>[] }> $preload_paths Paths already queued for preloading. + * @return array|int<100, 599>[] }> Paths with the Connectors-specific requests appended. */ function _wp_connectors_preload_paths( array $preload_paths ): array { // getEntityRecord( 'root', 'site' ) in stage.tsx / use-connector-plugin.ts. From 35123b520a3d59371b809da1cc8e3d4948d2f63e Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 17:20:12 -0700 Subject: [PATCH 07/16] Revert "Add preload paths filter introduced in https://github.com/WordPress/gutenberg/pull/77353" This reverts commit 0065b1654e9a157d22f7df189af9aae15b20a513. --- .../build/pages/options-connectors/page-wp-admin.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/wp-includes/build/pages/options-connectors/page-wp-admin.php b/src/wp-includes/build/pages/options-connectors/page-wp-admin.php index c3031a9c5b83d..3f3048b8fb98b 100644 --- a/src/wp-includes/build/pages/options-connectors/page-wp-admin.php +++ b/src/wp-includes/build/pages/options-connectors/page-wp-admin.php @@ -93,18 +93,6 @@ function wp_options_connectors_wp_admin_preload_data() { array( '/wp/v2/settings', 'OPTIONS' ), ); - /** - * Filters the REST API paths preloaded for this page. - * - * Each entry is either a string path (GET) or a `[ path, method ]` tuple. - * Pages that know which requests their JS will issue on mount can add - * them here so the responses are embedded in the initial HTML rather - * than fetched over the network after hydration. - * - * @param string[] $preload_paths Paths to preload. - */ - $preload_paths = apply_filters( 'options-connectors-wp-admin_preload_paths', $preload_paths ); - // Use rest_preload_api_request to gather the preloaded data $preload_data = array_reduce( $preload_paths, From 416c45335e74f5ec87845f0ce065d61406db8d0a Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 12 May 2026 09:48:12 -0700 Subject: [PATCH 08/16] Fix duplicated non-existing post ID Co-authored-by: Christoph Daum --- tests/phpunit/tests/rest-api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 7c3e737b80f10..bbdae95006309 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -947,7 +947,7 @@ public function test_rest_preload_api_request_with_method_and_allowed_statuses() $exiting_post_id = self::factory()->post->create(); $missing_post1_id = 10001; - $missing_post2_id = 10001; + $missing_post2_id = 10002; $this->assertNull( get_post( $missing_post1_id ), "Expected post with ID $missing_post1_id to not exist." ); $this->assertNull( get_post( $missing_post2_id ), "Expected post with ID $missing_post1_id to not exist." ); From ad4c7e4a0d5c4cca40ef4f6f157cc5656f65e86b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 12 May 2026 09:48:56 -0700 Subject: [PATCH 09/16] Fix variable reference in assertion message --- tests/phpunit/tests/rest-api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index bbdae95006309..3107e09e72956 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -949,7 +949,7 @@ public function test_rest_preload_api_request_with_method_and_allowed_statuses() $missing_post1_id = 10001; $missing_post2_id = 10002; $this->assertNull( get_post( $missing_post1_id ), "Expected post with ID $missing_post1_id to not exist." ); - $this->assertNull( get_post( $missing_post2_id ), "Expected post with ID $missing_post1_id to not exist." ); + $this->assertNull( get_post( $missing_post2_id ), "Expected post with ID $missing_post2_id to not exist." ); $preload_paths = array( '/wp/v2/types', From e6131bccf11ea275e40019f7b489eae982bb4b1c Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 15 Jun 2026 08:57:20 -0700 Subject: [PATCH 10/16] Update since tag Co-authored-by: Aki Hamano <54422211+t-hamano@users.noreply.github.com> --- src/wp-admin/options-connectors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-admin/options-connectors.php b/src/wp-admin/options-connectors.php index 5cb5ba60d78ad..5d83afbef2ac8 100644 --- a/src/wp-admin/options-connectors.php +++ b/src/wp-admin/options-connectors.php @@ -39,7 +39,7 @@ * plugin capability discovery, and each connector's plugin record after * the JS hydrates, which noticeably delays first paint. * - * @since 7.0.0 + * @since 7.0.1 * @access private * * @param array|int<100, 599>[] }> $preload_paths Paths already queued for preloading. From 01e3dc0a731edfd50b877024caaba36679d2b147 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 15 Jun 2026 18:26:08 -0700 Subject: [PATCH 11/16] Fix PHPStan rule level 10 issues in tests --- tests/phpunit/tests/rest-api.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 964281756a566..22be0cc0b63e0 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -941,11 +941,12 @@ public function test_register_rest_route_without_server() { /** * @ticket 65215 */ - public function test_rest_preload_api_request_with_method_and_allowed_statuses() { + public function test_rest_preload_api_request_with_method_and_allowed_statuses(): void { $rest_server = $GLOBALS['wp_rest_server']; $GLOBALS['wp_rest_server'] = null; - $exiting_post_id = self::factory()->post->create(); + $exiting_post_id = self::factory()->post->create(); + $this->assertIsInt( $exiting_post_id ); $missing_post1_id = 10001; $missing_post2_id = 10002; $this->assertNull( get_post( $missing_post1_id ), "Expected post with ID $missing_post1_id to not exist." ); @@ -973,7 +974,10 @@ public function test_rest_preload_api_request_with_method_and_allowed_statuses() $this->assertSame( $exiting_post_id, $existing_post_response_data['body']['id'] ); $missing_post_response_data = $preload_data[ "/wp/v2/posts/$missing_post1_id" ]; - $this->assertTrue( isset( $missing_post_response_data['body']['code'], $missing_post_response_data['body']['data']['status'] ), 'Expected body.code and body.data.status to exist.' ); + $this->assertTrue( isset( $missing_post_response_data['body']['code'] ), 'Expected body.code to exist.' ); + $this->assertTrue( isset( $missing_post_response_data['body']['data'] ), 'Expected body.data to exist.' ); + $this->assertIsArray( $missing_post_response_data['body']['data'], 'Expected body.data to be an array.' ); + $this->assertTrue( isset( $missing_post_response_data['body']['data']['status'] ), 'Expected body.data.status to exist.' ); $this->assertSame( 'rest_post_invalid_id', $missing_post_response_data['body']['code'] ); $this->assertSame( 404, $missing_post_response_data['body']['data']['status'] ); From 9185ca5712cfa93d2c2442442657fc82a615a089 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:24:42 +0900 Subject: [PATCH 12/16] Fix typo Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/phpunit/tests/rest-api.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 22be0cc0b63e0..b7cae2160404d 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -945,8 +945,8 @@ public function test_rest_preload_api_request_with_method_and_allowed_statuses() $rest_server = $GLOBALS['wp_rest_server']; $GLOBALS['wp_rest_server'] = null; - $exiting_post_id = self::factory()->post->create(); - $this->assertIsInt( $exiting_post_id ); + $existing_post_id = self::factory()->post->create(); + $this->assertIsInt( $existing_post_id ); $missing_post1_id = 10001; $missing_post2_id = 10002; $this->assertNull( get_post( $missing_post1_id ), "Expected post with ID $missing_post1_id to not exist." ); @@ -954,7 +954,7 @@ public function test_rest_preload_api_request_with_method_and_allowed_statuses() $preload_paths = array( '/wp/v2/types', - array( "/wp/v2/posts/$exiting_post_id", 'GET', array( 200 ) ), + array( "/wp/v2/posts/$existing_post_id", 'GET', array( 200 ) ), array( "/wp/v2/posts/$missing_post1_id", 'GET', array( 200, 404 ) ), array( "/wp/v2/posts/$missing_post2_id", 'GET' ), array( '/wp/v2/media', 'OPTIONS' ), From e9f0099ea0c68b43167d4d839692f8d03c2fde22 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Sun, 2 Aug 2026 16:53:21 +0900 Subject: [PATCH 13/16] Fix typo --- tests/phpunit/tests/rest-api.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index b7cae2160404d..9a8ec79006e70 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -966,12 +966,12 @@ public function test_rest_preload_api_request_with_method_and_allowed_statuses() array() ); - $this->assertSame( array_keys( $preload_data ), array( '/wp/v2/types', "/wp/v2/posts/$exiting_post_id", "/wp/v2/posts/$missing_post1_id", 'OPTIONS' ) ); + $this->assertSame( array_keys( $preload_data ), array( '/wp/v2/types', "/wp/v2/posts/$existing_post_id", "/wp/v2/posts/$missing_post1_id", 'OPTIONS' ) ); $this->assertArrayHasKey( '/wp/v2/media', $preload_data['OPTIONS'] ); - $existing_post_response_data = $preload_data[ "/wp/v2/posts/$exiting_post_id" ]; + $existing_post_response_data = $preload_data[ "/wp/v2/posts/$existing_post_id" ]; $this->assertTrue( isset( $existing_post_response_data['body']['id'] ), 'Expected body.id to be exist.' ); - $this->assertSame( $exiting_post_id, $existing_post_response_data['body']['id'] ); + $this->assertSame( $existing_post_id, $existing_post_response_data['body']['id'] ); $missing_post_response_data = $preload_data[ "/wp/v2/posts/$missing_post1_id" ]; $this->assertTrue( isset( $missing_post_response_data['body']['code'] ), 'Expected body.code to exist.' ); From 6236869e538625ed44027df8019405c0623c585d Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 29 Sep 2026 18:07:10 +0900 Subject: [PATCH 14/16] Remove obsolete PHPStan baseline entry for rest_preload_api_request() Co-Authored-By: Claude Opus 5.5 --- tests/phpstan/baselines/argument.type.neon | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon index 925f5cc743e04..8b63dc703579d 100644 --- a/tests/phpstan/baselines/argument.type.neon +++ b/tests/phpstan/baselines/argument.type.neon @@ -1213,11 +1213,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/post.php - - - message: '#^Parameter \#1 \$response of method WP_REST_Server\:\:response_to_data\(\) expects WP_REST_Response, WP_HTTP_Response given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/rest-api.php - message: '#^Parameter \#1 \$haystack of function str_starts_with expects string, int given\.$#' identifier: argument.type From 71701fd86bfdaec282f2f4883039f5de30ec4ce2 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 29 Sep 2026 18:40:02 +0900 Subject: [PATCH 15/16] Rename Connectors preload paths hook to match the Gutenberg wp-build template Co-Authored-By: Claude Opus 5.5 --- src/wp-admin/options-connectors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-admin/options-connectors.php b/src/wp-admin/options-connectors.php index 14ddd446eda12..28ab0ec8cb938 100644 --- a/src/wp-admin/options-connectors.php +++ b/src/wp-admin/options-connectors.php @@ -69,7 +69,7 @@ function _wp_connectors_preload_paths( array $preload_paths ): array { return $preload_paths; } -add_filter( 'options-connectors-wp-admin_preload_paths', '_wp_connectors_preload_paths' ); +add_filter( 'wp_options_connectors_wp_admin_preload_paths', '_wp_connectors_preload_paths' ); require_once ABSPATH . 'wp-admin/admin-header.php'; From 2d55126acc39d4afd01c313a65c115d5adabb737 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Fri, 2 Oct 2026 17:59:30 +0900 Subject: [PATCH 16/16] Update PHPDoc for Connectors preloading and rest_preload_api_request() Bump @since to 7.2.0, fix the JS source reference comment to match the Gutenberg PR, and document the allowed statuses element of the $path array. Co-Authored-By: Claude --- src/wp-admin/options-connectors.php | 4 ++-- src/wp-includes/rest-api.php | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/wp-admin/options-connectors.php b/src/wp-admin/options-connectors.php index 28ab0ec8cb938..63f1bb87c791e 100644 --- a/src/wp-admin/options-connectors.php +++ b/src/wp-admin/options-connectors.php @@ -39,14 +39,14 @@ * plugin capability discovery, and each connector's plugin record after * the JS hydrates, which noticeably delays first paint. * - * @since 7.0.1 + * @since 7.2.0 * @access private * * @param array|int<100, 599>[] }> $preload_paths Paths already queued for preloading. * @return array|int<100, 599>[] }> Paths with the Connectors-specific requests appended. */ function _wp_connectors_preload_paths( array $preload_paths ): array { - // getEntityRecord( 'root', 'site' ) in stage.tsx / use-connector-plugin.ts. + // getEntityRecord( 'root', 'site' ) in use-connector-plugin.ts / ai-plugin-callout.tsx. $preload_paths[] = '/wp/v2/settings'; // canUser( 'create', { kind: 'root', name: 'plugin' } ) in stage.tsx. diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index e6842d176e565..aa698ca10fa90 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -2981,9 +2981,13 @@ function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { * Expected to be called in the context of `array_reduce`. * * @since 5.0.0 + * @since 7.2.0 The `$path` array may include a third element for the allowed response statuses. * * @param array $memo Reduce accumulator. - * @param string|array $path REST API path to preload. + * @param string|array $path REST API path to preload, or an array containing the path, + * the HTTP method ('GET' or 'OPTIONS'), and the allowed response + * status code(s). Only responses with an allowed status are + * preloaded. Default allowed status is 200. * @return array Modified reduce accumulator. * * @phpstan-param array, headers: array } | array, headers: array }> > $memo