Opened 5 weeks ago
Last modified 4 weeks ago
#65215 assigned defect (bug)
Connectors: REST API responses on the Connectors screen should be preloaded
| Reported by: |
|
Owned by: |
|
|---|---|---|---|
| Milestone: | 7.0.1 | Priority: | normal |
| Severity: | normal | Version: | 7.0 |
| Component: | AI | Keywords: | connectors has-patch has-unit-tests |
| Focuses: | rest-api, performance | Cc: |
Description (last modified by )
For screenshots and for what this backports, see Gutenberg PR.
What?
The Connectors screen (options-general.php?page=options-connectors-wp-admin) fires several REST API requests after hydration, delaying the Largest Contentful Paint.
Specifically: GET /wp/v2/settings (site entity), OPTIONS /wp/v2/plugins (the canUser( 'create', 'plugin' ) check), a hardcoded GET /wp/v2/plugins/ai/ai used by the AI-plugin callout, and one GET /wp/v2/plugins/<basename> per registered connector — five sequential round-trips with the default connectors.
Why?
These responses are all trivially knowable at render time on the server, so they should be embedded in the initial HTML via createPreloadingMiddleware rather than re-fetched by the client after hydration. This also reduces the number of requests on the server, reducing server load.
Measured impact (median LCP over 10 runs)
| Scenario | Trunk | This PR | Δ |
| Fast 4G | 1523 ms | 1150 ms | −373 ms (≈24.5%) |
| No throttling | 743 ms | 518 ms | −225 ms (≈30.3%) |
How?
Adds a {page-slug}-wp-admin_preload_paths filter to the wp-build page-wp-admin template so any generated admin page can register page-specific preload paths. Hooks it in the Connectors loader to preload the five paths listed in What? above (the existing hardcoded preload in the template only covers the root site fields, not the settings entity the UI actually resolves, so /wp/v2/settings is added too).
After the change, none of the connector-related REST requests fire on page load — they are served from the preload middleware.
The two remaining requests come from @wordpress/core-abilities, which Gutenberg enqueues on every admin page — out of scope here, but a candidate for similar preloading.
To achieve the following, REST API responses for 404 Not Found need to be served to the preload middleware. This is a follow up to r44123 and r44172.
Change History (11)
This ticket was mentioned in PR #11790 on WordPress/wordpress-develop by @westonruter.
5 weeks ago
#1
- Keywords has-patch has-unit-tests added
@westonruter commented on PR #11790:
5 weeks ago
#3
This ticket was mentioned in Slack in #core-test by r1k0. View the logs.
4 weeks ago
#8
@
4 weeks ago
Thanks so much for working on this enhancement, @westonruter. Given that it's a performance enhancement involving some REST API mechanics changes, and we're close to the final release, I think it may be best to ship this in the next minor.
Trac ticket: https://core.trac.wordpress.org/ticket/65215
This backports the logic in this Gutenberg PR:
Additionally, improves REST API preloading in a few ways ways:
First of all, support is added to allow a non-OK response for a preloaded request to be sent to the preloading middleware. Without this, all of the plugins on the Connectors screen would cause unconditional 404 REST API responses when accessing the page:
The data format for a preloaded request was previously two possibilities:
string: The REST API path to preload.array{ 0: string, 1?: 'OPTIONS'|'GET' }. A tuple with the first item being the REST API path, and the second item being the method.This PR modifies the tuple to add a third item for the
allowed_statuses:array{ 0: string, 1?: 'OPTIONS'|'GET', 2?: int<100, 599>|int<100, 599>[] }This allows us now to do the following:
add_filter( 'options-connectors-wp-admin_preload_paths', static function ( array $preload_paths ): array { $preload_paths[] = array( '/wp/v2/plugins/ai/ai?context=edit', 'GET', array( 200, 404 ) ); return $preload_paths; } );This allows both
200 OKresponses and404 Not Foundresponses to be served to the preload middleware. If this 3rd item of the tuple is omitted, then it retains the previous behavior of only allowing200 OK.To further support this enhancement, full PHPStan typing was added to the
rest_preload_api_request()function, and any PHPStan rule level 10 errors were addressed:2937 Function rest_preload_api_request() has parameter $memo with no value type specified in iterable type array. 🪪 missingType.iterableValue 💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type at src/wp-includes/rest-api.php:2937 2937 Function rest_preload_api_request() return type has no value type specified in iterable type array. 🪪 missingType.iterableValue 💡 See: https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type at src/wp-includes/rest-api.php:2937 2961 Parameter #1 $value of function untrailingslashit expects string, string|false given. 🪪 argument.type at src/wp-includes/rest-api.php:2961 2979 Offset 'path' might not exist on array{scheme?: string, host?: string, port?: int<0, 65535>, user?: string, pass?: string, path?: string, query?: string, fragment?: string}. 🪪 offsetAccess.notFound at src/wp-includes/rest-api.php:2979 2979 Parameter #1 $method of class WP_REST_Request constructor expects string, string|false given. 🪪 argument.type at src/wp-includes/rest-api.php:2979 2990 Parameter #1 $embed of function rest_parse_embed_param expects array|string, mixed given. 🪪 argument.type at src/wp-includes/rest-api.php:2990 2991 Parameter #1 $response of method WP_REST_Server::response_to_data() expects WP_REST_Response, mixed given. 🪪 argument.type at src/wp-includes/rest-api.php:2991 2994 Cannot access offset string on mixed. 🪪 offsetAccess.nonOffsetAccessible at src/wp-includes/rest-api.php:2994 2996 Cannot access property $headers on mixed. 🪪 property.nonObject at src/wp-includes/rest-api.php:2996 3001 Cannot access property $headers on mixed. 🪪 property.nonObject at src/wp-includes/rest-api.php:3001## Use of AI Tools
AI assistance: Yes
Tool(s): Clause Code
Model(s): Claude Opus 4.7
Used for: Research for PHPStan types.