Skip to content

Connectors: preload REST API responses on the Connectors screen#77353

Open
westonruter wants to merge 5 commits into
trunkfrom
fix/connectors-preload-rest-requests
Open

Connectors: preload REST API responses on the Connectors screen#77353
westonruter wants to merge 5 commits into
trunkfrom
fix/connectors-preload-rest-requests

Conversation

@westonruter

@westonruter westonruter commented Apr 15, 2026

Copy link
Copy Markdown
Member

What?

The Connectors screen (options-general.php?page=options-connectors-wp-admin) fires several REST API requests after hydration, delaying the Largest Contentful Paint:

HTTP requests before

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:

HTTP requests after

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.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Opus 4.6
Used for: Investigation, implementation, performance benchmarking, PR description composition

westonruter and others added 2 commits April 14, 2026 20:15
The Connectors screen (options-connectors-wp-admin) previously fired
several REST API requests after hydration — site settings, a plugin
capability check, and one plugin record per registered connector —
delaying first paint.

Add 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. Hook it in the Connectors loader to
preload `/wp/v2/settings`, `OPTIONS /wp/v2/plugins`,
`/wp/v2/plugins/ai/ai?context=edit` (for the AI plugin callout),
and `/wp/v2/plugins/<basename>?context=edit` for each registered
connector with a plugin file.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@westonruter westonruter added [Type] Performance Related to performance efforts [Feature] Connectors screen Tracks connectors screen related tasks labels Apr 15, 2026
@github-project-automation github-project-automation Bot moved this to 🔎 Needs Review in WordPress 7.0 Editor Tasks Apr 15, 2026
@github-actions

github-actions Bot commented Apr 15, 2026

Copy link
Copy Markdown

Flaky tests detected in 2d6811f.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/27515021732
📝 Reported issues:

@gziolo gziolo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested, but these changes look solid to me.

@github-actions

github-actions Bot commented Apr 16, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: westonruter <westonruter@git.wordpress.org>
Co-authored-by: gziolo <gziolo@git.wordpress.org>
Co-authored-by: justlevine <justlevine@git.wordpress.org>
Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org>
Co-authored-by: t-hamano <wildworks@git.wordpress.org>
Co-authored-by: ellatrix <ellatrix@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@gziolo gziolo added the Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta label Apr 16, 2026
Comment thread lib/experimental/connectors/load.php Outdated
$preload_paths[] = '/wp/v2/plugins/ai/ai?context=edit';

// getEntityRecord( 'root', 'plugin', <basename> ) per connector in use-connector-plugin.ts.
if ( function_exists( 'wp_get_connectors' ) ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7.0 (and wp_get_connectors() ) is a pre-requesite for the AI plugin, and assumedly without we also don't care about prefetching wp/v2/settings or OPTIONS wp/v2/plugins.

Would it make sense to just early return at the top of the method instead of partially nesting this logic?

That said, if this is just about PHPStan (and the options-connectors...* filter won't even trigger otherwise ), then I'd just drop the always-true function_exists() and add a rule scoped // @phpstan-ignore <type> (<reason>)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good observation. I opted to remove the function_exists() check entirely in f3269d2 because this options-connectors-wp-admin_preload_paths filter only applies on the connectors admin page which only exists in 7.0 anyway.

Co-authored-by: justlevine <justlevine@git.wordpress.org>

@justlevine justlevine left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@jorgefilipecosta jorgefilipecosta left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change looks good to me, I verified the preloaded endpoint payloads are passed to the client and on the smoke tests I did things look ok.
This PR needs the backport changelog entry and the corresponding core ticket/PR.

@westonruter

Copy link
Copy Markdown
Member Author

@jorgefilipecosta In testing this further, it seems the REST API preloading is not sufficient. In particular, it does not support preloading 404 responses. This means that it still does a REST API request for any plugin that has not been installed. If none of the plugins are installed, then there are always four 404 responses to the REST API:

image

I've addressed this in the core PR: WordPress/wordpress-develop#11790

Comment thread lib/experimental/connectors/load.php Outdated

// 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';

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With WordPress/wordpress-develop#11790 this could become as follows to serve the 404 responses to the preload middleware:

$preload_paths[] = array( '/wp/v2/plugins/ai/ai?context=edit', 'GET', array( 200, 404 ) );

However, it would not be compatible with WP 6.9.

Comment thread lib/experimental/connectors/load.php Outdated
// 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';

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto above, but it would not be compatible with WP 6.9:

$preload_paths[] = array( '/wp/v2/plugins/' . $basename . '?context=edit', 'GET', array( 200, 404 ) );

@westonruter

Copy link
Copy Markdown
Member Author

This PR needs the backport changelog entry and the corresponding core ticket/PR.

See f3269d2 and WordPress/wordpress-develop#11790

westonruter added a commit to westonruter/wordpress-develop that referenced this pull request May 11, 2026
@ellatrix

Copy link
Copy Markdown
Member

This was punted, so moving to next minor.

@ellatrix ellatrix added Backport to WP Minor Release Pull request that needs to be backported to a WordPress minor release and removed Backport to WP 7.0 Beta/RC Pull request that needs to be backported to the WordPress major release that's currently in beta labels May 19, 2026
@t-hamano t-hamano moved this from 🎯 Needs Core Commit to 🐛 Punted to 7.0.1 in WordPress 7.0 Editor Tasks May 24, 2026
@t-hamano t-hamano moved this from 🐛 Punted to 7.0.1 to 🎯 Needs Core Commit in WordPress 7.0 Editor Tasks May 24, 2026

@t-hamano t-hamano left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move the code added to lib/experimental/connectors/load.php to lib/compat/wordpress-7.0/connectors.php to move this PR forward? lib/experimental/connectors no longer exists.

…7.0/connectors.php

The lib/experimental/connectors directory no longer exists on trunk; its
contents moved to lib/compat/wordpress-7.0/. Relocate the
_gutenberg_connectors_preload_paths() function and its filter from the
deleted lib/experimental/connectors/load.php into
lib/compat/wordpress-7.0/connectors.php to resolve the merge conflict.

Co-authored-by: t-hamano <wildworks@git.wordpress.org>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@westonruter

Copy link
Copy Markdown
Member Author

@t-hamano I've resolved the conflicts:

trunk This PR
image image

Note the non-precached 404 responses are addressed in WordPress/wordpress-develop#11790, within which zero REST API requests appear when accessing the Connectors screen.

* 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.
*

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first in keeping with #78826 it seems this is needed:

Suggested change
*
*
* @since 7.0.1
*

However, since this filter gets generated for every templated admin page, the docs would then incorrectly indicate 7.0.1 when a new admin page is added in a later release. So it seems this should be left out. This is a docs issue for these new admin routes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backport to WP Minor Release Pull request that needs to be backported to a WordPress minor release [Feature] Connectors screen Tracks connectors screen related tasks [Type] Performance Related to performance efforts

Projects

Status: 🎯 Needs Core Commit

Development

Successfully merging this pull request may close these issues.

6 participants