Repository navigation
Editor: Read the entity fields from the server #84700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
ebb589d
Core data: Add a private `getFieldsConfig` selector
oandregal 50087a1
Editor: Add `useFields` to read the fields from the server
oandregal 0e1b089
Entity fields API: Preload the fields of the screens that read them
oandregal 684c0b6
Editor: Read the post summary fields with `useFields`
oandregal ed23666
Editor: Read the post fields from the server in `usePostFields`
oandregal f3e69c1
E2E: Exercise the Entity fields API on the Pages list
oandregal 2940400
Changelogs: Note that the screens read their fields from the server
oandregal 64dc0f0
Editor: Register only the attachment fields on the client
oandregal 913eb55
Editor: Remove the unused content preview field
oandregal d6eba04
Media editor: Lay out the fields with a fixed or given form
oandregal a32f5be
View config: Provide the form of the media editor for attachments
oandregal 330d2a3
Entity fields API: Preload the attachment fields of the media editor
oandregal 41c0ab2
Editor: Resolve the fields of an entity from the server
oandregal 7ad8570
Media editor: Lay out the attachment fields with the server form
oandregal 2cb3ae3
E2E: Stop exercising fields registered on the client
oandregal b4fd7de
Changelogs: Note the deprecation of the client field registration
oandregal a8e7eee
Entity fields API: Preload the attachment form of the media editor route
oandregal 9f434f2
Editor: Show a snackbar when the post fields fail to load
oandregal 3cc0ce5
Fix error notice component syntax
oandregal 7685cce
Deprecations: List the client field registration without a removal ve…
oandregal e3a5518
Entity fields API: Move the route preloading to the experimental pages
oandregal 2c601d5
DataForm inspector: Call the entity fields preload helper directly
oandregal 7992acf
Editor: Indent the fields error notice of the post summary
oandregal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| <?php | ||
| /** | ||
| * Preload paths for the entity fields. | ||
| * | ||
| * @package gutenberg | ||
| */ | ||
|
|
||
| /** | ||
| * Returns the paths that serve the fields of the given post types, skipping | ||
| * the post types that are not registered. | ||
| * | ||
| * A path must match the request of the `getFieldsConfig` core data resolver, | ||
| * see packages/core-data/src/resolvers.js. | ||
| * | ||
| * @param string[] $post_types The post types. | ||
| * @return string[] One path of the `wp/v2/entity-fields` route per post type, in the | ||
| * order the post types are given, without duplicates. | ||
| */ | ||
| function _gutenberg_get_post_type_fields_preload_paths( $post_types ) { | ||
| $paths = array(); | ||
| foreach ( array_unique( $post_types ) as $post_type ) { | ||
| if ( ! post_type_exists( $post_type ) ) { | ||
| continue; | ||
| } | ||
| $paths[] = add_query_arg( | ||
| array( | ||
| 'kind' => 'postType', | ||
| 'name' => $post_type, | ||
| ), | ||
| '/wp/v2/entity-fields' | ||
| ); | ||
| } | ||
|
|
||
| return $paths; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the post types whose fields the screen of the site editor being | ||
| * loaded lists, from its `p` query arg. | ||
| * | ||
| * The screens are the routes in | ||
| * packages/edit-site/src/components/site-editor-routes: the lists and the | ||
| * editors of pages, templates, patterns, and template parts. The patterns | ||
| * screen lists both patterns and template parts. | ||
| * | ||
| * @return string[] The post types, empty for any other screen. | ||
| */ | ||
| function _gutenberg_get_site_editor_screen_post_types() { | ||
| // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only picks what to preload. | ||
| $path = isset( $_GET['p'] ) && is_string( $_GET['p'] ) ? sanitize_text_field( wp_unslash( $_GET['p'] ) ) : ''; | ||
| $segments = explode( '/', trim( $path, '/' ) ); | ||
|
|
||
| switch ( $segments[0] ) { | ||
| case 'page': | ||
| return array( 'page' ); | ||
| case 'template': | ||
| case 'wp_template': | ||
| return array( 'wp_template' ); | ||
| case 'pattern': | ||
| return array( 'wp_block', 'wp_template_part' ); | ||
| case 'wp_block': | ||
| return array( 'wp_block' ); | ||
| case 'wp_template_part': | ||
| return array( 'wp_template_part' ); | ||
| } | ||
| return array(); | ||
| } | ||
|
|
||
| /** | ||
| * Preloads the fields of the post types the site editor lists. | ||
| * | ||
| * 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: those of the edited | ||
| * post, if any, and of the post types of the screen it opens on. | ||
| * | ||
| * The post editor only reads them in the post summary of the DataForm-based | ||
| * inspector, which is an experiment that preloads them on its own, see | ||
| * lib/experimental/dataform-inspector-preload.php. | ||
| * | ||
| * @param array $paths REST API paths to preload. | ||
| * @param WP_Block_Editor_Context $context Block editor context. | ||
| * @return array Filtered preload paths. | ||
| */ | ||
| function _gutenberg_preload_entity_fields( $paths, $context ) { | ||
| if ( 'core/edit-site' !== $context->name ) { | ||
| return $paths; | ||
| } | ||
|
|
||
| $post_types = array(); | ||
| if ( isset( $context->post ) ) { | ||
| $post_types[] = $context->post->post_type; | ||
| } | ||
| $post_types = array_merge( $post_types, _gutenberg_get_site_editor_screen_post_types() ); | ||
|
|
||
| return array_merge( | ||
| $paths, | ||
| _gutenberg_get_post_type_fields_preload_paths( $post_types ) | ||
| ); | ||
| } | ||
| add_filter( 'block_editor_rest_api_preload_paths', '_gutenberg_preload_entity_fields', 10, 2 ); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,13 +159,69 @@ function _gutenberg_get_entity_view_config_root_site( $data ) { | |
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Provides the view configuration for the `attachment` post type. | ||
| * | ||
| * An attachment is edited through a form (the media editor) that shares | ||
| * nothing with the default post type form, so the `form` is replaced: the | ||
| * editable fields first, in a regular layout, then the metadata and the file | ||
| * information, in panels. The generic `default_view`, `default_layouts`, and | ||
| * `view_list` built by gutenberg_get_entity_view_config() are left untouched. | ||
| * | ||
| * Core has no callback for this entity, so this is a base definition rather | ||
| * than a layer on top of one. | ||
| * | ||
| * @param Gutenberg_View_Config_Data $data The view configuration container for the entity. | ||
| * @return Gutenberg_View_Config_Data The updated view configuration container. | ||
| */ | ||
| function _gutenberg_get_entity_view_config_posttype_attachment( $data ) { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This config is used for the post_type/attachment. See media-form at packages/media-editor/src/components/media-form/index.tsx. |
||
| $regular_layout = array( | ||
| 'type' => 'regular', | ||
| 'labelPosition' => 'top', | ||
| ); | ||
|
|
||
| return $data->set( | ||
| array( | ||
| 'form' => array( | ||
| 'layout' => array( 'type' => 'panel' ), | ||
| 'fields' => array( | ||
| array( | ||
| 'id' => 'title', | ||
| 'layout' => $regular_layout, | ||
| ), | ||
| array( | ||
| 'id' => 'alt_text', | ||
| 'layout' => $regular_layout, | ||
| ), | ||
| array( | ||
| 'id' => 'caption', | ||
| 'layout' => $regular_layout, | ||
| ), | ||
| array( | ||
| 'id' => 'description', | ||
| 'layout' => $regular_layout, | ||
| ), | ||
| 'date', | ||
| 'author', | ||
| 'filename', | ||
| 'mime_type', | ||
| 'filesize', | ||
| 'media_dimensions', | ||
| 'attached_to', | ||
| ), | ||
| ), | ||
| ), | ||
| 1 | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Post types whose base definition provides its own `form`, without the | ||
| * `status` and `discussion` groups of the default post type form. | ||
| * | ||
| * @var string[] | ||
| */ | ||
| const GUTENBERG_VIEW_CONFIG_POST_TYPES_WITH_OWN_FORM = array( 'wp_block', 'wp_template', 'wp_template_part' ); | ||
| const GUTENBERG_VIEW_CONFIG_POST_TYPES_WITH_OWN_FORM = array( 'attachment', 'wp_block', 'wp_template', 'wp_template_part' ); | ||
|
|
||
| /** | ||
| * Makes the panel summary of the `status` and `discussion` groups explicit in | ||
|
|
@@ -244,6 +300,12 @@ function gutenberg_register_entity_view_config_filters_7_2() { | |
| 5, | ||
| 1 | ||
| ); | ||
| add_filter( | ||
| gutenberg_get_entity_view_config_hook_name( 'postType', 'attachment' ), | ||
| '_gutenberg_get_entity_view_config_posttype_attachment', | ||
| 5, | ||
| 1 | ||
| ); | ||
| add_filter( | ||
| gutenberg_get_entity_view_config_hook_name( 'root', 'site' ), | ||
| '_gutenberg_get_entity_view_config_root_site', | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| <?php | ||
| /** | ||
| * Preload paths for the entity fields of the routes of the experimental pages: | ||
| * the extensible site editor and the media editor. | ||
| * | ||
| * The paths themselves come from `_gutenberg_get_post_type_fields_preload_paths()`, | ||
| * see lib/compat/wordpress-7.2/preload.php. | ||
| * | ||
| * @package gutenberg | ||
| */ | ||
|
|
||
| /** | ||
| * Returns the post types whose fields the route being loaded lists or edits, | ||
| * from its `p` query arg. | ||
| * | ||
| * The routes are the entry points in /routes whose screens make up the | ||
| * extensible site editor and the media editor page. A route that shows no | ||
| * post fields, such as `/styles`, contributes no post type. The paths without | ||
| * a screen of their own (`/templates`, `/patterns`, `/types/<post type>`, …) | ||
| * redirect client-side to their list route, and are what the menu items of | ||
| * the page link to, so they preload what the list they land on needs. | ||
| * | ||
| * @return string[] The post types, empty for any other route. | ||
| */ | ||
| function _gutenberg_get_route_post_types() { | ||
| // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only picks what to preload. | ||
| $path = isset( $_GET['p'] ) && is_string( $_GET['p'] ) ? sanitize_text_field( wp_unslash( $_GET['p'] ) ) : ''; | ||
| // The router keeps the search of the route in `p`, as in `/types/page/list/all?page=2`. | ||
| $path = explode( '?', $path )[0]; | ||
| $segments = explode( '/', trim( $path, '/' ) ); | ||
|
|
||
| switch ( $segments[0] ) { | ||
| case 'types': | ||
| // `/types/<post type>` and its `list`, `edit`, and `new` routes. | ||
| $post_type = isset( $segments[1] ) ? sanitize_key( $segments[1] ) : ''; | ||
| return '' === $post_type ? array() : array( $post_type ); | ||
| case 'templates': | ||
| return array( 'wp_template' ); | ||
| case 'template-parts': | ||
| return array( 'wp_template_part' ); | ||
| case 'patterns': | ||
| return array( 'wp_block' ); | ||
| case 'navigation': | ||
| return array( 'wp_navigation' ); | ||
| case 'media-editor': | ||
| return array( 'attachment' ); | ||
| } | ||
| return array(); | ||
| } | ||
|
|
||
| /** | ||
| * Returns the paths of the view config the route being loaded resolves before | ||
| * it renders. | ||
| * | ||
| * Only the media editor route does: its loader resolves the `form` of the | ||
| * attachment view config, see routes/media-editor/route.ts. It is the only | ||
| * route whose post type is `attachment`. A path must match the request of the | ||
| * `getViewConfig` core data resolver, `_fields` included. | ||
| * | ||
| * @return string[] The paths of the `wp/v2/view-config` route, empty for any other route. | ||
| */ | ||
| function _gutenberg_get_route_view_config_preload_paths() { | ||
| if ( array( 'attachment' ) !== _gutenberg_get_route_post_types() ) { | ||
| return array(); | ||
| } | ||
|
|
||
| return array( '/wp/v2/view-config?kind=postType&name=attachment&_fields=form' ); | ||
| } | ||
|
|
||
| /** | ||
| * Preloads the fields of the post types the route being loaded lists or edits, | ||
| * and the view config it resolves before it renders. | ||
| * | ||
| * A page booted by `@wordpress/boot` prints a preloading middleware of its own | ||
| * with the paths every one of its routes needs, see the `page.php` template of | ||
| * `@wordpress/build`. Which fields a screen needs depends on the route, which | ||
| * that list cannot tell, so they are preloaded here as a second middleware: | ||
| * `api-fetch` asks each middleware in turn, and one that does not hold the | ||
| * path of a request passes it on. | ||
| * | ||
| * The `init` action of a page fires before the page prints its own preloaded | ||
| * data, and `wp-api-fetch` is registered by then, so the inline script is | ||
| * attached to the handle and printed along with it. | ||
| */ | ||
| function _gutenberg_preload_route_entity_fields() { | ||
| $paths = array_merge( | ||
| _gutenberg_get_post_type_fields_preload_paths( _gutenberg_get_route_post_types() ), | ||
| _gutenberg_get_route_view_config_preload_paths() | ||
| ); | ||
| if ( empty( $paths ) ) { | ||
| return; | ||
| } | ||
|
|
||
| // `rest_preload_api_request()` only keeps the responses that succeeded, so | ||
| // an entity whose fields the current user cannot read leaves the request to the | ||
| // client rather than preloading the error. | ||
| $preload_data = array_reduce( $paths, 'rest_preload_api_request', array() ); | ||
| if ( empty( $preload_data ) ) { | ||
| return; | ||
| } | ||
|
|
||
| wp_add_inline_script( | ||
| 'wp-api-fetch', | ||
| sprintf( | ||
| 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );', | ||
| wp_json_encode( $preload_data ) | ||
| ), | ||
| 'after' | ||
| ); | ||
| } | ||
| add_action( 'site-editor-v2_init', '_gutenberg_preload_route_entity_fields' ); | ||
| add_action( 'media-editor-wp-admin_init', '_gutenberg_preload_route_entity_fields' ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.