REST API: Introduce Menu management endpoints.

This commit introduces the `/wp/v2/menus`, `/wp/v2/menu-items` and `/wp/v2/menu-locations` REST API endpoints. These endpoints are fully available to users with the `edit_theme_options` capability, but can be read by any user who can edit a REST API available post type.

The `nav_menu` taxonomy and `nav_menu_item` post type now map their capabilities to the `edit_theme_options` primitive capability. This allows developers to provide more fine-grained access control. However, if a developer is currently dynamically removing the `edit_theme_options` capability using `map_meta_cap`, they should use the `user_has_cap` filter instead.

The `wp_update_nav_menu_item()` function has been adjusted to return an error if saving the menu item post or assigning the menu item to a menu generate an error.

Lastly, a new menu item type is introduced, `block`, that can be used to store a Block as a menu item.

Props andraganescu, antonvlasenko, dingo_d, dlh, isabel_brison, kadamwhite, Mamaduka, NateWr, noisysocks, peterwilsoncc, ryelle, schlessera, soean, Spacedmonkey, talldanwp, TimothyBlynJacobs, tobifjellner, westonruter, wpscholar, zieladam.
Fixes #40878.


git-svn-id: https://develop.svn.wordpress.org/trunk@52079 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Timothy Jacobs
2021-11-09 18:58:59 +00:00
parent de9a1e6f94
commit aae0000cef
15 changed files with 5335 additions and 22 deletions

View File

@@ -89,6 +89,14 @@ class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase {
'/wp/v2/posts/(?P<parent>[\\d]+)/revisions/(?P<id>[\\d]+)',
'/wp/v2/posts/(?P<id>[\\d]+)/autosaves',
'/wp/v2/posts/(?P<parent>[\\d]+)/autosaves/(?P<id>[\\d]+)',
'/wp/v2/menu-items',
'/wp/v2/menu-items/(?P<id>[\d]+)',
'/wp/v2/menu-items/(?P<id>[\d]+)/autosaves',
'/wp/v2/menu-items/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)',
'/wp/v2/menu-locations',
'/wp/v2/menu-locations/(?P<location>[\w-]+)',
'/wp/v2/menus',
'/wp/v2/menus/(?P<id>[\d]+)',
'/wp/v2/pages',
'/wp/v2/pages/(?P<id>[\\d]+)',
'/wp/v2/pages/(?P<parent>[\\d]+)/revisions',

View File

@@ -68,7 +68,9 @@ class WP_Test_REST_Taxonomies_Controller extends WP_Test_REST_Controller_Testcas
$request->set_param( 'context', 'edit' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$taxonomies = $this->get_public_taxonomies( get_taxonomies( '', 'objects' ) );
$taxonomies = get_taxonomies( '', 'objects' );
unset( $taxonomies['nav_menu'] ); // Menus are not editable by contributors.
$taxonomies = $this->get_public_taxonomies( $taxonomies );
$this->assertSame( count( $taxonomies ), count( $data ) );
$this->assertSame( 'Categories', $data['category']['name'] );
$this->assertSame( 'category', $data['category']['slug'] );

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
<?php
/**
* WP_REST_Menu_Locations_Controller tests.
*
* @package WordPress
* @subpackage REST_API
* @since 5.9.0
*/
/**
* Tests for REST API for Menu locations.
*
* @group restapi
*
* @coversDefaultClass WP_REST_Menu_Locations_Controller
*/
class Tests_REST_WpRestMenuLocationsController extends WP_Test_REST_Controller_Testcase {
/**
* @var int
*/
protected static $admin_id;
/**
* Create fake data before our tests run.
*
* @param WP_UnitTest_Factory $factory Helper that lets us create fake data.
*/
public static function wpSetUpBeforeClass( $factory ) {
self::$admin_id = $factory->user->create(
array(
'role' => 'administrator',
)
);
}
/**
* Set up.
*/
public function set_up() {
parent::set_up();
// Unregister all nav menu locations.
foreach ( array_keys( get_registered_nav_menus() ) as $location ) {
unregister_nav_menu( $location );
}
}
/**
* Register nav menu locations.
*
* @param array $locations Location slugs.
*/
public function register_nav_menu_locations( $locations ) {
foreach ( $locations as $location ) {
register_nav_menu( $location, ucfirst( $location ) );
}
}
/**
* @ticket 40878
* @covers ::register_routes
*/
public function test_register_routes() {
$routes = rest_get_server()->get_routes();
$this->assertArrayHasKey( '/wp/v2/menu-locations', $routes );
$this->assertCount( 1, $routes['/wp/v2/menu-locations'] );
$this->assertArrayHasKey( '/wp/v2/menu-locations/(?P<location>[\w-]+)', $routes );
$this->assertCount( 1, $routes['/wp/v2/menu-locations/(?P<location>[\w-]+)'] );
}
/**
* @ticket 40878
* @covers ::get_context_param
*/
public function test_context_param() {
// Collection.
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/menu-locations' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertSame( 'view', $data['endpoints'][0]['args']['context']['default'] );
$this->assertSame( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
$menu = 'primary';
$this->register_nav_menu_locations( array( $menu ) );
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/menu-locations/' . $menu );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertSame( 'view', $data['endpoints'][0]['args']['context']['default'] );
$this->assertSame( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
}
/**
* @ticket 40878
* @covers ::get_items
*/
public function test_get_items() {
$menus = array( 'primary', 'secondary' );
$this->register_nav_menu_locations( array( 'primary', 'secondary' ) );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'GET', '/wp/v2/menu-locations' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$data = array_values( $data );
$this->assertCount( 2, $data );
$names = wp_list_pluck( $data, 'name' );
$descriptions = wp_list_pluck( $data, 'description' );
$this->assertSame( $menus, $names );
$menu_descriptions = array_map( 'ucfirst', $names );
$this->assertSame( $menu_descriptions, $descriptions );
}
/**
* @ticket 40878
* @covers ::get_item
*/
public function test_get_item() {
$menu = 'primary';
$this->register_nav_menu_locations( array( $menu ) );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'GET', '/wp/v2/menu-locations/' . $menu );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertSame( $menu, $data['name'] );
}
/**
* @ticket 40878
* @covers ::get_item
*/
public function test_get_item_invalid() {
$menu = 'primary';
$this->register_nav_menu_locations( array( $menu ) );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'GET', '/wp/v2/menu-locations/invalid' );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_menu_location_invalid', $response, 404 );
}
/**
* The test_create_item() method does not exist for menu locations.
*/
public function test_create_item() {}
/**
* The test_update_item() method does not exist for menu locations.
*/
public function test_update_item() {}
/**
* The test_delete_item() method does not exist for menu locations.
*/
public function test_delete_item() {}
/**
* The test_prepare_item() method does not exist for menu locations.
*/
public function test_prepare_item() {}
/**
* @ticket 40878
* @covers ::get_item_schema
*/
public function test_get_item_schema() {
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/menu-locations' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$properties = $data['schema']['properties'];
$this->assertSame( 3, count( $properties ) );
$this->assertArrayHasKey( 'name', $properties );
$this->assertArrayHasKey( 'description', $properties );
$this->assertArrayHasKey( 'menu', $properties );
}
/**
* @ticket 40878
* @covers ::get_items
* @covers ::get_items_permissions_check
*/
public function test_get_items_menu_location_context_without_permission() {
wp_set_current_user( 0 );
$request = new WP_REST_Request( 'GET', '/wp/v2/menu-locations' );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_cannot_view', $response, rest_authorization_required_code() );
}
/**
* @ticket 40878
* @covers ::get_item
* @covers ::get_item_permissions_check
*/
public function test_get_item_menu_location_context_without_permission() {
$menu = 'primary';
$this->register_nav_menu_locations( array( $menu ) );
wp_set_current_user( 0 );
$request = new WP_REST_Request( 'GET', '/wp/v2/menu-locations/' . $menu );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_cannot_view', $response, rest_authorization_required_code() );
}
}

View File

@@ -0,0 +1,642 @@
<?php
/**
* WP_REST_Menus_Controller tests
*
* @package WordPress
* @subpackage REST_API
* @since 5.9.0
*/
/**
* Tests for REST API for Menus.
*
* @group restapi
*
* @coversDefaultClass WP_REST_Menus_Controller
*/
class Tests_REST_WpRestMenusController extends WP_Test_REST_Controller_Testcase {
/**
* @var int
*/
public $menu_id;
/**
* @var int
*/
protected static $admin_id;
/**
* @var int
*/
protected static $editor_id;
/**
* @var int
*/
protected static $subscriber_id;
/**
*
*/
const TAXONOMY = 'nav_menu';
/**
* @var int
*/
protected static $per_page = 50;
/**
* Create fake data before our tests run.
*
* @param WP_UnitTest_Factory $factory Helper that lets us create fake data.
*/
public static function wpSetUpBeforeClass( $factory ) {
self::$admin_id = $factory->user->create(
array(
'role' => 'administrator',
)
);
self::$editor_id = $factory->user->create(
array(
'role' => 'editor',
)
);
self::$subscriber_id = $factory->user->create(
array(
'role' => 'subscriber',
)
);
}
/**
*
*/
public function set_up() {
parent::set_up();
// Unregister all nav menu locations.
foreach ( array_keys( get_registered_nav_menus() ) as $location ) {
unregister_nav_menu( $location );
}
$orig_args = array(
'name' => 'Original Name',
'description' => 'Original Description',
'slug' => 'original-slug',
'taxonomy' => 'nav_menu',
);
$this->menu_id = $this->factory->term->create( $orig_args );
register_meta(
'term',
'test_single_menu',
array(
'object_subtype' => self::TAXONOMY,
'show_in_rest' => true,
'single' => true,
'type' => 'string',
)
);
}
/**
* Register nav menu locations.
*
* @param array $locations Location slugs.
*/
public function register_nav_menu_locations( $locations ) {
foreach ( $locations as $location ) {
register_nav_menu( $location, ucfirst( $location ) );
}
}
/**
* @ticket 40878
* @covers ::register_routes
*/
public function test_register_routes() {
$routes = rest_get_server()->get_routes();
$this->assertArrayHasKey( '/wp/v2/menus', $routes );
$this->assertArrayHasKey( '/wp/v2/menus/(?P<id>[\d]+)', $routes );
}
/**
* @ticket 40878
* @covers ::get_context_param
*/
public function test_context_param() {
// Collection.
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/menus' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertSame( 'view', $data['endpoints'][0]['args']['context']['default'] );
$this->assertSameSets( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
$this->assertSame( array( 'v1' => true ), $data['endpoints'][0]['allow_batch'] );
// Single.
$tag1 = $this->factory->tag->create( array( 'name' => 'Season 5' ) );
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/menus/' . $tag1 );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->assertSame( 'view', $data['endpoints'][0]['args']['context']['default'] );
$this->assertSameSets( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
$this->assertSame( array( 'v1' => true ), $data['endpoints'][0]['allow_batch'] );
}
/**
* @ticket 40878
* @covers ::get_collection_params
*/
public function test_registered_query_params() {
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/menus' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$keys = array_keys( $data['endpoints'][0]['args'] );
sort( $keys );
$this->assertSame(
array(
'context',
'exclude',
'hide_empty',
'include',
'offset',
'order',
'orderby',
'page',
'per_page',
'post',
'search',
'slug',
),
$keys
);
}
/**
* @ticket 40878
* @covers ::get_items
*/
public function test_get_items() {
wp_set_current_user( self::$admin_id );
wp_update_nav_menu_object(
0,
array(
'description' => 'Test get',
'menu-name' => 'test Name get',
)
);
$request = new WP_REST_Request( 'GET', '/wp/v2/menus' );
$request->set_param( 'per_page', self::$per_page );
$response = rest_get_server()->dispatch( $request );
$this->check_get_taxonomy_terms_response( $response );
}
/**
* @ticket 40878
* @covers ::get_item
*/
public function test_get_item() {
wp_set_current_user( self::$admin_id );
$nav_menu_id = wp_update_nav_menu_object(
0,
array(
'description' => 'Test menu',
'menu-name' => 'test Name',
)
);
$this->register_nav_menu_locations( array( 'primary' ) );
set_theme_mod( 'nav_menu_locations', array( 'primary' => $nav_menu_id ) );
$request = new WP_REST_Request( 'GET', '/wp/v2/menus/' . $nav_menu_id );
$response = rest_get_server()->dispatch( $request );
$this->check_get_taxonomy_term_response( $response, $nav_menu_id );
}
/**
* @ticket 40878
* @covers ::create_item
*/
public function test_create_item() {
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus' );
$request->set_param( 'name', 'My Awesome menus' );
$request->set_param( 'description', 'This menu is so awesome.' );
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 201, $response->get_status() );
$headers = $response->get_headers();
$data = $response->get_data();
$this->assertStringContainsString( '/wp/v2/menus/' . $data['id'], $headers['Location'] );
$this->assertSame( 'My Awesome menus', $data['name'] );
$this->assertSame( 'This menu is so awesome.', $data['description'] );
$this->assertSame( 'my-awesome-menus', $data['slug'] );
}
/**
* @ticket 40878
* @covers ::create_item
*/
public function test_create_item_same_name() {
wp_set_current_user( self::$admin_id );
wp_update_nav_menu_object(
0,
array(
'description' => 'This menu is so Original',
'menu-name' => 'Original',
)
);
$request = new WP_REST_Request( 'POST', '/wp/v2/menus' );
$request->set_param( 'name', 'Original' );
$request->set_param( 'description', 'This menu is so Original' );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'menu_exists', $response, 400 );
}
/**
* @ticket 40878
* @covers ::update_item
* @covers ::handle_auto_add
*/
public function test_update_item() {
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus/' . $this->menu_id );
$request->set_param( 'name', 'New Name' );
$request->set_param( 'description', 'New Description' );
$request->set_param( 'auto_add', true );
$request->set_param(
'meta',
array(
'test_single_menu' => 'just meta',
)
);
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 200, $response->get_status() );
$data = $response->get_data();
$this->assertSame( 'New Name', $data['name'] );
$this->assertSame( 'New Description', $data['description'] );
$this->assertSame( true, $data['auto_add'] );
$this->assertSame( 'new-name', $data['slug'] );
$this->assertSame( 'just meta', $data['meta']['test_single_menu'] );
$this->assertFalse( isset( $data['meta']['test_cat_meta'] ) );
}
/**
* @ticket 40878
* @covers ::delete_item
*/
public function test_delete_item() {
wp_set_current_user( self::$admin_id );
$nav_menu_id = wp_update_nav_menu_object(
0,
array(
'description' => 'Deleted Menu',
'menu-name' => 'Deleted Menu',
)
);
$term = get_term_by( 'id', $nav_menu_id, self::TAXONOMY );
$request = new WP_REST_Request( 'DELETE', '/wp/v2/menus/' . $term->term_id );
$request->set_param( 'force', true );
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 200, $response->get_status() );
$data = $response->get_data();
$this->assertTrue( $data['deleted'] );
$this->assertSame( 'Deleted Menu', $data['previous']['name'] );
}
/**
* @ticket 40878
* @covers ::prepare_item_for_response
* @covers ::get_item
*/
public function test_prepare_item() {
$nav_menu_id = wp_update_nav_menu_object(
0,
array(
'description' => 'Foo Menu',
'menu-name' => 'Foo Menu',
)
);
$term = get_term_by( 'id', $nav_menu_id, self::TAXONOMY );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'GET', '/wp/v2/menus/' . $term->term_id );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$this->check_taxonomy_term( $term, $data, $response->get_links() );
}
/**
* @ticket 40878
* @covers ::get_item_schema
*/
public function test_get_item_schema() {
$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/menus' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$properties = $data['schema']['properties'];
$this->assertSame( 7, count( $properties ) );
$this->assertArrayHasKey( 'id', $properties );
$this->assertArrayHasKey( 'description', $properties );
$this->assertArrayHasKey( 'meta', $properties );
$this->assertArrayHasKey( 'name', $properties );
$this->assertArrayHasKey( 'slug', $properties );
$this->assertArrayHasKey( 'locations', $properties );
}
/**
* @ticket 40878
* @covers ::create_item
*/
public function test_create_item_with_location_permission_correct() {
$this->register_nav_menu_locations( array( 'primary', 'secondary' ) );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus' );
$request->set_param( 'name', 'My Awesome Term' );
$request->set_param( 'slug', 'so-awesome' );
$request->set_param( 'locations', 'primary' );
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 201, $response->get_status() );
$data = $response->get_data();
$term_id = $data['id'];
$locations = get_nav_menu_locations();
$this->assertSame( $locations['primary'], $term_id );
}
/**
* @ticket 40878
* @covers ::create_item
*/
public function test_create_item_with_invalid_location() {
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus' );
$request->set_param( 'name', 'My Awesome Term' );
$request->set_param( 'slug', 'so-awesome' );
$request->set_param( 'locations', 'bar' );
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 400, $response->get_status() );
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
$this->assertArrayHasKey( 'locations', $response->get_data()['data']['details'] );
$this->assertSame( 'rest_invalid_menu_location', $response->get_data()['data']['details']['locations']['code'] );
}
/**
* @ticket 40878
* @covers ::update_item
*/
public function test_update_item_with_no_location() {
$this->register_nav_menu_locations( array( 'primary', 'secondary' ) );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus/' . $this->menu_id );
$request->set_param( 'name', 'New Name' );
$request->set_param( 'description', 'New Description' );
$request->set_param( 'slug', 'new-slug' );
$request->set_param( 'locations', 'bar' );
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 400, $response->get_status() );
}
/**
* @ticket 40878
* @covers ::update_item
*/
public function test_update_item_with_location_permission_correct() {
$this->register_nav_menu_locations( array( 'primary', 'secondary' ) );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus/' . $this->menu_id );
$request->set_param( 'name', 'New Name' );
$request->set_param( 'description', 'New Description' );
$request->set_param( 'slug', 'new-slug' );
$request->set_param( 'locations', 'primary' );
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 200, $response->get_status() );
$locations = get_nav_menu_locations();
$this->assertSame( $locations['primary'], $this->menu_id );
}
/**
* @ticket 40878
* @covers ::update_item
*/
public function test_update_item_with_location_permission_incorrect() {
$this->register_nav_menu_locations( array( 'primary', 'secondary' ) );
wp_set_current_user( self::$subscriber_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus/' . $this->menu_id );
$request->set_param( 'name', 'New Name' );
$request->set_param( 'description', 'New Description' );
$request->set_param( 'slug', 'new-slug' );
$request->set_param( 'locations', 'primary' );
$response = rest_get_server()->dispatch( $request );
$this->assertSame( rest_authorization_required_code(), $response->get_status() );
}
/**
* @ticket 40878
* @covers ::prepare_links
*/
public function test_get_item_links() {
wp_set_current_user( self::$admin_id );
$nav_menu_id = wp_update_nav_menu_object(
0,
array(
'description' => 'Foo Menu',
'menu-name' => 'Foo Menu',
)
);
register_nav_menu( 'foo', 'Bar' );
set_theme_mod( 'nav_menu_locations', array( 'foo' => $nav_menu_id ) );
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/menus/%d', $nav_menu_id ) );
$response = rest_get_server()->dispatch( $request );
$links = $response->get_links();
$this->assertArrayHasKey( 'https://api.w.org/menu-location', $links );
$location_url = rest_url( '/wp/v2/menu-locations/foo' );
$this->assertSame( $location_url, $links['https://api.w.org/menu-location'][0]['href'] );
}
/**
* @ticket 40878
* @covers ::update_item
* @covers ::handle_locations
*/
public function test_change_menu_location() {
$this->register_nav_menu_locations( array( 'primary', 'secondary' ) );
$secondary_id = self::factory()->term->create(
array(
'name' => 'Secondary Name',
'description' => 'Secondary Description',
'slug' => 'secondary-slug',
'taxonomy' => 'nav_menu',
)
);
$locations = get_nav_menu_locations();
$locations['primary'] = $this->menu_id;
$locations['secondary'] = $secondary_id;
set_theme_mod( 'nav_menu_locations', $locations );
wp_set_current_user( self::$admin_id );
$request = new WP_REST_Request( 'POST', '/wp/v2/menus/' . $this->menu_id );
$request->set_body_params(
array(
'locations' => array( 'secondary' ),
)
);
$response = rest_get_server()->dispatch( $request );
$this->assertSame( 200, $response->get_status() );
$locations = get_nav_menu_locations();
$this->assertArrayNotHasKey( 'primary', $locations );
$this->assertArrayHasKey( 'secondary', $locations );
$this->assertSame( $this->menu_id, $locations['secondary'] );
}
/**
* @ticket 40878
* @covers ::get_items
* @covers ::get_items_permissions_check
*/
public function test_get_items_no_permission() {
wp_set_current_user( 0 );
$request = new WP_REST_Request( 'GET', '/wp/v2/menus' );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_cannot_view', $response, 401 );
}
/**
* @ticket 40878
* @covers ::get_items
* @covers ::get_items_permissions_check
*/
public function test_get_item_no_permission() {
wp_set_current_user( 0 );
$request = new WP_REST_Request( 'GET', '/wp/v2/menus/' . $this->menu_id );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_cannot_view', $response, 401 );
}
/**
* @ticket 40878
* @covers ::get_items
* @covers ::get_items_permissions_check
*/
public function test_get_items_wrong_permission() {
wp_set_current_user( self::$subscriber_id );
$request = new WP_REST_Request( 'GET', '/wp/v2/menus' );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_cannot_view', $response, 403 );
}
/**
* @ticket 40878
* @covers ::get_item
* @covers ::get_item_permissions_check
*/
public function test_get_item_wrong_permission() {
wp_set_current_user( self::$subscriber_id );
$request = new WP_REST_Request( 'GET', '/wp/v2/menus/' . $this->menu_id );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'rest_cannot_view', $response, 403 );
}
/**
* @ticket 40878
*/
public function test_it_allows_batch_requests_when_updating_menus() {
$rest_server = rest_get_server();
// This call is needed to initialize route_options.
$rest_server->get_routes();
$route_options = $rest_server->get_route_options( '/wp/v2/menus/(?P<id>[\d]+)' );
$this->assertArrayHasKey( 'allow_batch', $route_options );
$this->assertSame( array( 'v1' => true ), $route_options['allow_batch'] );
}
/**
* @param WP_REST_Response $response Response Class.
*/
protected function check_get_taxonomy_terms_response( $response ) {
$this->assertSame( 200, $response->get_status() );
$data = $response->get_data();
$args = array(
'hide_empty' => false,
);
$tags = get_terms( self::TAXONOMY, $args );
$this->assertSame( count( $tags ), count( $data ) );
$this->assertSame( $tags[0]->term_id, $data[0]['id'] );
$this->assertSame( $tags[0]->name, $data[0]['name'] );
$this->assertSame( $tags[0]->slug, $data[0]['slug'] );
$this->assertSame( $tags[0]->description, $data[0]['description'] );
}
/**
* @param WP_REST_Response $response Response Class.
* @param int $id Term ID.
*/
protected function check_get_taxonomy_term_response( $response, $id ) {
$this->assertSame( 200, $response->get_status() );
$data = $response->get_data();
$menu = get_term( $id, self::TAXONOMY );
$this->check_taxonomy_term( $menu, $data, $response->get_links() );
}
/**
* @param WP_Term $term WP_Term object.
* @param array $data Data from REST API.
* @param array $links Array of links.
*/
protected function check_taxonomy_term( $term, $data, $links ) {
$this->assertSame( $term->term_id, $data['id'] );
$this->assertSame( $term->name, $data['name'] );
$this->assertSame( $term->slug, $data['slug'] );
$this->assertSame( $term->description, $data['description'] );
$this->assertFalse( isset( $data['parent'] ) );
$locations = get_nav_menu_locations();
if ( ! empty( $locations ) ) {
$menu_locations = array();
foreach ( $locations as $location => $menu_id ) {
if ( $menu_id === $term->term_id ) {
$menu_locations[] = $location;
}
}
$this->assertSame( $menu_locations, $data['locations'] );
}
$relations = array(
'self',
'collection',
'about',
'https://api.w.org/post_type',
);
if ( ! empty( $data['parent'] ) ) {
$relations[] = 'up';
}
if ( ! empty( $data['locations'] ) ) {
$relations[] = 'https://api.w.org/menu-location';
}
$this->assertSameSets( $relations, array_keys( $links ) );
$this->assertStringContainsString( 'wp/v2/taxonomies/' . $term->taxonomy, $links['about'][0]['href'] );
$this->assertSame( add_query_arg( 'menus', $term->term_id, rest_url( 'wp/v2/menu-items' ) ), $links['https://api.w.org/post_type'][0]['href'] );
}
}