diff -r be944660c56a -r 3d72ae0968f4 wp/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php --- a/wp/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php Wed Sep 21 18:19:35 2022 +0200 +++ b/wp/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php Tue Sep 27 16:37:53 2022 +0200 @@ -17,6 +17,22 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { /** + * Tracks whether {@see retrieve_widgets()} has been called in the current request. + * + * @since 5.9.0 + * @var bool + */ + protected $widgets_retrieved = false; + + /** + * Whether the controller supports batching. + * + * @since 5.9.0 + * @var array + */ + protected $allow_batch = array( 'v1' => true ); + + /** * Widgets controller constructor. * * @since 5.8.0 @@ -48,7 +64,7 @@ 'permission_callback' => array( $this, 'create_item_permissions_check' ), 'args' => $this->get_endpoint_args_for_item_schema(), ), - 'allow_batch' => array( 'v1' => true ), + 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); @@ -82,7 +98,7 @@ ), ), ), - 'allow_batch' => array( 'v1' => true ), + 'allow_batch' => $this->allow_batch, 'schema' => array( $this, 'get_public_item_schema' ), ) ); @@ -97,6 +113,17 @@ * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_items_permissions_check( $request ) { + $this->retrieve_widgets(); + if ( isset( $request['sidebar'] ) && $this->check_read_sidebar_permission( $request['sidebar'] ) ) { + return true; + } + + foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { + if ( $this->check_read_sidebar_permission( $sidebar_id ) ) { + return true; + } + } + return $this->permissions_check( $request ); } @@ -109,15 +136,20 @@ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { - retrieve_widgets(); + $this->retrieve_widgets(); - $prepared = array(); + $prepared = array(); + $permissions_check = $this->permissions_check( $request ); foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) { if ( isset( $request['sidebar'] ) && $sidebar_id !== $request['sidebar'] ) { continue; } + if ( is_wp_error( $permissions_check ) && ! $this->check_read_sidebar_permission( $sidebar_id ) ) { + continue; + } + foreach ( $widget_ids as $widget_id ) { $response = $this->prepare_item_for_response( compact( 'sidebar_id', 'widget_id' ), $request ); @@ -139,10 +171,33 @@ * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ public function get_item_permissions_check( $request ) { + $this->retrieve_widgets(); + + $widget_id = $request['id']; + $sidebar_id = wp_find_widgets_sidebar( $widget_id ); + + if ( $sidebar_id && $this->check_read_sidebar_permission( $sidebar_id ) ) { + return true; + } + return $this->permissions_check( $request ); } /** + * Checks if a sidebar can be read publicly. + * + * @since 5.9.0 + * + * @param string $sidebar_id The sidebar ID. + * @return bool Whether the sidebar can be read. + */ + protected function check_read_sidebar_permission( $sidebar_id ) { + $sidebar = wp_get_sidebar( $sidebar_id ); + + return ! empty( $sidebar['show_in_rest'] ); + } + + /** * Gets an individual widget. * * @since 5.8.0 @@ -151,7 +206,7 @@ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function get_item( $request ) { - retrieve_widgets(); + $this->retrieve_widgets(); $widget_id = $request['id']; $sidebar_id = wp_find_widgets_sidebar( $widget_id ); @@ -247,8 +302,7 @@ * See https://core.trac.wordpress.org/ticket/53657. */ wp_get_sidebars_widgets(); - - retrieve_widgets(); + $this->retrieve_widgets(); $widget_id = $request['id']; $sidebar_id = wp_find_widgets_sidebar( $widget_id ); @@ -323,8 +377,7 @@ * See https://core.trac.wordpress.org/ticket/53657. */ wp_get_sidebars_widgets(); - - retrieve_widgets(); + $this->retrieve_widgets(); $widget_id = $request['id']; $sidebar_id = wp_find_widgets_sidebar( $widget_id ); @@ -407,10 +460,10 @@ * * @since 5.8.0 * - * @param string $widget_id ID of the widget marked for deletion. - * @param string $sidebar_id ID of the sidebar the widget was deleted from. - * @param WP_REST_Response $response The response data. - * @param WP_REST_Request $request The request sent to the API. + * @param string $widget_id ID of the widget marked for deletion. + * @param string $sidebar_id ID of the sidebar the widget was deleted from. + * @param WP_REST_Response|WP_Error $response The response data, or WP_Error object on failure. + * @param WP_REST_Request $request The request sent to the API. */ do_action( 'rest_delete_widget', $widget_id, $sidebar_id, $response, $request ); @@ -440,6 +493,20 @@ } /** + * Looks for "lost" widgets once per request. + * + * @since 5.9.0 + * + * @see retrieve_widgets() + */ + protected function retrieve_widgets() { + if ( ! $this->widgets_retrieved ) { + retrieve_widgets(); + $this->widgets_retrieved = true; + } + } + + /** * Saves the widget in the request object. * * @since 5.8.0 @@ -666,9 +733,9 @@ * * @since 5.8.0 * - * @param WP_REST_Response $response The response object. - * @param array $widget The registered widget data. - * @param WP_REST_Request $request Request used to generate the response. + * @param WP_REST_Response|WP_Error $response The response object, or WP_Error object on failure. + * @param array $widget The registered widget data. + * @param WP_REST_Request $request Request used to generate the response. */ return apply_filters( 'rest_prepare_widget', $response, $widget, $request ); } @@ -767,23 +834,23 @@ 'instance' => array( 'description' => __( 'Instance settings of the widget, if supported.' ), 'type' => 'object', - 'context' => array( 'view', 'edit', 'embed' ), + 'context' => array( 'edit' ), 'default' => null, 'properties' => array( 'encoded' => array( 'description' => __( 'Base64 encoded representation of the instance settings.' ), 'type' => 'string', - 'context' => array( 'view', 'edit', 'embed' ), + 'context' => array( 'edit' ), ), 'hash' => array( 'description' => __( 'Cryptographic hash of the instance settings.' ), 'type' => 'string', - 'context' => array( 'view', 'edit', 'embed' ), + 'context' => array( 'edit' ), ), 'raw' => array( 'description' => __( 'Unencoded instance settings, if supported.' ), 'type' => 'object', - 'context' => array( 'view', 'edit', 'embed' ), + 'context' => array( 'edit' ), ), ), ), @@ -792,7 +859,7 @@ 'type' => 'string', 'context' => array(), 'arg_options' => array( - 'sanitize_callback' => function( $string ) { + 'sanitize_callback' => static function( $string ) { $array = array(); wp_parse_str( $string, $array ); return $array;