wp/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
    25 		$this->namespace = 'wp/v2';
    25 		$this->namespace = 'wp/v2';
    26 		$this->rest_base = 'themes';
    26 		$this->rest_base = 'themes';
    27 	}
    27 	}
    28 
    28 
    29 	/**
    29 	/**
    30 	 * Registers the routes for the objects of the controller.
    30 	 * Registers the routes for themes.
    31 	 *
    31 	 *
    32 	 * @since 5.0.0
    32 	 * @since 5.0.0
    33 	 *
    33 	 *
    34 	 * @see register_rest_route()
    34 	 * @see register_rest_route()
    35 	 */
    35 	 */
    45 					'args'                => $this->get_collection_params(),
    45 					'args'                => $this->get_collection_params(),
    46 				),
    46 				),
    47 				'schema' => array( $this, 'get_item_schema' ),
    47 				'schema' => array( $this, 'get_item_schema' ),
    48 			)
    48 			)
    49 		);
    49 		);
       
    50 
       
    51 		register_rest_route(
       
    52 			$this->namespace,
       
    53 			'/' . $this->rest_base . '/(?P<stylesheet>[\w-]+)',
       
    54 			array(
       
    55 				'args'   => array(
       
    56 					'stylesheet' => array(
       
    57 						'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ),
       
    58 						'type'        => 'string',
       
    59 					),
       
    60 				),
       
    61 				array(
       
    62 					'methods'             => WP_REST_Server::READABLE,
       
    63 					'callback'            => array( $this, 'get_item' ),
       
    64 					'permission_callback' => array( $this, 'get_item_permissions_check' ),
       
    65 				),
       
    66 				'schema' => array( $this, 'get_public_item_schema' ),
       
    67 			)
       
    68 		);
    50 	}
    69 	}
    51 
    70 
    52 	/**
    71 	/**
    53 	 * Checks if a given request has access to read the theme.
    72 	 * Checks if a given request has access to read the theme.
    54 	 *
    73 	 *
    56 	 *
    75 	 *
    57 	 * @param WP_REST_Request $request Full details about the request.
    76 	 * @param WP_REST_Request $request Full details about the request.
    58 	 * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object.
    77 	 * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object.
    59 	 */
    78 	 */
    60 	public function get_items_permissions_check( $request ) {
    79 	public function get_items_permissions_check( $request ) {
       
    80 		if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) {
       
    81 			return true;
       
    82 		}
       
    83 
       
    84 		$registered = $this->get_collection_params();
       
    85 		if ( isset( $registered['status'], $request['status'] ) && is_array( $request['status'] ) && array( 'active' ) === $request['status'] ) {
       
    86 			return $this->check_read_active_theme_permission();
       
    87 		}
       
    88 
       
    89 		return new WP_Error(
       
    90 			'rest_cannot_view_themes',
       
    91 			__( 'Sorry, you are not allowed to view themes.' ),
       
    92 			array( 'status' => rest_authorization_required_code() )
       
    93 		);
       
    94 	}
       
    95 
       
    96 	/**
       
    97 	 * Checks if a given request has access to read the theme.
       
    98 	 *
       
    99 	 * @since 5.7.0
       
   100 	 *
       
   101 	 * @param WP_REST_Request $request Full details about the request.
       
   102 	 * @return bool|WP_Error True if the request has read access for the item, otherwise WP_Error object.
       
   103 	 */
       
   104 	public function get_item_permissions_check( $request ) {
       
   105 		if ( current_user_can( 'switch_themes' ) || current_user_can( 'manage_network_themes' ) ) {
       
   106 			return true;
       
   107 		}
       
   108 
       
   109 		$wp_theme      = wp_get_theme( $request['stylesheet'] );
       
   110 		$current_theme = wp_get_theme();
       
   111 
       
   112 		if ( $this->is_same_theme( $wp_theme, $current_theme ) ) {
       
   113 			return $this->check_read_active_theme_permission();
       
   114 		}
       
   115 
       
   116 		return new WP_Error(
       
   117 			'rest_cannot_view_themes',
       
   118 			__( 'Sorry, you are not allowed to view themes.' ),
       
   119 			array( 'status' => rest_authorization_required_code() )
       
   120 		);
       
   121 	}
       
   122 
       
   123 	/**
       
   124 	 * Checks if a theme can be read.
       
   125 	 *
       
   126 	 * @since 5.7.0
       
   127 	 *
       
   128 	 * @return bool|WP_Error Whether the theme can be read.
       
   129 	 */
       
   130 	protected function check_read_active_theme_permission() {
    61 		if ( current_user_can( 'edit_posts' ) ) {
   131 		if ( current_user_can( 'edit_posts' ) ) {
    62 			return true;
   132 			return true;
    63 		}
   133 		}
    64 
   134 
    65 		foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
   135 		foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
    67 				return true;
   137 				return true;
    68 			}
   138 			}
    69 		}
   139 		}
    70 
   140 
    71 		return new WP_Error(
   141 		return new WP_Error(
    72 			'rest_user_cannot_view',
   142 			'rest_cannot_view_active_theme',
    73 			__( 'Sorry, you are not allowed to view themes.' ),
   143 			__( 'Sorry, you are not allowed to view the active theme.' ),
    74 			array( 'status' => rest_authorization_required_code() )
   144 			array( 'status' => rest_authorization_required_code() )
    75 		);
   145 		);
    76 	}
   146 	}
    77 
   147 
    78 	/**
   148 	/**
    79 	 * Retrieves a collection of themes.
   149 	 * Retrieves a single theme.
    80 	 *
   150 	 *
    81 	 * @since 5.0.0
   151 	 * @since 5.7.0
    82 	 *
   152 	 *
    83 	 * @param WP_REST_Request $request Full details about the request.
   153 	 * @param WP_REST_Request $request Full details about the request.
    84 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
   154 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
    85 	 */
   155 	 */
       
   156 	public function get_item( $request ) {
       
   157 		$wp_theme = wp_get_theme( $request['stylesheet'] );
       
   158 		if ( ! $wp_theme->exists() ) {
       
   159 			return new WP_Error(
       
   160 				'rest_theme_not_found',
       
   161 				__( 'Theme not found.' ),
       
   162 				array( 'status' => 404 )
       
   163 			);
       
   164 		}
       
   165 		$data = $this->prepare_item_for_response( $wp_theme, $request );
       
   166 
       
   167 		return rest_ensure_response( $data );
       
   168 	}
       
   169 
       
   170 	/**
       
   171 	 * Retrieves a collection of themes.
       
   172 	 *
       
   173 	 * @since 5.0.0
       
   174 	 *
       
   175 	 * @param WP_REST_Request $request Full details about the request.
       
   176 	 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
       
   177 	 */
    86 	public function get_items( $request ) {
   178 	public function get_items( $request ) {
    87 		// Retrieve the list of registered collection query parameters.
   179 		$themes = array();
    88 		$registered = $this->get_collection_params();
   180 
    89 		$themes     = array();
   181 		$active_themes = wp_get_themes();
    90 
   182 		$current_theme = wp_get_theme();
    91 		if ( isset( $registered['status'], $request['status'] ) && in_array( 'active', $request['status'], true ) ) {
   183 		$status        = $request['status'];
    92 			$active_theme = wp_get_theme();
   184 
    93 			$active_theme = $this->prepare_item_for_response( $active_theme, $request );
   185 		foreach ( $active_themes as $theme_name => $theme ) {
    94 			$themes[]     = $this->prepare_response_for_collection( $active_theme );
   186 			$theme_status = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive';
       
   187 			if ( is_array( $status ) && ! in_array( $theme_status, $status, true ) ) {
       
   188 				continue;
       
   189 			}
       
   190 
       
   191 			$prepared = $this->prepare_item_for_response( $theme, $request );
       
   192 			$themes[] = $this->prepare_response_for_collection( $prepared );
    95 		}
   193 		}
    96 
   194 
    97 		$response = rest_ensure_response( $themes );
   195 		$response = rest_ensure_response( $themes );
    98 
   196 
    99 		$response->header( 'X-WP-Total', count( $themes ) );
   197 		$response->header( 'X-WP-Total', count( $themes ) );
   100 		$response->header( 'X-WP-TotalPages', count( $themes ) );
   198 		$response->header( 'X-WP-TotalPages', 1 );
   101 
   199 
   102 		return $response;
   200 		return $response;
   103 	}
   201 	}
   104 
   202 
   105 	/**
   203 	/**
   164 			if ( rest_is_field_included( "{$field}.rendered", $fields ) ) {
   262 			if ( rest_is_field_included( "{$field}.rendered", $fields ) ) {
   165 				$data[ $field ]['rendered'] = $theme->display( $header );
   263 				$data[ $field ]['rendered'] = $theme->display( $header );
   166 			}
   264 			}
   167 		}
   265 		}
   168 
   266 
   169 		if ( rest_is_field_included( 'theme_supports', $fields ) ) {
   267 		$current_theme = wp_get_theme();
       
   268 		if ( rest_is_field_included( 'status', $fields ) ) {
       
   269 			$data['status'] = ( $this->is_same_theme( $theme, $current_theme ) ) ? 'active' : 'inactive';
       
   270 		}
       
   271 
       
   272 		if ( rest_is_field_included( 'theme_supports', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) {
   170 			foreach ( get_registered_theme_features() as $feature => $config ) {
   273 			foreach ( get_registered_theme_features() as $feature => $config ) {
   171 				if ( ! is_array( $config['show_in_rest'] ) ) {
   274 				if ( ! is_array( $config['show_in_rest'] ) ) {
   172 					continue;
   275 					continue;
   173 				}
   276 				}
   174 
   277 
   203 
   306 
   204 		$data = $this->add_additional_fields_to_object( $data, $request );
   307 		$data = $this->add_additional_fields_to_object( $data, $request );
   205 
   308 
   206 		// Wrap the data in a response object.
   309 		// Wrap the data in a response object.
   207 		$response = rest_ensure_response( $data );
   310 		$response = rest_ensure_response( $data );
       
   311 
       
   312 		$response->add_links( $this->prepare_links( $theme ) );
   208 
   313 
   209 		/**
   314 		/**
   210 		 * Filters theme data returned from the REST API.
   315 		 * Filters theme data returned from the REST API.
   211 		 *
   316 		 *
   212 		 * @since 5.0.0
   317 		 * @since 5.0.0
   217 		 */
   322 		 */
   218 		return apply_filters( 'rest_prepare_theme', $response, $theme, $request );
   323 		return apply_filters( 'rest_prepare_theme', $response, $theme, $request );
   219 	}
   324 	}
   220 
   325 
   221 	/**
   326 	/**
       
   327 	 * Prepares links for the request.
       
   328 	 *
       
   329 	 * @since 5.7.0
       
   330 	 *
       
   331 	 * @param WP_Theme $theme Theme data.
       
   332 	 * @return array Links for the given block type.
       
   333 	 */
       
   334 	protected function prepare_links( $theme ) {
       
   335 		return array(
       
   336 			'self'       => array(
       
   337 				'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $theme->get_stylesheet() ) ),
       
   338 			),
       
   339 			'collection' => array(
       
   340 				'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
       
   341 			),
       
   342 		);
       
   343 	}
       
   344 
       
   345 	/**
       
   346 	 * Helper function to compare two themes.
       
   347 	 *
       
   348 	 * @since 5.7.0
       
   349 	 *
       
   350 	 * @param WP_Theme $theme_a First theme to compare.
       
   351 	 * @param WP_Theme $theme_b Second theme to compare.
       
   352 	 * @return bool
       
   353 	 */
       
   354 	protected function is_same_theme( $theme_a, $theme_b ) {
       
   355 		return $theme_a->get_stylesheet() === $theme_b->get_stylesheet();
       
   356 	}
       
   357 
       
   358 	/**
   222 	 * Prepares the theme support value for inclusion in the REST API response.
   359 	 * Prepares the theme support value for inclusion in the REST API response.
   223 	 *
   360 	 *
   224 	 * @since 5.5.0
   361 	 * @since 5.5.0
   225 	 *
   362 	 *
   226 	 * @param mixed           $support The raw value from get_theme_support().
   363 	 * @param mixed           $support The raw value from get_theme_support().
   397 				'version'        => array(
   534 				'version'        => array(
   398 					'description' => __( 'The theme\'s current version.' ),
   535 					'description' => __( 'The theme\'s current version.' ),
   399 					'type'        => 'string',
   536 					'type'        => 'string',
   400 					'readonly'    => true,
   537 					'readonly'    => true,
   401 				),
   538 				),
       
   539 				'status'         => array(
       
   540 					'description' => __( 'A named status for the theme.' ),
       
   541 					'type'        => 'string',
       
   542 					'enum'        => array( 'inactive', 'active' ),
       
   543 				),
   402 			),
   544 			),
   403 		);
   545 		);
   404 
   546 
   405 		foreach ( get_registered_theme_features() as $feature => $config ) {
   547 		foreach ( get_registered_theme_features() as $feature => $config ) {
   406 			if ( ! is_array( $config['show_in_rest'] ) ) {
   548 			if ( ! is_array( $config['show_in_rest'] ) ) {
   423 	 * @since 5.0.0
   565 	 * @since 5.0.0
   424 	 *
   566 	 *
   425 	 * @return array Collection parameters.
   567 	 * @return array Collection parameters.
   426 	 */
   568 	 */
   427 	public function get_collection_params() {
   569 	public function get_collection_params() {
   428 		$query_params = parent::get_collection_params();
   570 		$query_params = array(
   429 
   571 			'status' => array(
   430 		$query_params['status'] = array(
   572 				'description' => __( 'Limit result set to themes assigned one or more statuses.' ),
   431 			'description'       => __( 'Limit result set to themes assigned one or more statuses.' ),
   573 				'type'        => 'array',
   432 			'type'              => 'array',
   574 				'items'       => array(
   433 			'items'             => array(
   575 					'enum' => array( 'active', 'inactive' ),
   434 				'enum' => array( 'active' ),
   576 					'type' => 'string',
   435 				'type' => 'string',
   577 				),
   436 			),
   578 			),
   437 			'required'          => true,
       
   438 			'sanitize_callback' => array( $this, 'sanitize_theme_status' ),
       
   439 		);
   579 		);
   440 
   580 
   441 		/**
   581 		/**
   442 		 * Filter collection parameters for the themes controller.
   582 		 * Filters REST API collection parameters for the themes controller.
   443 		 *
   583 		 *
   444 		 * @since 5.0.0
   584 		 * @since 5.0.0
   445 		 *
   585 		 *
   446 		 * @param array $query_params JSON Schema-formatted collection parameters.
   586 		 * @param array $query_params JSON Schema-formatted collection parameters.
   447 		 */
   587 		 */
   450 
   590 
   451 	/**
   591 	/**
   452 	 * Sanitizes and validates the list of theme status.
   592 	 * Sanitizes and validates the list of theme status.
   453 	 *
   593 	 *
   454 	 * @since 5.0.0
   594 	 * @since 5.0.0
       
   595 	 * @deprecated 5.7.0
   455 	 *
   596 	 *
   456 	 * @param string|array    $statuses  One or more theme statuses.
   597 	 * @param string|array    $statuses  One or more theme statuses.
   457 	 * @param WP_REST_Request $request   Full details about the request.
   598 	 * @param WP_REST_Request $request   Full details about the request.
   458 	 * @param string          $parameter Additional parameter to pass to validation.
   599 	 * @param string          $parameter Additional parameter to pass to validation.
   459 	 * @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
   600 	 * @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
   460 	 */
   601 	 */
   461 	public function sanitize_theme_status( $statuses, $request, $parameter ) {
   602 	public function sanitize_theme_status( $statuses, $request, $parameter ) {
       
   603 		_deprecated_function( __METHOD__, '5.7.0' );
       
   604 
   462 		$statuses = wp_parse_slug_list( $statuses );
   605 		$statuses = wp_parse_slug_list( $statuses );
   463 
   606 
   464 		foreach ( $statuses as $status ) {
   607 		foreach ( $statuses as $status ) {
   465 			$result = rest_validate_request_arg( $status, $request, $parameter );
   608 			$result = rest_validate_request_arg( $status, $request, $parameter );
   466 
   609