Make WordPress Core

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: westonruter's profile westonruter Owned by: westonruter's profile westonruter
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 westonruter)

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

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:

https://github.com/user-attachments/assets/8a94aca9-07da-4193-9acb-d6f1c1233846

The data format for a preloaded request was previously two possibilities:

  1. string: The REST API path to preload.
  2. 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 OK responses and 404 Not Found responses to be served to the preload middleware. If this 3rd item of the tuple is omitted, then it retains the previous behavior of only allowing 200 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.

#2 @westonruter
5 weeks ago

  • Focuses rest-api added

@westonruter commented on PR #11790:


5 weeks ago
#3

@pento As you've been around lately and you introduced rest_preload_api_request() in r44123 and r44172, maybe you'd have review input as well.

#4 @westonruter
5 weeks ago

cc @chubes4 as this relates to #65206

#5 @westonruter
5 weeks ago

  • Description modified (diff)

#6 @JeffPaul
5 weeks ago

  • Keywords connectors added

This ticket was mentioned in Slack in #core-test by r1k0. View the logs.


4 weeks ago

#8 @jorgefilipecosta
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.

This ticket was mentioned in Slack in #core by audrasjb. View the logs.


4 weeks ago

#10 @audrasjb
4 weeks ago

  • Milestone changed from 7.0 to 7.0.1

As per today's bug scrub: Moving to 7.0.1 as we're too late in the release cycle.

#11 @audrasjb
4 weeks ago

Removing trunk version as this is not going to be shipped with WP 7.0 but in the next releases.

Note: See TracTickets for help on using tickets.