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 diff --git a/lib/compat/wordpress-7.0/connectors.php b/lib/compat/wordpress-7.0/connectors.php index b37fd5b71cb73d..0e0d858e103585 100644 --- a/lib/compat/wordpress-7.0/connectors.php +++ b/lib/compat/wordpress-7.0/connectors.php @@ -235,3 +235,41 @@ function _gutenberg_connectors_add_settings_menu_item(): void { 1 ); } + +/** + * 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 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. + $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', '_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 e8bef9d71982ff..6d987a14693582 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 string[] $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,