wp/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    56 	 *
    56 	 *
    57 	 * @param WP_REST_Request $request Full details about the request.
    57 	 * @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.
    58 	 * @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object.
    59 	 */
    59 	 */
    60 	public function get_items_permissions_check( $request ) {
    60 	public function get_items_permissions_check( $request ) {
    61 		if ( ! is_user_logged_in() || ! current_user_can( 'edit_posts' ) ) {
    61 		if ( current_user_can( 'edit_posts' ) ) {
    62 			return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you are not allowed to view themes.' ), array( 'status' => rest_authorization_required_code() ) );
    62 			return true;
    63 		}
    63 		}
    64 
    64 
    65 		return true;
    65 		foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
       
    66 			if ( current_user_can( $post_type->cap->edit_posts ) ) {
       
    67 				return true;
       
    68 			}
       
    69 		}
       
    70 
       
    71 		return new WP_Error(
       
    72 			'rest_user_cannot_view',
       
    73 			__( 'Sorry, you are not allowed to view themes.' ),
       
    74 			array( 'status' => rest_authorization_required_code() )
       
    75 		);
    66 	}
    76 	}
    67 
    77 
    68 	/**
    78 	/**
    69 	 * Retrieves a collection of themes.
    79 	 * Retrieves a collection of themes.
    70 	 *
    80 	 *
   103 	 */
   113 	 */
   104 	public function prepare_item_for_response( $theme, $request ) {
   114 	public function prepare_item_for_response( $theme, $request ) {
   105 		$data   = array();
   115 		$data   = array();
   106 		$fields = $this->get_fields_for_response( $request );
   116 		$fields = $this->get_fields_for_response( $request );
   107 
   117 
   108 		if ( in_array( 'theme_supports', $fields, true ) ) {
   118 		if ( rest_is_field_included( 'stylesheet', $fields ) ) {
   109 			$formats                           = get_theme_support( 'post-formats' );
   119 			$data['stylesheet'] = $theme->get_stylesheet();
   110 			$formats                           = is_array( $formats ) ? array_values( $formats[0] ) : array();
   120 		}
   111 			$formats                           = array_merge( array( 'standard' ), $formats );
   121 
   112 			$data['theme_supports']['formats'] = $formats;
   122 		if ( rest_is_field_included( 'template', $fields ) ) {
   113 
   123 			/**
   114 			$data['theme_supports']['post-thumbnails']   = false;
   124 			 * Use the get_template() method, not the 'Template' header, for finding the template.
   115 			$data['theme_supports']['responsive-embeds'] = (bool) get_theme_support( 'responsive-embeds' );
   125 			 * The 'Template' header is only good for what was written in the style.css, while
   116 			$post_thumbnails                             = get_theme_support( 'post-thumbnails' );
   126 			 * get_template() takes into account where WordPress actually located the theme and
   117 
   127 			 * whether it is actually valid.
   118 			if ( $post_thumbnails ) {
   128 			 */
   119 				// $post_thumbnails can contain a nested array of post types.
   129 			$data['template'] = $theme->get_template();
   120 				// e.g. array( array( 'post', 'page' ) ).
   130 		}
   121 				$data['theme_supports']['post-thumbnails'] = is_array( $post_thumbnails ) ? $post_thumbnails[0] : true;
   131 
       
   132 		$plain_field_mappings = array(
       
   133 			'requires_php' => 'RequiresPHP',
       
   134 			'requires_wp'  => 'RequiresWP',
       
   135 			'textdomain'   => 'TextDomain',
       
   136 			'version'      => 'Version',
       
   137 		);
       
   138 
       
   139 		foreach ( $plain_field_mappings as $field => $header ) {
       
   140 			if ( rest_is_field_included( $field, $fields ) ) {
       
   141 				$data[ $field ] = $theme->get( $header );
       
   142 			}
       
   143 		}
       
   144 
       
   145 		if ( rest_is_field_included( 'screenshot', $fields ) ) {
       
   146 			// Using $theme->get_screenshot() with no args to get absolute URL.
       
   147 			$data['screenshot'] = $theme->get_screenshot() ? $theme->get_screenshot() : '';
       
   148 		}
       
   149 
       
   150 		$rich_field_mappings = array(
       
   151 			'author'      => 'Author',
       
   152 			'author_uri'  => 'AuthorURI',
       
   153 			'description' => 'Description',
       
   154 			'name'        => 'Name',
       
   155 			'tags'        => 'Tags',
       
   156 			'theme_uri'   => 'ThemeURI',
       
   157 		);
       
   158 
       
   159 		foreach ( $rich_field_mappings as $field => $header ) {
       
   160 			if ( rest_is_field_included( "{$field}.raw", $fields ) ) {
       
   161 				$data[ $field ]['raw'] = $theme->display( $header, false, true );
       
   162 			}
       
   163 
       
   164 			if ( rest_is_field_included( "{$field}.rendered", $fields ) ) {
       
   165 				$data[ $field ]['rendered'] = $theme->display( $header );
       
   166 			}
       
   167 		}
       
   168 
       
   169 		if ( rest_is_field_included( 'theme_supports', $fields ) ) {
       
   170 			foreach ( get_registered_theme_features() as $feature => $config ) {
       
   171 				if ( ! is_array( $config['show_in_rest'] ) ) {
       
   172 					continue;
       
   173 				}
       
   174 
       
   175 				$name = $config['show_in_rest']['name'];
       
   176 
       
   177 				if ( ! rest_is_field_included( "theme_supports.{$name}", $fields ) ) {
       
   178 					continue;
       
   179 				}
       
   180 
       
   181 				if ( ! current_theme_supports( $feature ) ) {
       
   182 					$data['theme_supports'][ $name ] = $config['show_in_rest']['schema']['default'];
       
   183 					continue;
       
   184 				}
       
   185 
       
   186 				$support = get_theme_support( $feature );
       
   187 
       
   188 				if ( isset( $config['show_in_rest']['prepare_callback'] ) ) {
       
   189 					$prepare = $config['show_in_rest']['prepare_callback'];
       
   190 				} else {
       
   191 					$prepare = array( $this, 'prepare_theme_support' );
       
   192 				}
       
   193 
       
   194 				$prepared = $prepare( $support, $config, $feature, $request );
       
   195 
       
   196 				if ( is_wp_error( $prepared ) ) {
       
   197 					continue;
       
   198 				}
       
   199 
       
   200 				$data['theme_supports'][ $name ] = $prepared;
   122 			}
   201 			}
   123 		}
   202 		}
   124 
   203 
   125 		$data = $this->add_additional_fields_to_object( $data, $request );
   204 		$data = $this->add_additional_fields_to_object( $data, $request );
   126 
   205 
   138 		 */
   217 		 */
   139 		return apply_filters( 'rest_prepare_theme', $response, $theme, $request );
   218 		return apply_filters( 'rest_prepare_theme', $response, $theme, $request );
   140 	}
   219 	}
   141 
   220 
   142 	/**
   221 	/**
       
   222 	 * Prepares the theme support value for inclusion in the REST API response.
       
   223 	 *
       
   224 	 * @since 5.5.0
       
   225 	 *
       
   226 	 * @param mixed           $support The raw value from get_theme_support().
       
   227 	 * @param array           $args    The feature's registration args.
       
   228 	 * @param string          $feature The feature name.
       
   229 	 * @param WP_REST_Request $request The request object.
       
   230 	 * @return mixed The prepared support value.
       
   231 	 */
       
   232 	protected function prepare_theme_support( $support, $args, $feature, $request ) {
       
   233 		$schema = $args['show_in_rest']['schema'];
       
   234 
       
   235 		if ( 'boolean' === $schema['type'] ) {
       
   236 			return true;
       
   237 		}
       
   238 
       
   239 		if ( is_array( $support ) && ! $args['variadic'] ) {
       
   240 			$support = $support[0];
       
   241 		}
       
   242 
       
   243 		return rest_sanitize_value_from_schema( $support, $schema );
       
   244 	}
       
   245 
       
   246 	/**
   143 	 * Retrieves the theme's schema, conforming to JSON Schema.
   247 	 * Retrieves the theme's schema, conforming to JSON Schema.
   144 	 *
   248 	 *
   145 	 * @since 5.0.0
   249 	 * @since 5.0.0
   146 	 *
   250 	 *
   147 	 * @return array Item schema data.
   251 	 * @return array Item schema data.
   148 	 */
   252 	 */
   149 	public function get_item_schema() {
   253 	public function get_item_schema() {
       
   254 		if ( $this->schema ) {
       
   255 			return $this->add_additional_fields_schema( $this->schema );
       
   256 		}
       
   257 
   150 		$schema = array(
   258 		$schema = array(
   151 			'$schema'    => 'http://json-schema.org/draft-04/schema#',
   259 			'$schema'    => 'http://json-schema.org/draft-04/schema#',
   152 			'title'      => 'theme',
   260 			'title'      => 'theme',
   153 			'type'       => 'object',
   261 			'type'       => 'object',
   154 			'properties' => array(
   262 			'properties' => array(
       
   263 				'stylesheet'     => array(
       
   264 					'description' => __( 'The theme\'s stylesheet. This uniquely identifies the theme.' ),
       
   265 					'type'        => 'string',
       
   266 					'readonly'    => true,
       
   267 				),
       
   268 				'template'       => array(
       
   269 					'description' => __( 'The theme\'s template. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet.' ),
       
   270 					'type'        => 'string',
       
   271 					'readonly'    => true,
       
   272 				),
       
   273 				'author'         => array(
       
   274 					'description' => __( 'The theme author.' ),
       
   275 					'type'        => 'object',
       
   276 					'readonly'    => true,
       
   277 					'properties'  => array(
       
   278 						'raw'      => array(
       
   279 							'description' => __( 'The theme author\'s name, as found in the theme header.' ),
       
   280 							'type'        => 'string',
       
   281 						),
       
   282 						'rendered' => array(
       
   283 							'description' => __( 'HTML for the theme author, transformed for display.' ),
       
   284 							'type'        => 'string',
       
   285 						),
       
   286 					),
       
   287 				),
       
   288 				'author_uri'     => array(
       
   289 					'description' => __( 'The website of the theme author.' ),
       
   290 					'type'        => 'object',
       
   291 					'readonly'    => true,
       
   292 					'properties'  => array(
       
   293 						'raw'      => array(
       
   294 							'description' => __( 'The website of the theme author, as found in the theme header.' ),
       
   295 							'type'        => 'string',
       
   296 							'format'      => 'uri',
       
   297 						),
       
   298 						'rendered' => array(
       
   299 							'description' => __( 'The website of the theme author, transformed for display.' ),
       
   300 							'type'        => 'string',
       
   301 							'format'      => 'uri',
       
   302 						),
       
   303 					),
       
   304 				),
       
   305 				'description'    => array(
       
   306 					'description' => __( 'A description of the theme.' ),
       
   307 					'type'        => 'object',
       
   308 					'readonly'    => true,
       
   309 					'properties'  => array(
       
   310 						'raw'      => array(
       
   311 							'description' => __( 'The theme description, as found in the theme header.' ),
       
   312 							'type'        => 'string',
       
   313 						),
       
   314 						'rendered' => array(
       
   315 							'description' => __( 'The theme description, transformed for display.' ),
       
   316 							'type'        => 'string',
       
   317 						),
       
   318 					),
       
   319 				),
       
   320 				'name'           => array(
       
   321 					'description' => __( 'The name of the theme.' ),
       
   322 					'type'        => 'object',
       
   323 					'readonly'    => true,
       
   324 					'properties'  => array(
       
   325 						'raw'      => array(
       
   326 							'description' => __( 'The theme name, as found in the theme header.' ),
       
   327 							'type'        => 'string',
       
   328 						),
       
   329 						'rendered' => array(
       
   330 							'description' => __( 'The theme name, transformed for display.' ),
       
   331 							'type'        => 'string',
       
   332 						),
       
   333 					),
       
   334 				),
       
   335 				'requires_php'   => array(
       
   336 					'description' => __( 'The minimum PHP version required for the theme to work.' ),
       
   337 					'type'        => 'string',
       
   338 					'readonly'    => true,
       
   339 				),
       
   340 				'requires_wp'    => array(
       
   341 					'description' => __( 'The minimum WordPress version required for the theme to work.' ),
       
   342 					'type'        => 'string',
       
   343 					'readonly'    => true,
       
   344 				),
       
   345 				'screenshot'     => array(
       
   346 					'description' => __( 'The theme\'s screenshot URL.' ),
       
   347 					'type'        => 'string',
       
   348 					'format'      => 'uri',
       
   349 					'readonly'    => true,
       
   350 				),
       
   351 				'tags'           => array(
       
   352 					'description' => __( 'Tags indicating styles and features of the theme.' ),
       
   353 					'type'        => 'object',
       
   354 					'readonly'    => true,
       
   355 					'properties'  => array(
       
   356 						'raw'      => array(
       
   357 							'description' => __( 'The theme tags, as found in the theme header.' ),
       
   358 							'type'        => 'array',
       
   359 							'items'       => array(
       
   360 								'type' => 'string',
       
   361 							),
       
   362 						),
       
   363 						'rendered' => array(
       
   364 							'description' => __( 'The theme tags, transformed for display.' ),
       
   365 							'type'        => 'string',
       
   366 						),
       
   367 					),
       
   368 				),
       
   369 				'textdomain'     => array(
       
   370 					'description' => __( 'The theme\'s text domain.' ),
       
   371 					'type'        => 'string',
       
   372 					'readonly'    => true,
       
   373 				),
   155 				'theme_supports' => array(
   374 				'theme_supports' => array(
   156 					'description' => __( 'Features supported by this theme.' ),
   375 					'description' => __( 'Features supported by this theme.' ),
   157 					'type'        => 'array',
   376 					'type'        => 'object',
   158 					'readonly'    => true,
   377 					'readonly'    => true,
   159 					'properties'  => array(
   378 					'properties'  => array(),
   160 						'formats'           => array(
   379 				),
   161 							'description' => __( 'Post formats supported.' ),
   380 				'theme_uri'      => array(
   162 							'type'        => 'array',
   381 					'description' => __( 'The URI of the theme\'s webpage.' ),
   163 							'readonly'    => true,
   382 					'type'        => 'object',
   164 						),
   383 					'readonly'    => true,
   165 						'post-thumbnails'   => array(
   384 					'properties'  => array(
   166 							'description' => __( 'Whether the theme supports post thumbnails.' ),
   385 						'raw'      => array(
   167 							'type'        => array( 'array', 'bool' ),
   386 							'description' => __( 'The URI of the theme\'s webpage, as found in the theme header.' ),
   168 							'readonly'    => true,
   387 							'type'        => 'string',
   169 						),
   388 							'format'      => 'uri',
   170 						'responsive-embeds' => array(
   389 						),
   171 							'description' => __( 'Whether the theme supports responsive embedded content.' ),
   390 						'rendered' => array(
   172 							'type'        => 'bool',
   391 							'description' => __( 'The URI of the theme\'s webpage, transformed for display.' ),
   173 							'readonly'    => true,
   392 							'type'        => 'string',
   174 						),
   393 							'format'      => 'uri',
   175 					),
   394 						),
       
   395 					),
       
   396 				),
       
   397 				'version'        => array(
       
   398 					'description' => __( 'The theme\'s current version.' ),
       
   399 					'type'        => 'string',
       
   400 					'readonly'    => true,
   176 				),
   401 				),
   177 			),
   402 			),
   178 		);
   403 		);
   179 
   404 
   180 		return $this->add_additional_fields_schema( $schema );
   405 		foreach ( get_registered_theme_features() as $feature => $config ) {
       
   406 			if ( ! is_array( $config['show_in_rest'] ) ) {
       
   407 				continue;
       
   408 			}
       
   409 
       
   410 			$name = $config['show_in_rest']['name'];
       
   411 
       
   412 			$schema['properties']['theme_supports']['properties'][ $name ] = $config['show_in_rest']['schema'];
       
   413 		}
       
   414 
       
   415 		$this->schema = $schema;
       
   416 
       
   417 		return $this->add_additional_fields_schema( $this->schema );
   181 	}
   418 	}
   182 
   419 
   183 	/**
   420 	/**
   184 	 * Retrieves the search params for the themes collection.
   421 	 * Retrieves the search params for the themes collection.
   185 	 *
   422 	 *
   204 		/**
   441 		/**
   205 		 * Filter collection parameters for the themes controller.
   442 		 * Filter collection parameters for the themes controller.
   206 		 *
   443 		 *
   207 		 * @since 5.0.0
   444 		 * @since 5.0.0
   208 		 *
   445 		 *
   209 		 * @param array        $query_params JSON Schema-formatted collection parameters.
   446 		 * @param array $query_params JSON Schema-formatted collection parameters.
   210 		 */
   447 		 */
   211 		return apply_filters( 'rest_themes_collection_params', $query_params );
   448 		return apply_filters( 'rest_themes_collection_params', $query_params );
   212 	}
   449 	}
   213 
   450 
   214 	/**
   451 	/**
   215 	 * Sanitizes and validates the list of theme status.
   452 	 * Sanitizes and validates the list of theme status.
   216 	 *
   453 	 *
   217 	 * @since 5.0.0
   454 	 * @since 5.0.0
   218 	 *
   455 	 *
   219 	 * @param  string|array    $statuses  One or more theme statuses.
   456 	 * @param string|array    $statuses  One or more theme statuses.
   220 	 * @param  WP_REST_Request $request   Full details about the request.
   457 	 * @param WP_REST_Request $request   Full details about the request.
   221 	 * @param  string          $parameter Additional parameter to pass to validation.
   458 	 * @param string          $parameter Additional parameter to pass to validation.
   222 	 * @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
   459 	 * @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
   223 	 */
   460 	 */
   224 	public function sanitize_theme_status( $statuses, $request, $parameter ) {
   461 	public function sanitize_theme_status( $statuses, $request, $parameter ) {
   225 		$statuses = wp_parse_slug_list( $statuses );
   462 		$statuses = wp_parse_slug_list( $statuses );
   226 
   463