wp/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php
changeset 19 3d72ae0968f4
parent 18 be944660c56a
child 21 48c4eec2b7e6
--- 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;