wp/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php
changeset 19 3d72ae0968f4
parent 18 be944660c56a
child 21 48c4eec2b7e6
equal deleted inserted replaced
18:be944660c56a 19:3d72ae0968f4
    13  * @since 5.8.0
    13  * @since 5.8.0
    14  *
    14  *
    15  * @see WP_REST_Controller
    15  * @see WP_REST_Controller
    16  */
    16  */
    17 class WP_REST_Widgets_Controller extends WP_REST_Controller {
    17 class WP_REST_Widgets_Controller extends WP_REST_Controller {
       
    18 
       
    19 	/**
       
    20 	 * Tracks whether {@see retrieve_widgets()} has been called in the current request.
       
    21 	 *
       
    22 	 * @since 5.9.0
       
    23 	 * @var bool
       
    24 	 */
       
    25 	protected $widgets_retrieved = false;
       
    26 
       
    27 	/**
       
    28 	 * Whether the controller supports batching.
       
    29 	 *
       
    30 	 * @since 5.9.0
       
    31 	 * @var array
       
    32 	 */
       
    33 	protected $allow_batch = array( 'v1' => true );
    18 
    34 
    19 	/**
    35 	/**
    20 	 * Widgets controller constructor.
    36 	 * Widgets controller constructor.
    21 	 *
    37 	 *
    22 	 * @since 5.8.0
    38 	 * @since 5.8.0
    46 					'methods'             => WP_REST_Server::CREATABLE,
    62 					'methods'             => WP_REST_Server::CREATABLE,
    47 					'callback'            => array( $this, 'create_item' ),
    63 					'callback'            => array( $this, 'create_item' ),
    48 					'permission_callback' => array( $this, 'create_item_permissions_check' ),
    64 					'permission_callback' => array( $this, 'create_item_permissions_check' ),
    49 					'args'                => $this->get_endpoint_args_for_item_schema(),
    65 					'args'                => $this->get_endpoint_args_for_item_schema(),
    50 				),
    66 				),
    51 				'allow_batch' => array( 'v1' => true ),
    67 				'allow_batch' => $this->allow_batch,
    52 				'schema'      => array( $this, 'get_public_item_schema' ),
    68 				'schema'      => array( $this, 'get_public_item_schema' ),
    53 			)
    69 			)
    54 		);
    70 		);
    55 
    71 
    56 		register_rest_route(
    72 		register_rest_route(
    80 							'description' => __( 'Whether to force removal of the widget, or move it to the inactive sidebar.' ),
    96 							'description' => __( 'Whether to force removal of the widget, or move it to the inactive sidebar.' ),
    81 							'type'        => 'boolean',
    97 							'type'        => 'boolean',
    82 						),
    98 						),
    83 					),
    99 					),
    84 				),
   100 				),
    85 				'allow_batch' => array( 'v1' => true ),
   101 				'allow_batch' => $this->allow_batch,
    86 				'schema'      => array( $this, 'get_public_item_schema' ),
   102 				'schema'      => array( $this, 'get_public_item_schema' ),
    87 			)
   103 			)
    88 		);
   104 		);
    89 	}
   105 	}
    90 
   106 
    95 	 *
   111 	 *
    96 	 * @param WP_REST_Request $request Full details about the request.
   112 	 * @param WP_REST_Request $request Full details about the request.
    97 	 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
   113 	 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
    98 	 */
   114 	 */
    99 	public function get_items_permissions_check( $request ) {
   115 	public function get_items_permissions_check( $request ) {
       
   116 		$this->retrieve_widgets();
       
   117 		if ( isset( $request['sidebar'] ) && $this->check_read_sidebar_permission( $request['sidebar'] ) ) {
       
   118 			return true;
       
   119 		}
       
   120 
       
   121 		foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) {
       
   122 			if ( $this->check_read_sidebar_permission( $sidebar_id ) ) {
       
   123 				return true;
       
   124 			}
       
   125 		}
       
   126 
   100 		return $this->permissions_check( $request );
   127 		return $this->permissions_check( $request );
   101 	}
   128 	}
   102 
   129 
   103 	/**
   130 	/**
   104 	 * Retrieves a collection of widgets.
   131 	 * Retrieves a collection of widgets.
   107 	 *
   134 	 *
   108 	 * @param WP_REST_Request $request Full details about the request.
   135 	 * @param WP_REST_Request $request Full details about the request.
   109 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   136 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   110 	 */
   137 	 */
   111 	public function get_items( $request ) {
   138 	public function get_items( $request ) {
   112 		retrieve_widgets();
   139 		$this->retrieve_widgets();
   113 
   140 
   114 		$prepared = array();
   141 		$prepared          = array();
       
   142 		$permissions_check = $this->permissions_check( $request );
   115 
   143 
   116 		foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) {
   144 		foreach ( wp_get_sidebars_widgets() as $sidebar_id => $widget_ids ) {
   117 			if ( isset( $request['sidebar'] ) && $sidebar_id !== $request['sidebar'] ) {
   145 			if ( isset( $request['sidebar'] ) && $sidebar_id !== $request['sidebar'] ) {
   118 				continue;
   146 				continue;
   119 			}
   147 			}
   120 
   148 
       
   149 			if ( is_wp_error( $permissions_check ) && ! $this->check_read_sidebar_permission( $sidebar_id ) ) {
       
   150 				continue;
       
   151 			}
       
   152 
   121 			foreach ( $widget_ids as $widget_id ) {
   153 			foreach ( $widget_ids as $widget_id ) {
   122 				$response = $this->prepare_item_for_response( compact( 'sidebar_id', 'widget_id' ), $request );
   154 				$response = $this->prepare_item_for_response( compact( 'sidebar_id', 'widget_id' ), $request );
   123 
   155 
   124 				if ( ! is_wp_error( $response ) ) {
   156 				if ( ! is_wp_error( $response ) ) {
   125 					$prepared[] = $this->prepare_response_for_collection( $response );
   157 					$prepared[] = $this->prepare_response_for_collection( $response );
   137 	 *
   169 	 *
   138 	 * @param WP_REST_Request $request Full details about the request.
   170 	 * @param WP_REST_Request $request Full details about the request.
   139 	 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
   171 	 * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
   140 	 */
   172 	 */
   141 	public function get_item_permissions_check( $request ) {
   173 	public function get_item_permissions_check( $request ) {
       
   174 		$this->retrieve_widgets();
       
   175 
       
   176 		$widget_id  = $request['id'];
       
   177 		$sidebar_id = wp_find_widgets_sidebar( $widget_id );
       
   178 
       
   179 		if ( $sidebar_id && $this->check_read_sidebar_permission( $sidebar_id ) ) {
       
   180 			return true;
       
   181 		}
       
   182 
   142 		return $this->permissions_check( $request );
   183 		return $this->permissions_check( $request );
   143 	}
   184 	}
   144 
   185 
   145 	/**
   186 	/**
       
   187 	 * Checks if a sidebar can be read publicly.
       
   188 	 *
       
   189 	 * @since 5.9.0
       
   190 	 *
       
   191 	 * @param string $sidebar_id The sidebar ID.
       
   192 	 * @return bool Whether the sidebar can be read.
       
   193 	 */
       
   194 	protected function check_read_sidebar_permission( $sidebar_id ) {
       
   195 		$sidebar = wp_get_sidebar( $sidebar_id );
       
   196 
       
   197 		return ! empty( $sidebar['show_in_rest'] );
       
   198 	}
       
   199 
       
   200 	/**
   146 	 * Gets an individual widget.
   201 	 * Gets an individual widget.
   147 	 *
   202 	 *
   148 	 * @since 5.8.0
   203 	 * @since 5.8.0
   149 	 *
   204 	 *
   150 	 * @param WP_REST_Request $request Full details about the request.
   205 	 * @param WP_REST_Request $request Full details about the request.
   151 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   206 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   152 	 */
   207 	 */
   153 	public function get_item( $request ) {
   208 	public function get_item( $request ) {
   154 		retrieve_widgets();
   209 		$this->retrieve_widgets();
   155 
   210 
   156 		$widget_id  = $request['id'];
   211 		$widget_id  = $request['id'];
   157 		$sidebar_id = wp_find_widgets_sidebar( $widget_id );
   212 		$sidebar_id = wp_find_widgets_sidebar( $widget_id );
   158 
   213 
   159 		if ( is_null( $sidebar_id ) ) {
   214 		if ( is_null( $sidebar_id ) ) {
   245 		 * sidebar.
   300 		 * sidebar.
   246 		 *
   301 		 *
   247 		 * See https://core.trac.wordpress.org/ticket/53657.
   302 		 * See https://core.trac.wordpress.org/ticket/53657.
   248 		 */
   303 		 */
   249 		wp_get_sidebars_widgets();
   304 		wp_get_sidebars_widgets();
   250 
   305 		$this->retrieve_widgets();
   251 		retrieve_widgets();
       
   252 
   306 
   253 		$widget_id  = $request['id'];
   307 		$widget_id  = $request['id'];
   254 		$sidebar_id = wp_find_widgets_sidebar( $widget_id );
   308 		$sidebar_id = wp_find_widgets_sidebar( $widget_id );
   255 
   309 
   256 		// Allow sidebar to be unset or missing when widget is not a WP_Widget.
   310 		// Allow sidebar to be unset or missing when widget is not a WP_Widget.
   321 		 * sidebar.
   375 		 * sidebar.
   322 		 *
   376 		 *
   323 		 * See https://core.trac.wordpress.org/ticket/53657.
   377 		 * See https://core.trac.wordpress.org/ticket/53657.
   324 		 */
   378 		 */
   325 		wp_get_sidebars_widgets();
   379 		wp_get_sidebars_widgets();
   326 
   380 		$this->retrieve_widgets();
   327 		retrieve_widgets();
       
   328 
   381 
   329 		$widget_id  = $request['id'];
   382 		$widget_id  = $request['id'];
   330 		$sidebar_id = wp_find_widgets_sidebar( $widget_id );
   383 		$sidebar_id = wp_find_widgets_sidebar( $widget_id );
   331 
   384 
   332 		if ( is_null( $sidebar_id ) ) {
   385 		if ( is_null( $sidebar_id ) ) {
   405 		/**
   458 		/**
   406 		 * Fires after a widget is deleted via the REST API.
   459 		 * Fires after a widget is deleted via the REST API.
   407 		 *
   460 		 *
   408 		 * @since 5.8.0
   461 		 * @since 5.8.0
   409 		 *
   462 		 *
   410 		 * @param string           $widget_id  ID of the widget marked for deletion.
   463 		 * @param string                    $widget_id  ID of the widget marked for deletion.
   411 		 * @param string           $sidebar_id ID of the sidebar the widget was deleted from.
   464 		 * @param string                    $sidebar_id ID of the sidebar the widget was deleted from.
   412 		 * @param WP_REST_Response $response   The response data.
   465 		 * @param WP_REST_Response|WP_Error $response   The response data, or WP_Error object on failure.
   413 		 * @param WP_REST_Request  $request    The request sent to the API.
   466 		 * @param WP_REST_Request           $request    The request sent to the API.
   414 		 */
   467 		 */
   415 		do_action( 'rest_delete_widget', $widget_id, $sidebar_id, $response, $request );
   468 		do_action( 'rest_delete_widget', $widget_id, $sidebar_id, $response, $request );
   416 
   469 
   417 		return $response;
   470 		return $response;
   418 	}
   471 	}
   435 				)
   488 				)
   436 			);
   489 			);
   437 		}
   490 		}
   438 
   491 
   439 		return true;
   492 		return true;
       
   493 	}
       
   494 
       
   495 	/**
       
   496 	 * Looks for "lost" widgets once per request.
       
   497 	 *
       
   498 	 * @since 5.9.0
       
   499 	 *
       
   500 	 * @see retrieve_widgets()
       
   501 	 */
       
   502 	protected function retrieve_widgets() {
       
   503 		if ( ! $this->widgets_retrieved ) {
       
   504 			retrieve_widgets();
       
   505 			$this->widgets_retrieved = true;
       
   506 		}
   440 	}
   507 	}
   441 
   508 
   442 	/**
   509 	/**
   443 	 * Saves the widget in the request object.
   510 	 * Saves the widget in the request object.
   444 	 *
   511 	 *
   664 		/**
   731 		/**
   665 		 * Filters the REST API response for a widget.
   732 		 * Filters the REST API response for a widget.
   666 		 *
   733 		 *
   667 		 * @since 5.8.0
   734 		 * @since 5.8.0
   668 		 *
   735 		 *
   669 		 * @param WP_REST_Response $response The response object.
   736 		 * @param WP_REST_Response|WP_Error $response The response object, or WP_Error object on failure.
   670 		 * @param array            $widget   The registered widget data.
   737 		 * @param array                     $widget   The registered widget data.
   671 		 * @param WP_REST_Request  $request  Request used to generate the response.
   738 		 * @param WP_REST_Request           $request  Request used to generate the response.
   672 		 */
   739 		 */
   673 		return apply_filters( 'rest_prepare_widget', $response, $widget, $request );
   740 		return apply_filters( 'rest_prepare_widget', $response, $widget, $request );
   674 	}
   741 	}
   675 
   742 
   676 	/**
   743 	/**
   765 					'readonly'    => true,
   832 					'readonly'    => true,
   766 				),
   833 				),
   767 				'instance'      => array(
   834 				'instance'      => array(
   768 					'description' => __( 'Instance settings of the widget, if supported.' ),
   835 					'description' => __( 'Instance settings of the widget, if supported.' ),
   769 					'type'        => 'object',
   836 					'type'        => 'object',
   770 					'context'     => array( 'view', 'edit', 'embed' ),
   837 					'context'     => array( 'edit' ),
   771 					'default'     => null,
   838 					'default'     => null,
   772 					'properties'  => array(
   839 					'properties'  => array(
   773 						'encoded' => array(
   840 						'encoded' => array(
   774 							'description' => __( 'Base64 encoded representation of the instance settings.' ),
   841 							'description' => __( 'Base64 encoded representation of the instance settings.' ),
   775 							'type'        => 'string',
   842 							'type'        => 'string',
   776 							'context'     => array( 'view', 'edit', 'embed' ),
   843 							'context'     => array( 'edit' ),
   777 						),
   844 						),
   778 						'hash'    => array(
   845 						'hash'    => array(
   779 							'description' => __( 'Cryptographic hash of the instance settings.' ),
   846 							'description' => __( 'Cryptographic hash of the instance settings.' ),
   780 							'type'        => 'string',
   847 							'type'        => 'string',
   781 							'context'     => array( 'view', 'edit', 'embed' ),
   848 							'context'     => array( 'edit' ),
   782 						),
   849 						),
   783 						'raw'     => array(
   850 						'raw'     => array(
   784 							'description' => __( 'Unencoded instance settings, if supported.' ),
   851 							'description' => __( 'Unencoded instance settings, if supported.' ),
   785 							'type'        => 'object',
   852 							'type'        => 'object',
   786 							'context'     => array( 'view', 'edit', 'embed' ),
   853 							'context'     => array( 'edit' ),
   787 						),
   854 						),
   788 					),
   855 					),
   789 				),
   856 				),
   790 				'form_data'     => array(
   857 				'form_data'     => array(
   791 					'description' => __( 'URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.' ),
   858 					'description' => __( 'URL-encoded form data from the widget admin form. Used to update a widget that does not support instance. Write only.' ),
   792 					'type'        => 'string',
   859 					'type'        => 'string',
   793 					'context'     => array(),
   860 					'context'     => array(),
   794 					'arg_options' => array(
   861 					'arg_options' => array(
   795 						'sanitize_callback' => function( $string ) {
   862 						'sanitize_callback' => static function( $string ) {
   796 							$array = array();
   863 							$array = array();
   797 							wp_parse_str( $string, $array );
   864 							wp_parse_str( $string, $array );
   798 							return $array;
   865 							return $array;
   799 						},
   866 						},
   800 					),
   867 					),