diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php index 2aad57ad54..fbc70fe331 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-sidebars-controller.php @@ -18,6 +18,14 @@ */ class WP_REST_Sidebars_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; + /** * Sidebars controller constructor. * @@ -86,6 +94,19 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { * @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(); + foreach ( wp_get_sidebars_widgets() as $id => $widgets ) { + $sidebar = $this->get_sidebar( $id ); + + if ( ! $sidebar ) { + continue; + } + + if ( $this->check_read_permission( $sidebar ) ) { + return true; + } + } + return $this->do_permissions_check(); } @@ -95,12 +116,14 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { * @since 5.8.0 * * @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. + * @return WP_REST_Response Response object on success. */ public function get_items( $request ) { - retrieve_widgets(); + $this->retrieve_widgets(); + + $data = array(); + $permissions_check = $this->do_permissions_check(); - $data = array(); foreach ( wp_get_sidebars_widgets() as $id => $widgets ) { $sidebar = $this->get_sidebar( $id ); @@ -108,6 +131,10 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { continue; } + if ( is_wp_error( $permissions_check ) && ! $this->check_read_permission( $sidebar ) ) { + continue; + } + $data[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $sidebar, $request ) ); @@ -125,9 +152,28 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { * @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(); + + $sidebar = $this->get_sidebar( $request['id'] ); + if ( $sidebar && $this->check_read_permission( $sidebar ) ) { + return true; + } + return $this->do_permissions_check(); } + /** + * Checks if a sidebar can be read publicly. + * + * @since 5.9.0 + * + * @param array $sidebar The registered sidebar configuration. + * @return bool Whether the side can be read. + */ + protected function check_read_permission( $sidebar ) { + return ! empty( $sidebar['show_in_rest'] ); + } + /** * Retrieves one sidebar from the collection. * @@ -137,10 +183,9 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { * @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(); $sidebar = $this->get_sidebar( $request['id'] ); - if ( ! $sidebar ) { return new WP_Error( 'rest_sidebar_not_found', __( 'No sidebar exists with that id.' ), array( 'status' => 404 ) ); } @@ -234,28 +279,25 @@ class WP_REST_Sidebars_Controller extends WP_REST_Controller { * * @since 5.8.0 * - * @global array $wp_registered_sidebars The registered sidebars. - * * @param string|int $id ID of the sidebar. * @return array|null The discovered sidebar, or null if it is not registered. */ protected function get_sidebar( $id ) { - global $wp_registered_sidebars; + return wp_get_sidebar( $id ); + } - foreach ( (array) $wp_registered_sidebars as $sidebar ) { - if ( $sidebar['id'] === $id ) { - return $sidebar; - } + /** + * 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; } - - if ( 'wp_inactive_widgets' === $id ) { - return array( - 'id' => 'wp_inactive_widgets', - 'name' => __( 'Inactive widgets' ), - ); - } - - return null; } /** diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php index 4c54620f50..6385be8ef8 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-widgets-controller.php @@ -16,6 +16,14 @@ */ 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; + /** * Widgets controller constructor. * @@ -97,6 +105,17 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * @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 +128,20 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * @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,9 +163,32 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * @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. * @@ -151,7 +198,7 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * @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 +294,7 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * 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 +369,7 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { * 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 ); @@ -439,6 +484,20 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { return true; } + /** + * 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. * @@ -767,23 +826,23 @@ class WP_REST_Widgets_Controller extends WP_REST_Controller { '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' ), ), ), ), diff --git a/wp-includes/version.php b/wp-includes/version.php index acb681e1d8..a9d1ddc3c5 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '5.9-alpha-52015'; +$wp_version = '5.9-alpha-52016'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-includes/widgets.php b/wp-includes/widgets.php index de15317d1b..56087c32f3 100644 --- a/wp-includes/widgets.php +++ b/wp-includes/widgets.php @@ -220,6 +220,7 @@ function register_sidebars( $number = 1, $args = array() ) { * * @since 2.2.0 * @since 5.6.0 Added the `before_sidebar` and `after_sidebar` arguments. + * @since 5.9.0 Added the `show_in_rest` argument. * * @global array $wp_registered_sidebars Registered sidebars. * @@ -250,6 +251,8 @@ function register_sidebars( $number = 1, $args = array() ) { * @type string $after_sidebar HTML content to append to the sidebar when displayed. * Outputs before the {@see 'dynamic_sidebar_after'} action. * Default empty string. + * @type bool $show_in_rest Whether to show this sidebar publicly in the REST API. + * Defaults to only showing the sidebar to administrator users. * } * @return string Sidebar ID added to $wp_registered_sidebars global. */ @@ -272,6 +275,7 @@ function register_sidebar( $args = array() ) { 'after_title' => "\n", 'before_sidebar' => '', 'after_sidebar' => '', + 'show_in_rest' => false, ); /** @@ -1035,6 +1039,35 @@ function wp_get_sidebars_widgets( $deprecated = true ) { return apply_filters( 'sidebars_widgets', $sidebars_widgets ); } +/** + * Retrieves the registered sidebar with the given id. + * + * @since 5.9.0 + * + * @global array $wp_registered_sidebars The registered sidebars. + * + * @param string $id The sidebar id. + * @return array|null The discovered sidebar, or null if it is not registered. + */ +function wp_get_sidebar( $id ) { + global $wp_registered_sidebars; + + foreach ( (array) $wp_registered_sidebars as $sidebar ) { + if ( $sidebar['id'] === $id ) { + return $sidebar; + } + } + + if ( 'wp_inactive_widgets' === $id ) { + return array( + 'id' => 'wp_inactive_widgets', + 'name' => __( 'Inactive widgets' ), + ); + } + + return null; +} + /** * Set the sidebar widget option to update sidebars. *