From 48baff3cde282225b813d528c4c7e9c2b3250586 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Mon, 19 Oct 2026 21:47:39 +0100 Subject: [PATCH] Editor: Preload the entity fields and actions the editors read. The post editor now preloads the entity fields of the edited post type, which the post summary of its inspector reads, and the site editor preloads the entity actions of the edited post and of the post types its screen lists, as it already did for the entity fields. --- src/wp-includes/entity-actions.php | 30 ++++++-- src/wp-includes/entity-fields.php | 31 ++++---- tests/phpunit/tests/entity-actions.php | 77 ++++++++++++++++++- .../entity-fields/wpPreloadEntityFields.php | 9 ++- 4 files changed, 115 insertions(+), 32 deletions(-) diff --git a/src/wp-includes/entity-actions.php b/src/wp-includes/entity-actions.php index 13ec78bc03e33..426fd1d30943a 100644 --- a/src/wp-includes/entity-actions.php +++ b/src/wp-includes/entity-actions.php @@ -189,13 +189,16 @@ function _wp_add_entity_action_modules_to_editor_script( $scripts = null ) { } /** - * Preloads the actions of the post type the post editor edits. + * Preloads the actions of the post types the editors list. * - * The actions menu of the post editor reads them from the `wp/v2/entity-actions` - * route as it loads, see `useEntityActions()` in - * packages/editor/src/dataviews/entity-actions-loader.ts. The path must match the - * request of the `getEntityActionsConfig` core data resolver, see - * packages/core-data/src/resolvers.js. + * The editors read them from the `/wp/v2/entity-actions` route as they load, + * see `useEntityActions()` in + * packages/editor/src/dataviews/entity-actions-loader.ts in Gutenberg. The + * post editor reads those of the edited post in its actions menu. The site + * editor reads those of the edited post, if any, and of the post types of the + * screen it opens on, whose lists show the actions of their items. A path must + * match the request of the `getEntityActionsConfig` core data resolver, see + * packages/core-data/src/resolvers.js in Gutenberg. * * @since 7.2.0 * @@ -204,11 +207,24 @@ function _wp_add_entity_action_modules_to_editor_script( $scripts = null ) { * @return array Filtered preload paths. */ function _wp_preload_entity_actions( $paths, $context ) { + $post_types = array(); if ( 'core/edit-post' === $context->name && isset( $context->post ) ) { + $post_types[] = $context->post->post_type; + } elseif ( 'core/edit-site' === $context->name ) { + if ( isset( $context->post ) ) { + $post_types[] = $context->post->post_type; + } + $post_types = array_merge( $post_types, _wp_get_site_editor_screen_post_types() ); + } + + foreach ( array_unique( $post_types ) as $post_type ) { + if ( ! post_type_exists( $post_type ) ) { + continue; + } $paths[] = add_query_arg( array( 'kind' => 'postType', - 'name' => $context->post->post_type, + 'name' => $post_type, ), '/wp/v2/entity-actions' ); diff --git a/src/wp-includes/entity-fields.php b/src/wp-includes/entity-fields.php index 91a0547557a3e..779a32f7fe3f2 100644 --- a/src/wp-includes/entity-fields.php +++ b/src/wp-includes/entity-fields.php @@ -288,8 +288,8 @@ function _wp_get_post_type_fields_preload_paths( $post_types ) { } /** - * Returns the post types whose fields the screen of the site editor being - * loaded lists, from its `p` query arg. + * Returns the post types whose items the screen of the site editor being + * loaded lists or edits, from its `p` query arg. * * The screens are the routes in * packages/edit-site/src/components/site-editor-routes in Gutenberg: the @@ -323,16 +323,13 @@ function _wp_get_site_editor_screen_post_types() { } /** - * Preloads the fields of the post types the site editor lists. + * Preloads the fields of the post types the editors list. * - * The site editor reads them from the `/wp/v2/entity-fields` route before it - * can list the post fields, see `useFields` in - * packages/editor/src/dataviews/fields-loader/index.ts in Gutenberg: those of - * the edited post, if any, and of the post types of the screen it opens on. - * - * The post editor is left untouched: it only reads the fields in the - * DataForm-based inspector, an experiment of the Gutenberg plugin which - * preloads them on its own. + * The editors read them from the `/wp/v2/entity-fields` route, see `useFields` + * in packages/editor/src/dataviews/fields-loader/index.ts in Gutenberg. The + * post editor reads those of the edited post in the post summary of its + * inspector. The site editor reads those of the edited post, if any, and of + * the post types of the screen it opens on. * * @since 7.2.0 * @access private @@ -342,15 +339,15 @@ function _wp_get_site_editor_screen_post_types() { * @return array Filtered preload paths. */ function _wp_preload_entity_fields( $paths, $context ) { - if ( 'core/edit-site' !== $context->name ) { - return $paths; - } - $post_types = array(); - if ( isset( $context->post ) ) { + if ( 'core/edit-post' === $context->name && isset( $context->post ) ) { $post_types[] = $context->post->post_type; + } elseif ( 'core/edit-site' === $context->name ) { + if ( isset( $context->post ) ) { + $post_types[] = $context->post->post_type; + } + $post_types = array_merge( $post_types, _wp_get_site_editor_screen_post_types() ); } - $post_types = array_merge( $post_types, _wp_get_site_editor_screen_post_types() ); return array_merge( $paths, diff --git a/tests/phpunit/tests/entity-actions.php b/tests/phpunit/tests/entity-actions.php index 4625df3f4a205..5643906778bc2 100644 --- a/tests/phpunit/tests/entity-actions.php +++ b/tests/phpunit/tests/entity-actions.php @@ -42,6 +42,7 @@ public function set_up() { * the actions WordPress registers back. */ public function tear_down() { + unset( $_GET['p'] ); self::reset_registry(); parent::tear_down(); @@ -428,15 +429,83 @@ public function test_the_preloaded_actions_path_serves_the_actions() { } /** - * Only the post editor preloads the actions: the other editors have no - * post type of their own. + * The site editor preloads the actions of the post types its screen lists, + * from the `p` query arg. + * + * @ticket 66343 + * + * @dataProvider data_site_editor_screens + * + * @param string $path The `p` query arg. + * @param string[] $post_types The post types whose actions are preloaded. + */ + public function test_the_site_editor_preloads_the_actions_of_its_screen( $path, $post_types ) { + $_GET['p'] = $path; + $context = new WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) ); + + $expected = array(); + foreach ( $post_types as $post_type ) { + $expected[] = '/wp/v2/entity-actions?kind=postType&name=' . $post_type; + } + $this->assertSame( $expected, _wp_preload_entity_actions( array(), $context ), 'The actions of the post types of the screen are preloaded.' ); + } + + /** + * Data provider for test_the_site_editor_preloads_the_actions_of_its_screen(). + * + * @return array[] + */ + public static function data_site_editor_screens() { + return array( + 'pages' => array( '/page', array( 'page' ) ), + 'page' => array( '/page/12', array( 'page' ) ), + 'templates' => array( '/template', array( 'wp_template' ) ), + 'template' => array( '/wp_template/emptytheme//index', array( 'wp_template' ) ), + 'patterns' => array( '/pattern', array( 'wp_block', 'wp_template_part' ) ), + 'pattern' => array( '/wp_block/12', array( 'wp_block' ) ), + 'template part' => array( '/wp_template_part/emptytheme//header', array( 'wp_template_part' ) ), + 'root' => array( '/', array() ), + 'styles' => array( '/styles', array() ), + 'navigation' => array( '/navigation', array() ), + ); + } + + /** + * The site editor preloads the actions of the edited post, once, next to + * those of its screen. + * + * @ticket 66343 + */ + public function test_the_site_editor_preloads_the_actions_of_the_edited_post() { + $_GET['p'] = '/page'; + $context = new WP_Block_Editor_Context( + array( + 'name' => 'core/edit-site', + 'post' => self::factory()->post->create_and_get( array( 'post_type' => 'page' ) ), + ) + ); + + $this->assertSame( + array( '/wp/v2/entity-actions?kind=postType&name=page' ), + _wp_preload_entity_actions( array(), $context ), + 'The actions of pages are preloaded once.' + ); + } + + /** + * Other editors, a post editor context without a post, and a site editor + * screen that lists no posts are left untouched. * * @ticket 66343 */ public function test_other_editors_do_not_preload_the_actions() { - $context = new WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) ); + $site_editor = new WP_Block_Editor_Context( array( 'name' => 'core/edit-site' ) ); + $no_post = new WP_Block_Editor_Context( array( 'name' => 'core/edit-post' ) ); + $widgets = new WP_Block_Editor_Context( array( 'name' => 'core/edit-widgets' ) ); - $this->assertSame( array( '/wp/v2/types' ), _wp_preload_entity_actions( array( '/wp/v2/types' ), $context ), 'The paths are unchanged.' ); + $this->assertSame( array( '/wp/v2/types' ), _wp_preload_entity_actions( array( '/wp/v2/types' ), $site_editor ), 'The paths of the site editor root are unchanged.' ); + $this->assertSame( array( '/wp/v2/types' ), _wp_preload_entity_actions( array( '/wp/v2/types' ), $no_post ), 'The paths of a post editor without a post are unchanged.' ); + $this->assertSame( array( '/wp/v2/types' ), _wp_preload_entity_actions( array( '/wp/v2/types' ), $widgets ), 'The paths of the widgets editor are unchanged.' ); } /** diff --git a/tests/phpunit/tests/entity-fields/wpPreloadEntityFields.php b/tests/phpunit/tests/entity-fields/wpPreloadEntityFields.php index 064fbbf063566..58593c5727c36 100644 --- a/tests/phpunit/tests/entity-fields/wpPreloadEntityFields.php +++ b/tests/phpunit/tests/entity-fields/wpPreloadEntityFields.php @@ -32,12 +32,13 @@ public function test_the_fields_are_preloaded_on_the_block_editor_preload_paths( } /** - * The post editor does not preload the fields, whatever its `p` query arg. + * The post editor preloads the fields of the edited post type, which the + * post summary of its inspector reads, whatever its `p` query arg. * * @ticket 66229 */ - public function test_the_post_editor_does_not_preload_the_fields() { - $_GET['p'] = '/page'; + public function test_the_post_editor_preloads_the_fields_of_the_post_type() { + $_GET['p'] = '/wp_template'; $post = self::factory()->post->create_and_get( array( 'post_type' => 'page' ) ); $context = new WP_Block_Editor_Context( array( @@ -46,7 +47,7 @@ public function test_the_post_editor_does_not_preload_the_fields() { ) ); - $this->assertSame( array(), _wp_preload_entity_fields( array(), $context ) ); + $this->assertSame( array( '/wp/v2/entity-fields?kind=postType&name=page' ), _wp_preload_entity_fields( array(), $context ) ); } /**