From 8a7495701f028731e6c5c2a96a93e431f15878ee Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Wed, 30 Jun 2021 10:40:21 +0000 Subject: [PATCH] REST API: Allow multiple widgets to be deleted in a single batch request. This resets the `WP_Widget::$updated` flag when deleting a widget, to avoid blocking all future updates in a request. Props noisysocks, andraganescu. Fixes #53557. git-svn-id: https://develop.svn.wordpress.org/trunk@51277 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-rest-widgets-controller.php | 24 +++++-- .../rest-api/rest-widgets-controller.php | 72 ++++++++++++++++--- 2 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php index 5fb9b8f6e1..9b97da4199 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php @@ -289,13 +289,14 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * * @since 5.8.0 * - * @global array $wp_registered_widget_updates The registered widget update functions. + * @global array $wp_registered_widget_updates The registered widget update functions. + * @global WP_Widget_Factory $wp_widget_factory * * @param WP_REST_Request $request Full details about the request. * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { - global $wp_registered_widget_updates; + global $wp_registered_widget_updates, $wp_widget_factory; retrieve_widgets(); @@ -344,6 +345,17 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { $_POST = $original_post; $_REQUEST = $original_request; + $widget_object = $wp_widget_factory->get_widget_object( $id_base ); + + if ( $widget_object ) { + /* + * WP_Widget sets `updated = true` after an update to prevent more than one widget + * from being saved per request. This isn't what we want in the REST API, though, + * as we support batch requests. + */ + $widget_object->updated = false; + } + wp_assign_widget_to_sidebar( $widget_id, '' ); $response->set_data( @@ -520,9 +532,11 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { $widget_object->_set( $number ); $widget_object->_register_one( $number ); - // WP_Widget sets updated = true after an update to prevent more - // than one widget from being saved per request. This isn't what we - // want in the REST API, though, as we support batch requests. + /* + * WP_Widget sets `updated = true` after an update to prevent more than one widget + * from being saved per request. This isn't what we want in the REST API, though, + * as we support batch requests. + */ $widget_object->updated = false; } diff --git a/tests/phpunit/tests/rest-api/rest-widgets-controller.php b/tests/phpunit/tests/rest-api/rest-widgets-controller.php index 594458598b..86d162f510 100644 --- a/tests/phpunit/tests/rest-api/rest-widgets-controller.php +++ b/tests/phpunit/tests/rest-api/rest-widgets-controller.php @@ -165,19 +165,20 @@ class WP_Test_REST_Widgets_Controller extends WP_Test_REST_Controller_Testcase { } private function setup_widget( $id_base, $number, $settings ) { + $this->setup_widgets( $id_base, array( $number => $settings ) ); + } + + private function setup_widgets( $id_base, $settings ) { global $wp_widget_factory; $option_name = "widget_$id_base"; - update_option( - $option_name, - array( - $number => $settings, - ) - ); + update_option( $option_name, $settings ); $widget_object = $wp_widget_factory->get_widget_object( $id_base ); - $widget_object->_set( $number ); - $widget_object->_register_one( $number ); + foreach ( array_keys( $settings ) as $number ) { + $widget_object->_set( $number ); + $widget_object->_register_one( $number ); + } } private function setup_sidebar( $id, $attrs = array(), $widgets = array() ) { @@ -1378,6 +1379,61 @@ class WP_Test_REST_Widgets_Controller extends WP_Test_REST_Controller_Testcase { $this->assertErrorResponse( 'rest_cannot_manage_widgets', $response, 403 ); } + /** + * @ticket 53557 + */ + public function test_delete_item_multiple() { + $this->setup_widgets( + 'text', + array( + 2 => array( 'text' => 'Text widget' ), + 3 => array( 'text' => 'Text widget' ), + 4 => array( 'text' => 'Text widget' ), + ) + ); + $this->setup_sidebar( + 'sidebar-1', + array( + 'name' => 'Test sidebar', + ), + array( 'text-2', 'text-3', 'text-4' ) + ); + + $request = new WP_REST_Request( 'POST', '/batch/v1' ); + $request->set_body_params( + array( + 'requests' => array( + array( + 'method' => 'DELETE', + 'path' => '/wp/v2/widgets/text-2?force=1', + ), + array( + 'method' => 'DELETE', + 'path' => '/wp/v2/widgets/text-3?force=1', + ), + array( + 'method' => 'DELETE', + 'path' => '/wp/v2/widgets/text-4?force=1', + ), + ), + ) + ); + $response = rest_do_request( $request ); + + $this->assertSame( + array( + 'sidebar-1' => array(), + ), + wp_get_sidebars_widgets() + ); + $this->assertSame( + array( + '_multiwidget' => 1, + ), + get_option( 'widget_text' ) + ); + } + /** * The test_prepare_item() method does not exist for sidebar. */