diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 16afab80fcd58..55053f4c2193d 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -841,7 +841,7 @@ add_filter( 'rest_pre_insert_wp_template_part', 'inject_ignored_hooked_blocks_metadata_attributes' ); // View Config API. -foreach ( array( 'page', 'wp_block', 'wp_template_part', 'wp_template' ) as $post_type ) { +foreach ( array( 'page', 'wp_block', 'wp_template_part', 'wp_template', 'attachment' ) as $post_type ) { // Base definitions run before the default priority, so third-party // callbacks registered at the default compose on top of them // regardless of registration order. diff --git a/src/wp-includes/view-config.php b/src/wp-includes/view-config.php index bf10553500907..ebf3dd3dc5fc0 100644 --- a/src/wp-includes/view-config.php +++ b/src/wp-includes/view-config.php @@ -771,6 +771,61 @@ function _wp_get_entity_view_config_posttype_wp_template( $data ) { return $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 wp_get_entity_view_config() are left untouched. + * + * @since 7.2.0 + * + * @param WP_View_Config_Data $data The view configuration container for the entity. + * @return WP_View_Config_Data The updated view configuration container. + */ +function _wp_get_entity_view_config_posttype_attachment( $data ) { + $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 + ); +} + /** * Provides the view configuration for the `root`/`site` entity. * diff --git a/tests/phpunit/tests/rest-api/rest-view-config-controller.php b/tests/phpunit/tests/rest-api/rest-view-config-controller.php index c6a7ed86b816d..833f4e598a138 100644 --- a/tests/phpunit/tests/rest-api/rest-view-config-controller.php +++ b/tests/phpunit/tests/rest-api/rest-view-config-controller.php @@ -302,6 +302,34 @@ public function test_get_items_matches_underlying_config() { $this->assertSame( $config['form'], $data['form'] ); } + /** + * The `attachment` post type provides the form of the media editor. + * + * @ticket 66229 + * + * @covers ::get_items + */ + public function test_get_items_attachment_form() { + wp_set_current_user( self::$editor_id ); + + $response = $this->dispatch_request( 'postType', 'attachment' ); + $this->assertSame( 200, $response->get_status(), 'The request succeeds.' ); + + $data = json_decode( wp_json_encode( $response->get_data() ), true ); + + $this->assertSame( array( 'type' => 'panel' ), $data['form']['layout'], 'The form uses a panel layout.' ); + $this->assertSame( + array( 'title', 'alt_text', 'caption', 'description', 'date', 'author', 'filename', 'mime_type', 'filesize', 'media_dimensions', 'attached_to' ), + array_map( + static function ( $field ) { + return is_array( $field ) ? $field['id'] : $field; + }, + $data['form']['fields'] + ), + 'The form lists the media editor fields in order.' + ); + } + /** * The `root`/`site` entity provides the form of the site identity screen. * diff --git a/tests/phpunit/tests/view-config.php b/tests/phpunit/tests/view-config.php index e30e7820368c6..28966f8c33f13 100644 --- a/tests/phpunit/tests/view-config.php +++ b/tests/phpunit/tests/view-config.php @@ -139,6 +139,84 @@ public function data_default_form_post_types() { ); } + /** + * Post types with their own form do not receive the default form groups. + * + * @ticket 66229 + * + * @dataProvider data_post_types_with_own_form + * + * @param string $post_type The post type. + */ + public function test_own_form_post_types_do_not_get_default_groups( $post_type ) { + $config = wp_get_entity_view_config( 'postType', $post_type ); + + $this->assertNull( $this->get_form_field( $config, 'status' ), 'The `status` group is absent.' ); + $this->assertNull( $this->get_form_field( $config, 'discussion' ), 'The `discussion` group is absent.' ); + } + + /** + * Data provider. + * + * @return array[] + */ + public function data_post_types_with_own_form() { + return array( + 'attachment' => array( 'attachment' ), + 'wp_block' => array( 'wp_block' ), + 'wp_template' => array( 'wp_template' ), + 'wp_template_part' => array( 'wp_template_part' ), + ); + } + + /** + * The `attachment` post type provides the form of the media editor: the + * editable fields in a regular layout, then the rest in panels. + * + * @ticket 66229 + * + * @covers ::_wp_get_entity_view_config_posttype_attachment + */ + public function test_attachment_form() { + $config = wp_get_entity_view_config( 'postType', 'attachment' ); + + $this->assertSame( array( 'type' => 'panel' ), $config['form']['layout'], 'The form uses a panel layout.' ); + + $regular_layout = array( + 'type' => 'regular', + 'labelPosition' => 'top', + ); + $this->assertSame( + 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', + ), + $config['form']['fields'], + 'The form lists the media editor fields in order.' + ); + } + /** * The default configuration exposes the documented shape for an unknown entity. */