Skip to content

Commit

Permalink
Remove parent and position validation from menu item REST API endpoint (
Browse files Browse the repository at this point in the history
#34672)

* Remove validation

* Remove tests

* Validate if menu_order is set and >= 1

* Feddback.

* Remove validation again.

* Fix test.

* Menu order 1.

Co-authored-by: Adam Zieliński <[email protected]>
  • Loading branch information
spacedmonkey and adamziel authored Sep 14, 2021
1 parent 4fc4a03 commit 639a603
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 102 deletions.
63 changes: 12 additions & 51 deletions lib/class-wp-rest-menu-items-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ protected function prepare_item_for_database( $request ) {
'menu-item-object-id' => 0,
'menu-item-object' => '',
'menu-item-parent-id' => 0,
'menu-item-position' => 0,
'menu-item-position' => 1,
'menu-item-type' => 'custom',
'menu-item-title' => '',
'menu-item-url' => '',
Expand Down Expand Up @@ -524,51 +524,6 @@ protected function prepare_item_for_database( $request ) {
}
}

// If menu id is set, valid the value of menu item position and parent id.
if ( ! empty( $prepared_nav_item['menu-id'] ) ) {
// Check if nav menu is valid.
if ( ! is_nav_menu( $prepared_nav_item['menu-id'] ) ) {
return new WP_Error( 'invalid_menu_id', __( 'Invalid menu ID.', 'gutenberg' ), array( 'status' => 400 ) );
}

// If menu item position is set to 0, insert as the last item in the existing menu.
$menu_items = wp_get_nav_menu_items( $prepared_nav_item['menu-id'], array( 'post_status' => 'publish,draft' ) );
if ( 0 === (int) $prepared_nav_item['menu-item-position'] ) {
if ( $menu_items ) {
$last_item = $menu_items[ count( $menu_items ) - 1 ];
if ( $last_item && isset( $last_item->menu_order ) ) {
$prepared_nav_item['menu-item-position'] = $last_item->menu_order + 1;
} else {
$prepared_nav_item['menu-item-position'] = count( $menu_items ) - 1;
}
array_push( $menu_items, $last_item );
} else {
$prepared_nav_item['menu-item-position'] = 1;
}
}

// Check if existing menu position is already in use by another menu item.
$menu_item_ids = array();
foreach ( $menu_items as $menu_item ) {
$menu_item_ids[] = $menu_item->ID;
if ( $menu_item->ID !== (int) $menu_item_db_id ) {
if ( (int) $prepared_nav_item['menu-item-position'] === (int) $menu_item->menu_order ) {
return new WP_Error( 'invalid_menu_order', __( 'Invalid menu position.', 'gutenberg' ), array( 'status' => 400 ) );
}
}
}

// Check if valid parent id is valid nav menu item in menu.
if ( $prepared_nav_item['menu-item-parent-id'] ) {
if ( ! is_nav_menu_item( $prepared_nav_item['menu-item-parent-id'] ) ) {
return new WP_Error( 'invalid_menu_item_parent', __( 'Invalid menu item parent.', 'gutenberg' ), array( 'status' => 400 ) );
}
if ( ! $menu_item_ids || ! in_array( $prepared_nav_item['menu-item-parent-id'], $menu_item_ids, true ) ) {
return new WP_Error( 'invalid_item_parent', __( 'Invalid menu item parent.', 'gutenberg' ), array( 'status' => 400 ) );
}
}
}

foreach ( array( 'menu-item-object-id', 'menu-item-parent-id' ) as $key ) {
// Note we need to allow negative-integer IDs for previewed objects not inserted yet.
$prepared_nav_item[ $key ] = (int) $prepared_nav_item[ $key ];
Expand Down Expand Up @@ -750,8 +705,13 @@ public function prepare_item_for_response( $post, $request ) {
$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;

if ( rest_is_field_included( $base, $fields ) ) {
$terms = get_the_terms( $post, $taxonomy->name );
$data[ $base ] = $terms ? array_values( wp_list_pluck( $terms, 'term_id' ) ) : array();
$terms = get_the_terms( $post, $taxonomy->name );
$term_ids = $terms ? array_values( wp_list_pluck( $terms, 'term_id' ) ) : array();
if ( 'nav_menu' === $taxonomy->name ) {
$data[ $base ] = $term_ids ? array_shift( $term_ids ) : 0;
} else {
$data[ $base ] = $term_ids;
}
}
}

Expand Down Expand Up @@ -962,10 +922,11 @@ public function get_item_schema() {
'description' => __( 'The DB ID of the nav_menu_item that is this item\'s menu parent, if any, otherwise 0.', 'gutenberg' ),
'context' => array( 'view', 'edit', 'embed' ),
'type' => 'integer',
'minimum' => 0,
'default' => 0,
'minimum' => 1,
'default' => 1,
);
$schema['properties']['object'] = array(

$schema['properties']['object'] = array(
'description' => __( 'The type of object originally represented, such as "category," "post", or "attachment."', 'gutenberg' ),
'context' => array( 'view', 'edit', 'embed' ),
'type' => 'string',
Expand Down
2 changes: 1 addition & 1 deletion packages/edit-navigation/src/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const createMissingMenuItems = serializeProcessing( function* ( post ) {
data: {
title: 'Placeholder',
url: 'Placeholder',
menu_order: 0,
menu_order: 1,
},
} );

Expand Down
4 changes: 2 additions & 2 deletions packages/edit-navigation/src/store/test/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe( 'createMissingMenuItems', () => {
data: {
title: 'Placeholder',
url: 'Placeholder',
menu_order: 0,
menu_order: 1,
},
} )
);
Expand Down Expand Up @@ -200,7 +200,7 @@ describe( 'createMissingMenuItems', () => {
data: {
title: 'Placeholder',
url: 'Placeholder',
menu_order: 0,
menu_order: 1,
},
} )
);
Expand Down
71 changes: 23 additions & 48 deletions phpunit/class-rest-nav-menu-items-controller-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,39 +277,47 @@ public function test_create_item_invalid_term() {
public function test_create_item_change_position() {
wp_set_current_user( self::$admin_id );
$new_menu_id = wp_create_nav_menu( rand_str() );
$expected = array();
$actual = array();
for ( $i = 1; $i < 5; $i ++ ) {
$request = new WP_REST_Request( 'POST', '/__experimental/menu-items' );
$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
$params = $this->set_menu_item_data(
array(
'menus' => $new_menu_id,
'menu_order' => $i,
'menus' => $new_menu_id,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );
$this->check_create_menu_item_response( $response );
$data = $response->get_data();
$this->assertEquals( $data['menu_order'], $i );

$expected[] = $i;
$actual[] = $data['menu_order'];
}
$this->assertEquals( $actual, $expected );
}

/**
*
*/
public function test_create_item_invalid_position() {
public function test_menu_order_must_be_set() {
wp_set_current_user( self::$admin_id );
$new_menu_id = wp_create_nav_menu( rand_str() );
$request = new WP_REST_Request( 'POST', '/__experimental/menu-items' );

$request = new WP_REST_Request( 'POST', '/__experimental/menu-items' );
$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
$params = $this->set_menu_item_data(
array(
'menu_order' => 1,
'menu_order' => 0,
'menus' => $new_menu_id,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );
$this->check_create_menu_item_response( $response );
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );

$request = new WP_REST_Request( 'POST', '/__experimental/menu-items' );
$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
$params = $this->set_menu_item_data(
Expand All @@ -320,8 +328,7 @@ public function test_create_item_invalid_position() {
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );

$this->assertErrorResponse( 'invalid_menu_order', $response, 400 );
$this->assertEquals( 201, $response->get_status() );
}

/**
Expand Down Expand Up @@ -380,43 +387,6 @@ public function test_create_item_invalid_parent() {
$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
}

/**
*
*/
public function test_create_item_invalid_parent_menu_item() {
wp_set_current_user( self::$admin_id );
$new_menu_id = wp_create_nav_menu( rand_str() );
$request = new WP_REST_Request( 'POST', '/__experimental/menu-items' );
$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
$params = $this->set_menu_item_data(
array(
'menus' => $new_menu_id,
'parent' => $this->menu_item_id,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'invalid_item_parent', $response, 400 );
}

/**
*
*/
public function test_create_item_invalid_parent_post() {
wp_set_current_user( self::$admin_id );
$post_id = self::factory()->post->create();
$request = new WP_REST_Request( 'POST', '/__experimental/menu-items' );
$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
$params = $this->set_menu_item_data(
array(
'parent' => $post_id,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );
$this->assertErrorResponse( 'invalid_menu_item_parent', $response, 400 );
}

/**
*
*/
Expand Down Expand Up @@ -830,8 +800,13 @@ protected function check_menu_item_data( $post, $data, $context, $links ) {
$this->assertTrue( isset( $data[ $taxonomy->rest_base ] ) );
$terms = wp_get_object_terms( $post->ID, $taxonomy->name, array( 'fields' => 'ids' ) );
sort( $terms );
sort( $data[ $taxonomy->rest_base ] );
$this->assertEquals( $terms, $data[ $taxonomy->rest_base ] );
if ( 'nav_menu' === $taxonomy->name ) {
$term_id = $terms ? array_shift( $terms ) : 0;
$this->assertEquals( $term_id, $data[ $taxonomy->rest_base ] );
} else {
sort( $data[ $taxonomy->rest_base ] );
$this->assertEquals( $terms, $data[ $taxonomy->rest_base ] );
}
}

// test links.
Expand Down Expand Up @@ -908,7 +883,7 @@ protected function set_menu_item_data( $args = array() ) {
$defaults = array(
'object_id' => 0,
'parent' => 0,
'menu_order' => 0,
'menu_order' => 1,
'menus' => $this->menu_id,
'type' => 'custom',
'title' => 'Custom Link Title',
Expand Down

0 comments on commit 639a603

Please sign in to comment.