Skip to content
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

Remove parent and position validation from menu item REST API endpoint #34672

Merged
merged 10 commits into from
Sep 14, 2021
46 changes: 3 additions & 43 deletions lib/class-wp-rest-menu-items-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -524,49 +524,9 @@ 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'] ) ) {
TimothyBJacobs marked this conversation as resolved.
Show resolved Hide resolved
// 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 ) );
}
}
// Check if nav menu is valid.
if ( ! empty( $prepared_nav_item['menu-id'] ) && ! is_nav_menu( $prepared_nav_item['menu-id'] ) ) {
return new WP_Error( 'invalid_menu_id', __( 'Invalid menu ID.', 'gutenberg' ), array( 'status' => 400 ) );
}

foreach ( array( 'menu-item-object-id', 'menu-item-parent-id' ) as $key ) {
Expand Down
90 changes: 0 additions & 90 deletions phpunit/class-rest-nav-menu-items-controller-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,59 +271,6 @@ public function test_create_item_invalid_term() {
$this->assertErrorResponse( 'rest_term_invalid_id', $response, 400 );
}

/**
*
*/
public function test_create_item_change_position() {
wp_set_current_user( self::$admin_id );
$new_menu_id = wp_create_nav_menu( rand_str() );
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,
)
);
$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 );
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this test be removed? It doesn't seem to trigger validation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It failed.

Copy link
Contributor

@adamziel adamziel Sep 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It failed because it resulted in the following sequence of positions: 0, 2, 3, 4, 5. According to https://core.trac.wordpress.org/ticket/28140, menu position 0 is invalid and breaks things so it would be good to get it fixed. I proposed an adjustment in 4e97c84 (feel free to roll it back) – what do you think @spacedmonkey ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be better change the schema to make the min 1 and default 1.

$schema['properties']['menu_order'] = array(
'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,
);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would also think about making the position a required field.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Yes, let's do that instead

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.


/**
*
*/
public function test_create_item_invalid_position() {
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(
'menu_order' => 1,
'menus' => $new_menu_id,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );
$this->check_create_menu_item_response( $response );
$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,
'menus' => $new_menu_id,
)
);
$request->set_body_params( $params );
$response = rest_get_server()->dispatch( $request );

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

/**
*
*/
Expand Down Expand Up @@ -380,43 +327,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