--- a/wp/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php Tue Dec 15 15:52:01 2020 +0100
+++ b/wp/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php Wed Sep 21 18:19:35 2022 +0200
@@ -27,7 +27,7 @@
}
/**
- * Registers the routes for the objects of the controller.
+ * Registers the routes for themes.
*
* @since 5.0.0
*
@@ -47,6 +47,25 @@
'schema' => array( $this, 'get_item_schema' ),
)
);
+
+ register_rest_route(
+ $this->namespace,
+ '/' . $this->rest_base . '/(?P<stylesheet>[\w-]+)',
+ array(
+ 'args' => array(
+ 'stylesheet' => array(
+ 'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ),
+ 'type' => 'string',
+ ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_item' ),
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
}
/**
@@ -58,6 +77,57 @@
* @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object.
*/
public function get_items_permissions_check( $request ) {
+ if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) {
+ return true;
+ }
+
+ $registered = $this->get_collection_params();
+ if ( isset( $registered['status'], $request['status'] ) && is_array( $request['status'] ) && array( 'active' ) === $request['status'] ) {
+ return $this->check_read_active_theme_permission();
+ }
+
+ return new WP_Error(
+ 'rest_cannot_view_themes',
+ __( 'Sorry, you are not allowed to view themes.' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
+ /**
+ * Checks if a given request has access to read the theme.
+ *
+ * @since 5.7.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return bool|WP_Error True if the request has read access for the item, otherwise WP_Error object.
+ */
+ public function get_item_permissions_check( $request ) {
+ if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) {
+ return true;
+ }
+
+ $wp_theme = wp_get_theme( $request['stylesheet'] );
+ $current_theme = wp_get_theme();
+
+ if ( $this->is_same_theme( $wp_theme, $current_theme ) ) {
+ return $this->check_read_active_theme_permission();
+ }
+
+ return new WP_Error(
+ 'rest_cannot_view_themes',
+ __( 'Sorry, you are not allowed to view themes.' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
+ /**
+ * Checks if a theme can be read.
+ *
+ * @since 5.7.0
+ *
+ * @return bool|WP_Error Whether the theme can be read.
+ */
+ protected function check_read_active_theme_permission() {
if ( current_user_can( 'edit_posts' ) ) {
return true;
}
@@ -69,13 +139,35 @@
}
return new WP_Error(
- 'rest_user_cannot_view',
- __( 'Sorry, you are not allowed to view themes.' ),
+ 'rest_cannot_view_active_theme',
+ __( 'Sorry, you are not allowed to view the active theme.' ),
array( 'status' => rest_authorization_required_code() )
);
}
/**
+ * Retrieves a single theme.
+ *
+ * @since 5.7.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.
+ */
+ public function get_item( $request ) {
+ $wp_theme = wp_get_theme( $request['stylesheet'] );
+ if ( ! $wp_theme->exists() ) {
+ return new WP_Error(
+ 'rest_theme_not_found',
+ __( 'Theme not found.' ),
+ array( 'status' => 404 )
+ );
+ }
+ $data = $this->prepare_item_for_response( $wp_theme, $request );
+
+ return rest_ensure_response( $data );
+ }
+
+ /**
* Retrieves a collection of themes.
*
* @since 5.0.0
@@ -84,20 +176,26 @@
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_items( $request ) {
- // Retrieve the list of registered collection query parameters.
- $registered = $this->get_collection_params();
- $themes = array();
+ $themes = array();
+
+ $active_themes = wp_get_themes();
+ $current_theme = wp_get_theme();
+ $status = $request['status'];
- if ( isset( $registered['status'], $request['status'] ) && in_array( 'active', $request['status'], true ) ) {
- $active_theme = wp_get_theme();
- $active_theme = $this->prepare_item_for_response( $active_theme, $request );
- $themes[] = $this->prepare_response_for_collection( $active_theme );
+ foreach ( $active_themes as $theme_name => $theme ) {
+ $theme_status = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive';
+ if ( is_array( $status ) && ! in_array( $theme_status, $status, true ) ) {
+ continue;
+ }
+
+ $prepared = $this->prepare_item_for_response( $theme, $request );
+ $themes[] = $this->prepare_response_for_collection( $prepared );
}
$response = rest_ensure_response( $themes );
$response->header( 'X-WP-Total', count( $themes ) );
- $response->header( 'X-WP-TotalPages', count( $themes ) );
+ $response->header( 'X-WP-TotalPages', 1 );
return $response;
}
@@ -166,7 +264,12 @@
}
}
- if ( rest_is_field_included( 'theme_supports', $fields ) ) {
+ $current_theme = wp_get_theme();
+ if ( rest_is_field_included( 'status', $fields ) ) {
+ $data['status'] = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive';
+ }
+
+ if ( rest_is_field_included( 'theme_supports', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) {
foreach ( get_registered_theme_features() as $feature => $config ) {
if ( ! is_array( $config['show_in_rest'] ) ) {
continue;
@@ -206,6 +309,8 @@
// Wrap the data in a response object.
$response = rest_ensure_response( $data );
+ $response->add_links( $this->prepare_links( $theme ) );
+
/**
* Filters theme data returned from the REST API.
*
@@ -219,6 +324,38 @@
}
/**
+ * Prepares links for the request.
+ *
+ * @since 5.7.0
+ *
+ * @param WP_Theme $theme Theme data.
+ * @return array Links for the given block type.
+ */
+ protected function prepare_links( $theme ) {
+ return array(
+ 'self' => array(
+ 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $theme->get_stylesheet() ) ),
+ ),
+ 'collection' => array(
+ 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
+ ),
+ );
+ }
+
+ /**
+ * Helper function to compare two themes.
+ *
+ * @since 5.7.0
+ *
+ * @param WP_Theme $theme_a First theme to compare.
+ * @param WP_Theme $theme_b Second theme to compare.
+ * @return bool
+ */
+ protected function is_same_theme( $theme_a, $theme_b ) {
+ return $theme_a->get_stylesheet() === $theme_b->get_stylesheet();
+ }
+
+ /**
* Prepares the theme support value for inclusion in the REST API response.
*
* @since 5.5.0
@@ -399,6 +536,11 @@
'type' => 'string',
'readonly' => true,
),
+ 'status' => array(
+ 'description' => __( 'A named status for the theme.' ),
+ 'type' => 'string',
+ 'enum' => array( 'inactive', 'active' ),
+ ),
),
);
@@ -425,21 +567,19 @@
* @return array Collection parameters.
*/
public function get_collection_params() {
- $query_params = parent::get_collection_params();
-
- $query_params['status'] = array(
- 'description' => __( 'Limit result set to themes assigned one or more statuses.' ),
- 'type' => 'array',
- 'items' => array(
- 'enum' => array( 'active' ),
- 'type' => 'string',
+ $query_params = array(
+ 'status' => array(
+ 'description' => __( 'Limit result set to themes assigned one or more statuses.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'enum' => array( 'active', 'inactive' ),
+ 'type' => 'string',
+ ),
),
- 'required' => true,
- 'sanitize_callback' => array( $this, 'sanitize_theme_status' ),
);
/**
- * Filter collection parameters for the themes controller.
+ * Filters REST API collection parameters for the themes controller.
*
* @since 5.0.0
*
@@ -452,6 +592,7 @@
* Sanitizes and validates the list of theme status.
*
* @since 5.0.0
+ * @deprecated 5.7.0
*
* @param string|array $statuses One or more theme statuses.
* @param WP_REST_Request $request Full details about the request.
@@ -459,6 +600,8 @@
* @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
*/
public function sanitize_theme_status( $statuses, $request, $parameter ) {
+ _deprecated_function( __METHOD__, '5.7.0' );
+
$statuses = wp_parse_slug_list( $statuses );
foreach ( $statuses as $status ) {