From f7ea92875bd57b6484be9d7d08fac2b44a602449 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 14 Apr 2026 20:15:36 -0700 Subject: [PATCH 1/4] Connectors: preload REST API responses on the Connectors screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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/?context=edit` for each registered connector with a plugin file. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/experimental/connectors/load.php | 40 +++++++++++++++++++ .../templates/page-wp-admin.php.template | 12 ++++++ 2 files changed, 52 insertions(+) diff --git a/lib/experimental/connectors/load.php b/lib/experimental/connectors/load.php index 7e60135edb41c3..8dc57301243048 100644 --- a/lib/experimental/connectors/load.php +++ b/lib/experimental/connectors/load.php @@ -35,3 +35,43 @@ function _gutenberg_connectors_add_settings_menu_item(): void { } require __DIR__ . '/default-connectors.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. + * + * @access private + * + * @param array $preload_paths Paths already queued for preloading. + * @return array Paths with the Connectors-specific requests appended. + */ +function _gutenberg_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. + if ( function_exists( 'wp_get_connectors' ) ) { + 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', '_gutenberg_connectors_preload_paths' ); diff --git a/packages/wp-build/templates/page-wp-admin.php.template b/packages/wp-build/templates/page-wp-admin.php.template index 3c7210739eea4d..ccf2a51a60b8c3 100644 --- a/packages/wp-build/templates/page-wp-admin.php.template +++ b/packages/wp-build/templates/page-wp-admin.php.template @@ -93,6 +93,18 @@ function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_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 array $preload_paths Paths to preload. + */ + $preload_paths = apply_filters( '{{PAGE_SLUG}}-wp-admin_preload_paths', $preload_paths ); + // Use rest_preload_api_request to gather the preloaded data $preload_data = array_reduce( $preload_paths, From 1cadfe034efdb223135060320b9a45dd0c21507d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 14 Apr 2026 21:03:43 -0700 Subject: [PATCH 2/4] Use more specific PHP type --- lib/experimental/connectors/load.php | 4 ++-- packages/wp-build/templates/page-wp-admin.php.template | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/experimental/connectors/load.php b/lib/experimental/connectors/load.php index 8dc57301243048..ac4b1333547752 100644 --- a/lib/experimental/connectors/load.php +++ b/lib/experimental/connectors/load.php @@ -45,8 +45,8 @@ function _gutenberg_connectors_add_settings_menu_item(): void { * * @access private * - * @param array $preload_paths Paths already queued for preloading. - * @return array Paths with the Connectors-specific requests appended. + * @param string[] $preload_paths Paths already queued for preloading. + * @return string[] Paths with the Connectors-specific requests appended. */ function _gutenberg_connectors_preload_paths( array $preload_paths ): array { // getEntityRecord( 'root', 'site' ) in stage.tsx / use-connector-plugin.ts. diff --git a/packages/wp-build/templates/page-wp-admin.php.template b/packages/wp-build/templates/page-wp-admin.php.template index ccf2a51a60b8c3..fa34ca02cebbc1 100644 --- a/packages/wp-build/templates/page-wp-admin.php.template +++ b/packages/wp-build/templates/page-wp-admin.php.template @@ -101,7 +101,7 @@ function {{PREFIX}}_{{PAGE_SLUG_UNDERSCORE}}_wp_admin_preload_data() { * them here so the responses are embedded in the initial HTML rather * than fetched over the network after hydration. * - * @param array $preload_paths Paths to preload. + * @param string[] $preload_paths Paths to preload. */ $preload_paths = apply_filters( '{{PAGE_SLUG}}-wp-admin_preload_paths', $preload_paths ); From f3269d20100043c2cc68d3102870df79f66ef5c4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 8 May 2026 09:21:38 -0700 Subject: [PATCH 3/4] Remove unnecesary wp_get_connectors() function exists check Co-authored-by: justlevine --- lib/experimental/connectors/load.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/experimental/connectors/load.php b/lib/experimental/connectors/load.php index ac4b1333547752..8cb4e4f3299379 100644 --- a/lib/experimental/connectors/load.php +++ b/lib/experimental/connectors/load.php @@ -60,16 +60,14 @@ function _gutenberg_connectors_preload_paths( array $preload_paths ): array { $preload_paths[] = '/wp/v2/plugins/ai/ai?context=edit'; // getEntityRecord( 'root', 'plugin', ) per connector in use-connector-plugin.ts. - if ( function_exists( 'wp_get_connectors' ) ) { - 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'; + 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; From faa91e5c5dcf07deab17befc69e59f73f20171fa Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 10 May 2026 17:09:00 -0700 Subject: [PATCH 4/4] Add backport changelog --- backport-changelog/7.0/11790.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 backport-changelog/7.0/11790.md diff --git a/backport-changelog/7.0/11790.md b/backport-changelog/7.0/11790.md new file mode 100644 index 00000000000000..1ef4cb50e402d6 --- /dev/null +++ b/backport-changelog/7.0/11790.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/11790 + +* https://github.com/WordPress/gutenberg/pull/77353