From bb6c5dbb8d613cb450d3f73983ecca27a75b003b Mon Sep 17 00:00:00 2001 From: Timothy Jacobs Date: Sun, 31 Oct 2021 23:15:10 +0000 Subject: [PATCH] REST API: Support custom namespaces for custom post types. While a custom post type can define a custom route by using the `rest_base` argument, a namespace of `wp/v2` was assumed. This commit introduces support for a `rest_namespace` argument. A new `rest_get_route_for_post_type_items` function has been introduced and the `rest_get_route_for_post` function updated to facilitate getting the correct route for custom post types. While the WordPress Core Block Editor bootstrap code has been updated to use these API functions, for maximum compatibility sticking with the default `wp/v2` namespace is recommended until the API functions see wider use. Props spacedmonkey, swissspidy. Fixes #53656. git-svn-id: https://develop.svn.wordpress.org/trunk@51962 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/edit-form-blocks.php | 10 ++-- src/wp-admin/widgets-form-blocks.php | 2 +- src/wp-includes/class-wp-post-type.php | 14 +++++ src/wp-includes/post.php | 1 + src/wp-includes/rest-api.php | 51 +++++++++++++------ .../rest-api/class-wp-rest-server.php | 2 +- .../class-wp-rest-autosaves-controller.php | 2 +- ...class-wp-rest-post-statuses-controller.php | 5 +- .../class-wp-rest-post-types-controller.php | 37 +++++++++----- .../class-wp-rest-posts-controller.php | 6 +-- .../class-wp-rest-revisions-controller.php | 2 +- .../class-wp-rest-templates-controller.php | 2 +- .../class-wp-rest-terms-controller.php | 7 ++- tests/phpunit/tests/rest-api.php | 45 +++++++++++++++- .../rest-api/rest-post-types-controller.php | 21 +++++++- tests/qunit/fixtures/wp-api-generated.js | 8 ++- 16 files changed, 165 insertions(+), 50 deletions(-) diff --git a/src/wp-admin/edit-form-blocks.php b/src/wp-admin/edit-form-blocks.php index 7e335fa49b..969d138ecb 100644 --- a/src/wp-admin/edit-form-blocks.php +++ b/src/wp-admin/edit-form-blocks.php @@ -49,7 +49,7 @@ add_filter( 'screen_options_show_screen', '__return_false' ); wp_enqueue_script( 'heartbeat' ); wp_enqueue_script( 'wp-edit-post' ); -$rest_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; +$rest_path = rest_get_route_for_post( $post ); // Preload common data. $preload_paths = array( @@ -57,12 +57,12 @@ $preload_paths = array( '/wp/v2/types?context=edit', '/wp/v2/taxonomies?per_page=-1&context=edit', '/wp/v2/themes?status=active', - sprintf( '/wp/v2/%s/%s?context=edit', $rest_base, $post->ID ), + add_query_arg( 'context', 'edit', $rest_path ), sprintf( '/wp/v2/types/%s?context=edit', $post_type ), sprintf( '/wp/v2/users/me?post_type=%s&context=edit', $post_type ), - array( '/wp/v2/media', 'OPTIONS' ), - array( '/wp/v2/blocks', 'OPTIONS' ), - sprintf( '/wp/v2/%s/%d/autosaves?context=edit', $rest_base, $post->ID ), + array( rest_get_route_for_post_type_items( 'attachment' ), 'OPTIONS' ), + array( rest_get_route_for_post_type_items( 'wp_block' ), 'OPTIONS' ), + sprintf( '%s/autosaves?context=edit', $rest_path ), ); block_editor_rest_api_preload( $preload_paths, $block_editor_context ); diff --git a/src/wp-admin/widgets-form-blocks.php b/src/wp-admin/widgets-form-blocks.php index 95908e1e9e..563bbf2a69 100644 --- a/src/wp-admin/widgets-form-blocks.php +++ b/src/wp-admin/widgets-form-blocks.php @@ -18,7 +18,7 @@ $current_screen->is_block_editor( true ); $block_editor_context = new WP_Block_Editor_Context(); $preload_paths = array( - array( '/wp/v2/media', 'OPTIONS' ), + array( rest_get_route_for_post_type_items( 'attachment' ), 'OPTIONS' ), '/wp/v2/sidebars?context=edit&per_page=-1', '/wp/v2/widgets?context=edit&per_page=-1&_embed=about', ); diff --git a/src/wp-includes/class-wp-post-type.php b/src/wp-includes/class-wp-post-type.php index 43e8a61514..e284994401 100644 --- a/src/wp-includes/class-wp-post-type.php +++ b/src/wp-includes/class-wp-post-type.php @@ -358,6 +358,14 @@ final class WP_Post_Type { */ public $rest_base; + /** + * The namespace for this post type's REST API endpoints. + * + * @since 5.9 + * @var string|bool $rest_namespace + */ + public $rest_namespace; + /** * The controller for this post type's REST API endpoints. * @@ -452,6 +460,7 @@ final class WP_Post_Type { 'delete_with_user' => null, 'show_in_rest' => false, 'rest_base' => false, + 'rest_namespace' => false, 'rest_controller_class' => false, 'template' => array(), 'template_lock' => false, @@ -473,6 +482,11 @@ final class WP_Post_Type { $args['show_ui'] = $args['public']; } + // If not set, default rest_namespace to wp/v2 if show_in_rest is true. + if ( false === $args['rest_namespace'] && ! empty( $args['show_in_rest'] ) ) { + $args['rest_namespace'] = 'wp/v2'; + } + // If not set, default to the setting for 'show_ui'. if ( null === $args['show_in_menu'] || ! $args['show_ui'] ) { $args['show_in_menu'] = $args['show_ui']; diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index fb90f626f4..5cd73d1bd8 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -1418,6 +1418,7 @@ function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) * @type bool $show_in_rest Whether to include the post type in the REST API. Set this to true * for the post type to be available in the block editor. * @type string $rest_base To change the base URL of REST API route. Default is $post_type. + * @type string $rest_namespace To change the namespace URL of REST API route. Default is wp/v2. * @type string $rest_controller_class REST API controller class name. Default is 'WP_REST_Posts_Controller'. * @type int $menu_position The position in the menu order the post type should appear. To work, * $show_in_menu must be true. Default null (at the bottom). diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index 3d89f16009..a30a246d95 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -3049,24 +3049,12 @@ function rest_get_route_for_post( $post ) { return ''; } - $post_type = get_post_type_object( $post->post_type ); - if ( ! $post_type ) { + $post_type_route = rest_get_route_for_post_type_items( $post->post_type ); + if ( ! $post_type_route ) { return ''; } - $controller = $post_type->get_rest_controller(); - if ( ! $controller ) { - return ''; - } - - $route = ''; - - // The only two controllers that we can detect are the Attachments and Posts controllers. - if ( in_array( get_class( $controller ), array( 'WP_REST_Attachments_Controller', 'WP_REST_Posts_Controller' ), true ) ) { - $namespace = 'wp/v2'; - $rest_base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; - $route = sprintf( '/%s/%s/%d', $namespace, $rest_base, $post->ID ); - } + $route = sprintf( '%s/%d', $post_type_route, $post->ID ); /** * Filters the REST API route for a post. @@ -3079,6 +3067,39 @@ function rest_get_route_for_post( $post ) { return apply_filters( 'rest_route_for_post', $route, $post ); } +/** + * Gets the REST API route for a post type. + * + * @since 5.9.0 + * + * @param string $post_type The name of a registered post type. + * @return string The route path with a leading slash for the given post type, or an empty string if there is not a route. + */ +function rest_get_route_for_post_type_items( $post_type ) { + $post_type = get_post_type_object( $post_type ); + if ( ! $post_type ) { + return ''; + } + + if ( ! $post_type->show_in_rest ) { + return ''; + } + + $namespace = ! empty( $post_type->rest_namespace ) ? $post_type->rest_namespace : 'wp/v2'; + $rest_base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; + $route = sprintf( '/%s/%s', $namespace, $rest_base ); + + /** + * Filters the REST API route for a post type. + * + * @since 5.9.0 + * + * @param string $route The route path. + * @param WP_Post_Type $post_type The post type object. + */ + return apply_filters( 'rest_route_for_post_type_items', $route, $post_type ); +} + /** * Gets the REST API route for a term. * diff --git a/src/wp-includes/rest-api/class-wp-rest-server.php b/src/wp-includes/rest-api/class-wp-rest-server.php index e2999f7c82..3585aa7656 100644 --- a/src/wp-includes/rest-api/class-wp-rest-server.php +++ b/src/wp-includes/rest-api/class-wp-rest-server.php @@ -1288,7 +1288,7 @@ class WP_REST_Server { if ( $site_logo_id ) { $response->add_link( 'https://api.w.org/featuredmedia', - rest_url( 'wp/v2/media/' . $site_logo_id ), + rest_url( rest_get_route_for_post( $site_logo_id ) ), array( 'embeddable' => true, ) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php index 3cb3d7efe5..0a2cf5d49b 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php @@ -67,8 +67,8 @@ class WP_REST_Autosaves_Controller extends WP_REST_Revisions_Controller { $this->parent_controller = $parent_controller; $this->revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type ); - $this->namespace = 'wp/v2'; $this->rest_base = 'autosaves'; + $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php index 8ef94ea21a..4801d7943d 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-statuses-controller.php @@ -263,10 +263,11 @@ class WP_REST_Post_Statuses_Controller extends WP_REST_Controller { $response = rest_ensure_response( $data ); + $rest_url = rest_url( rest_get_route_for_post_type_items( 'post' ) ); if ( 'publish' === $status->name ) { - $response->add_link( 'archives', rest_url( 'wp/v2/posts' ) ); + $response->add_link( 'archives', $rest_url ); } else { - $response->add_link( 'archives', add_query_arg( 'status', $status->name, rest_url( 'wp/v2/posts' ) ) ); + $response->add_link( 'archives', add_query_arg( 'status', $status->name, $rest_url ) ); } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php index 09b4e68bc0..088d238883 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php @@ -180,6 +180,7 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { $taxonomies = wp_list_filter( get_object_taxonomies( $post_type->name, 'objects' ), array( 'show_in_rest' => true ) ); $taxonomies = wp_list_pluck( $taxonomies, 'name' ); $base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; + $namespace = ! empty( $post_type->rest_namespace ) ? $post_type->rest_namespace : 'wp/v2'; $supports = get_all_post_type_supports( $post_type->name ); $fields = $this->get_fields_for_response( $request ); @@ -232,6 +233,10 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { $data['rest_base'] = $base; } + if ( in_array( 'rest_namespace', $fields, true ) ) { + $data['rest_namespace'] = $namespace; + } + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); @@ -245,7 +250,7 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), ), 'https://api.w.org/items' => array( - 'href' => rest_url( sprintf( 'wp/v2/%s', $base ) ), + 'href' => rest_url( rest_get_route_for_post_type_items( $post_type->name ) ), ), ) ); @@ -269,7 +274,7 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { * * @since 4.7.0 * @since 4.8.0 The `supports` property was added. - * @since 5.9.0 The `visibility` property was added. + * @since 5.9.0 The `visibility` and `rest_namespace` properties were added. * * @return array Item schema data. */ @@ -283,55 +288,55 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { 'title' => 'type', 'type' => 'object', 'properties' => array( - 'capabilities' => array( + 'capabilities' => array( 'description' => __( 'All capabilities used by the post type.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), - 'description' => array( + 'description' => array( 'description' => __( 'A human-readable description of the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), - 'hierarchical' => array( + 'hierarchical' => array( 'description' => __( 'Whether or not the post type should have children.' ), 'type' => 'boolean', 'context' => array( 'view', 'edit' ), 'readonly' => true, ), - 'viewable' => array( + 'viewable' => array( 'description' => __( 'Whether or not the post type can be viewed.' ), 'type' => 'boolean', 'context' => array( 'edit' ), 'readonly' => true, ), - 'labels' => array( + 'labels' => array( 'description' => __( 'Human-readable labels for the post type for various contexts.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), - 'name' => array( + 'name' => array( 'description' => __( 'The title for the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), - 'slug' => array( + 'slug' => array( 'description' => __( 'An alphanumeric identifier for the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), - 'supports' => array( + 'supports' => array( 'description' => __( 'All features, supported by the post type.' ), 'type' => 'object', 'context' => array( 'edit' ), 'readonly' => true, ), - 'taxonomies' => array( + 'taxonomies' => array( 'description' => __( 'Taxonomies associated with post type.' ), 'type' => 'array', 'items' => array( @@ -340,13 +345,19 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { 'context' => array( 'view', 'edit' ), 'readonly' => true, ), - 'rest_base' => array( + 'rest_base' => array( 'description' => __( 'REST base route for the post type.' ), 'type' => 'string', 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), - 'visibility' => array( + 'rest_namespace' => array( + 'description' => __( 'REST route\'s namespace for the post type.' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + 'readonly' => true, + ), + 'visibility' => array( 'description' => __( 'The visibility settings for the post type.' ), 'type' => 'object', 'context' => array( 'edit' ), diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php index 068cc70bc2..0cc548b0b6 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php @@ -48,9 +48,9 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { */ public function __construct( $post_type ) { $this->post_type = $post_type; - $this->namespace = 'wp/v2'; $obj = get_post_type_object( $post_type ); $this->rest_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name; + $this->namespace = ! empty( $obj->rest_namespace ) ? $obj->rest_namespace : 'wp/v2'; $this->meta = new WP_REST_Post_Meta_Fields( $this->post_type ); } @@ -2037,7 +2037,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { // If we have a featured media, add that. $featured_media = get_post_thumbnail_id( $post->ID ); if ( $featured_media ) { - $image_url = rest_url( 'wp/v2/media/' . $featured_media ); + $image_url = rest_url( rest_get_route_for_post( $featured_media ) ); $links['https://api.w.org/featuredmedia'] = array( 'href' => $image_url, @@ -2046,7 +2046,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller { } if ( ! in_array( $post->post_type, array( 'attachment', 'nav_menu_item', 'revision' ), true ) ) { - $attachments_url = rest_url( 'wp/v2/media' ); + $attachments_url = rest_url( rest_get_route_for_post_type_items( 'attachment' ) ); $attachments_url = add_query_arg( 'parent', $post->ID, $attachments_url ); $links['https://api.w.org/attachment'] = array( diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php index 5449812e19..bea3ddac78 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php @@ -49,10 +49,10 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller { */ public function __construct( $parent_post_type ) { $this->parent_post_type = $parent_post_type; - $this->namespace = 'wp/v2'; $this->rest_base = 'revisions'; $post_type_object = get_post_type_object( $parent_post_type ); $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; + $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; $this->parent_controller = $post_type_object->get_rest_controller(); if ( ! $this->parent_controller ) { diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 1b4df794e8..e7712363f7 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -33,9 +33,9 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { */ public function __construct( $post_type ) { $this->post_type = $post_type; - $this->namespace = 'wp/v2'; $obj = get_post_type_object( $post_type ); $this->rest_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name; + $this->namespace = ! empty( $obj->rest_namespace ) ? $obj->rest_namespace : 'wp/v2'; } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php index 093b98a491..183b7c7ffa 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php @@ -914,15 +914,14 @@ class WP_REST_Terms_Controller extends WP_REST_Controller { $post_type_links = array(); foreach ( $taxonomy_obj->object_type as $type ) { - $post_type_object = get_post_type_object( $type ); + $rest_path = rest_get_route_for_post_type_items( $type ); - if ( empty( $post_type_object->show_in_rest ) ) { + if ( empty( $rest_path ) ) { continue; } - $rest_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; $post_type_links[] = array( - 'href' => add_query_arg( $this->rest_base, $term->term_id, rest_url( sprintf( 'wp/v2/%s', $rest_base ) ) ), + 'href' => add_query_arg( $this->rest_base, $term->term_id, rest_url( $rest_path ) ), ); } diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 4ec818013b..5770f68841 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -1829,6 +1829,48 @@ class Tests_REST_API extends WP_UnitTestCase { $this->assertSame( '', rest_get_route_for_post( $post ) ); } + /** + * @ticket 53656 + */ + public function test_rest_get_route_for_post_custom_namespace() { + register_post_type( + 'cpt', + array( + 'show_in_rest' => true, + 'rest_base' => 'cpt', + 'rest_namespace' => 'wordpress/v1', + ) + ); + $post = self::factory()->post->create_and_get( array( 'post_type' => 'cpt' ) ); + + $this->assertSame( '/wordpress/v1/cpt/' . $post->ID, rest_get_route_for_post( $post ) ); + unregister_post_type( 'cpt' ); + } + + /** + * @ticket 53656 + */ + public function test_rest_get_route_for_post_type_items() { + $this->assertSame( '/wp/v2/posts', rest_get_route_for_post_type_items( 'post' ) ); + } + + /** + * @ticket 53656 + */ + public function test_rest_get_route_for_post_type_items_custom_namespace() { + register_post_type( + 'cpt', + array( + 'show_in_rest' => true, + 'rest_base' => 'cpt', + 'rest_namespace' => 'wordpress/v1', + ) + ); + + $this->assertSame( '/wordpress/v1/cpt', rest_get_route_for_post_type_items( 'cpt' ) ); + unregister_post_type( 'cpt' ); + } + /** * @ticket 49116 */ @@ -1839,10 +1881,11 @@ class Tests_REST_API extends WP_UnitTestCase { /** * @ticket 49116 + * @ticket 53656 */ public function test_rest_get_route_for_post_custom_controller() { $post = self::factory()->post->create_and_get( array( 'post_type' => 'wp_block' ) ); - $this->assertSame( '', rest_get_route_for_post( $post ) ); + $this->assertSame( '/wp/v2/blocks/' . $post->ID, rest_get_route_for_post( $post ) ); } /** diff --git a/tests/phpunit/tests/rest-api/rest-post-types-controller.php b/tests/phpunit/tests/rest-api/rest-post-types-controller.php index d93f5814c1..22ff225a69 100644 --- a/tests/phpunit/tests/rest-api/rest-post-types-controller.php +++ b/tests/phpunit/tests/rest-api/rest-post-types-controller.php @@ -62,6 +62,23 @@ class WP_Test_REST_Post_Types_Controller extends WP_Test_REST_Controller_Testcas $this->assertSame( array( 'category', 'post_tag' ), $data['taxonomies'] ); } + /** + * @ticket 53656 + */ + public function test_get_item_cpt() { + register_post_type( + 'cpt', + array( + 'show_in_rest' => true, + 'rest_base' => 'cpt', + 'rest_namespace' => 'wordpress/v1', + ) + ); + $request = new WP_REST_Request( 'GET', '/wp/v2/types/cpt' ); + $response = rest_get_server()->dispatch( $request ); + $this->check_post_type_object_response( 'view', $response, 'cpt' ); + } + public function test_get_item_page() { $request = new WP_REST_Request( 'GET', '/wp/v2/types/page' ); $response = rest_get_server()->dispatch( $request ); @@ -144,7 +161,7 @@ class WP_Test_REST_Post_Types_Controller extends WP_Test_REST_Controller_Testcas $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertCount( 11, $properties ); + $this->assertCount( 12, $properties ); $this->assertArrayHasKey( 'capabilities', $properties ); $this->assertArrayHasKey( 'description', $properties ); $this->assertArrayHasKey( 'hierarchical', $properties ); @@ -155,6 +172,7 @@ class WP_Test_REST_Post_Types_Controller extends WP_Test_REST_Controller_Testcas $this->assertArrayHasKey( 'supports', $properties ); $this->assertArrayHasKey( 'taxonomies', $properties ); $this->assertArrayHasKey( 'rest_base', $properties ); + $this->assertArrayHasKey( 'rest_namespace', $properties ); $this->assertArrayHasKey( 'visibility', $properties ); } @@ -204,6 +222,7 @@ class WP_Test_REST_Post_Types_Controller extends WP_Test_REST_Controller_Testcas $this->assertSame( $post_type_obj->description, $data['description'] ); $this->assertSame( $post_type_obj->hierarchical, $data['hierarchical'] ); $this->assertSame( $post_type_obj->rest_base, $data['rest_base'] ); + $this->assertSame( $post_type_obj->rest_namespace, $data['rest_namespace'] ); $links = test_rest_expand_compact_links( $links ); $this->assertSame( rest_url( 'wp/v2/types' ), $links['collection'][0]['href'] ); diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 0d5b2230e0..63b70dd2c8 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -8336,6 +8336,7 @@ mockedApiResponse.TypesCollection = { "post_tag" ], "rest_base": "posts", + "rest_namespace": "wp/v2", "_links": { "collection": [ { @@ -8363,6 +8364,7 @@ mockedApiResponse.TypesCollection = { "slug": "page", "taxonomies": [], "rest_base": "pages", + "rest_namespace": "wp/v2", "_links": { "collection": [ { @@ -8390,6 +8392,7 @@ mockedApiResponse.TypesCollection = { "slug": "attachment", "taxonomies": [], "rest_base": "media", + "rest_namespace": "wp/v2", "_links": { "collection": [ { @@ -8417,6 +8420,7 @@ mockedApiResponse.TypesCollection = { "slug": "wp_block", "taxonomies": [], "rest_base": "blocks", + "rest_namespace": "wp/v2", "_links": { "collection": [ { @@ -8444,6 +8448,7 @@ mockedApiResponse.TypesCollection = { "slug": "wp_template", "taxonomies": [], "rest_base": "templates", + "rest_namespace": "wp/v2", "_links": { "collection": [ { @@ -8475,7 +8480,8 @@ mockedApiResponse.TypeModel = { "category", "post_tag" ], - "rest_base": "posts" + "rest_base": "posts", + "rest_namespace": "wp/v2" }; mockedApiResponse.StatusesCollection = {