REST API: Add additional fields to the themes controller.

When the themes controller was introduced it only returned a theme's supported features. This adds the majority of a theme's header information to the response.

Props ockham, spacedmonkey.
Fixes #49906.


git-svn-id: https://develop.svn.wordpress.org/trunk@47921 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Timothy Jacobs 2020-06-07 06:44:08 +00:00
parent 602faebb0d
commit 4fb1e58c50
4 changed files with 398 additions and 2 deletions

View File

@ -115,10 +115,65 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
$data = array();
$fields = $this->get_fields_for_response( $request );
if ( in_array( 'theme_supports', $fields, true ) ) {
if ( rest_is_field_included( 'stylesheet', $fields ) ) {
$data['stylesheet'] = $theme->get_stylesheet();
}
if ( rest_is_field_included( 'template', $fields ) ) {
/**
* Use the get_template() method, not the 'Template' header, for finding the template.
* The 'Template' header is only good for what was written in the style.css, while
* get_template() takes into account where WordPress actually located the theme and
* whether it is actually valid.
*/
$data['template'] = $theme->get_template();
}
$plain_field_mappings = array(
'requires_php' => 'RequiresPHP',
'requires_wp' => 'RequiresWP',
'textdomain' => 'TextDomain',
'version' => 'Version',
);
foreach ( $plain_field_mappings as $field => $header ) {
if ( rest_is_field_included( $field, $fields ) ) {
$data[ $field ] = $theme->get( $header );
}
}
if ( rest_is_field_included( 'screenshot', $fields ) ) {
// Using $theme->get_screenshot() with no args to get absolute URL.
$data['screenshot'] = $theme->get_screenshot() ?: '';
}
$rich_field_mappings = array(
'author' => 'Author',
'author_uri' => 'AuthorURI',
'description' => 'Description',
'name' => 'Name',
'tags' => 'Tags',
'theme_uri' => 'ThemeURI',
);
foreach ( $rich_field_mappings as $field => $header ) {
if ( rest_is_field_included( "{$field}.raw", $fields ) ) {
$data[ $field ]['raw'] = $theme->display( $header, false, true );
}
if ( rest_is_field_included( "{$field}.rendered", $fields ) ) {
$data[ $field ]['rendered'] = $theme->display( $header );
}
}
if ( rest_is_field_included( 'theme_supports', $fields ) ) {
$item_schemas = $this->get_item_schema();
$theme_supports = $item_schemas['properties']['theme_supports']['properties'];
foreach ( $theme_supports as $name => $schema ) {
if ( ! rest_is_field_included( "theme_supports.{$name}", $fields ) ) {
continue;
}
if ( 'formats' === $name ) {
continue;
}
@ -192,6 +247,117 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
'title' => 'theme',
'type' => 'object',
'properties' => array(
'stylesheet' => array(
'description' => __( 'The theme\'s stylesheet. This uniquely identifies the theme.' ),
'type' => 'string',
'readonly' => true,
),
'template' => array(
'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.' ),
'type' => 'string',
'readonly' => true,
),
'author' => array(
'description' => __( 'The theme author.' ),
'type' => 'object',
'readonly' => true,
'properties' => array(
'raw' => array(
'description' => __( 'The theme author\'s name, as found in the theme header.' ),
'type' => 'string',
),
'rendered' => array(
'description' => __( 'HTML for the theme author, transformed for display.' ),
'type' => 'string',
),
),
),
'author_uri' => array(
'description' => __( 'The website of the theme author.' ),
'type' => 'object',
'readonly' => true,
'properties' => array(
'raw' => array(
'description' => __( 'The website of the theme author, as found in the theme header.' ),
'type' => 'string',
'format' => 'uri',
),
'rendered' => array(
'description' => __( 'The website of the theme author, transformed for display.' ),
'type' => 'string',
'format' => 'uri',
),
),
),
'description' => array(
'description' => __( 'A description of the theme.' ),
'type' => 'object',
'readonly' => true,
'properties' => array(
'raw' => array(
'description' => __( 'The theme description, as found in the theme header.' ),
'type' => 'string',
),
'rendered' => array(
'description' => __( 'The theme description, transformed for display.' ),
'type' => 'string',
),
),
),
'name' => array(
'description' => __( 'The name of the theme.' ),
'type' => 'object',
'readonly' => true,
'properties' => array(
'raw' => array(
'description' => __( 'The theme name, as found in the theme header.' ),
'type' => 'string',
),
'rendered' => array(
'description' => __( 'The theme name, transformed for display.' ),
'type' => 'string',
),
),
),
'requires_php' => array(
'description' => __( 'The minimum PHP version required for the theme to work.' ),
'type' => 'string',
'readonly' => true,
),
'requires_wp' => array(
'description' => __( 'The minimum WordPress version required for the theme to work.' ),
'type' => 'string',
'readonly' => true,
),
'screenshot' => array(
'description' => __( 'The theme\'s screenshot URL.' ),
'type' => 'string',
'format' => 'uri',
'readonly' => true,
),
'tags' => array(
'description' => __( 'Tags indicating styles and features of the theme.' ),
'type' => 'object',
'readonly' => true,
'properties' => array(
'raw' => array(
'description' => __( 'The theme tags, as found in the theme header.' ),
'type' => 'array',
'items' => array(
'type' => 'string',
),
),
'rendered' => array(
'description' => __( 'The theme tags, transformed for display.' ),
'type' => 'string',
),
),
),
'textdomain' => array(
'description' => __( 'The theme\'s textdomain.' ),
'type' => 'string',
'readonly' => true,
),
'theme_supports' => array(
'description' => __( 'Features supported by this theme.' ),
'type' => 'object',
@ -458,6 +624,28 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
),
),
),
'theme_uri' => array(
'description' => __( 'The URI of the theme\'s webpage.' ),
'type' => 'object',
'readonly' => true,
'properties' => array(
'raw' => array(
'description' => __( 'The URI of the theme\'s webpage, as found in the theme header.' ),
'type' => 'string',
'format' => 'uri',
),
'rendered' => array(
'description' => __( 'The URI of the theme\'s webpage, transformed for display.' ),
'type' => 'string',
'format' => 'uri',
),
),
),
'version' => array(
'description' => __( 'The theme\'s current version.' ),
'type' => 'string',
'readonly' => true,
),
),
);

View File

@ -0,0 +1,15 @@
/*
Theme Name: REST Theme
Theme URI: http://wordpress.org/?search=1&term=2
Description: The 9' foot tall theme.
Version: 1.6
Author: Michael Heilemann
Author URI: http://binarybonsai.com/?search=1&term=2
Tags: holiday, custom-menu
Template: default
Requires at least: 5.3
Requires PHP: 5.6
Text Domain: rest-api
*/

View File

@ -125,6 +125,7 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
parent::setUp();
wp_set_current_user( self::$contributor_id );
switch_theme( 'rest-api' );
}
/**
@ -150,7 +151,20 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
$this->check_get_theme_response( $response );
$fields = array(
'author',
'author_uri',
'description',
'name',
'requires_php',
'requires_wp',
'screenshot',
'stylesheet',
'tags',
'template',
'textdomain',
'theme_supports',
'theme_uri',
'version',
);
$this->assertEqualSets( $fields, array_keys( $data[0] ) );
}
@ -207,8 +221,44 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
$response = self::perform_active_theme_request( 'OPTIONS' );
$data = $response->get_data();
$properties = $data['schema']['properties'];
$this->assertEquals( 1, count( $properties ) );
$this->assertEquals( 14, count( $properties ) );
$this->assertArrayHasKey( 'author', $properties );
$this->assertArrayHasKey( 'raw', $properties['author']['properties'] );
$this->assertArrayHasKey( 'rendered', $properties['author']['properties'] );
$this->assertArrayHasKey( 'author_uri', $properties );
$this->assertArrayHasKey( 'raw', $properties['author_uri']['properties'] );
$this->assertArrayHasKey( 'rendered', $properties['author_uri']['properties'] );
$this->assertArrayHasKey( 'description', $properties );
$this->assertArrayHasKey( 'raw', $properties['description']['properties'] );
$this->assertArrayHasKey( 'rendered', $properties['description']['properties'] );
$this->assertArrayHasKey( 'name', $properties );
$this->assertArrayHasKey( 'raw', $properties['name']['properties'] );
$this->assertArrayHasKey( 'rendered', $properties['name']['properties'] );
$this->assertArrayHasKey( 'requires_php', $properties );
$this->assertArrayHasKey( 'requires_wp', $properties );
$this->assertArrayHasKey( 'screenshot', $properties );
$this->assertArrayHasKey( 'stylesheet', $properties );
$this->assertArrayHasKey( 'tags', $properties );
$this->assertArrayHasKey( 'raw', $properties['tags']['properties'] );
$this->assertArrayHasKey( 'items', $properties['tags']['properties']['raw'] );
$this->assertArrayHasKey( 'rendered', $properties['tags']['properties'] );
$this->assertArrayHasKey( 'template', $properties );
$this->assertArrayHasKey( 'textdomain', $properties );
$this->assertArrayHasKey( 'theme_supports', $properties );
$this->assertArrayHasKey( 'theme_uri', $properties );
$this->assertArrayHasKey( 'raw', $properties['theme_uri']['properties'] );
$this->assertArrayHasKey( 'rendered', $properties['theme_uri']['properties'] );
$this->assertArrayHasKey( 'version', $properties );
$theme_supports = $properties['theme_supports']['properties'];
$this->assertEquals( 20, count( $theme_supports ) );
$this->assertArrayHasKey( 'align-wide', $theme_supports );
@ -233,6 +283,148 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
$this->assertArrayHasKey( 'wp-block-styles', $theme_supports );
}
/**
* @ticket 49906
*/
public function test_theme_author() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'author', $result[0] );
$this->assertSame( 'Michael Heilemann', $result[0]['author']['raw'] );
$this->assertSame(
'<a href="http://binarybonsai.com/?search=1&#038;term=2">Michael Heilemann</a>',
$result[0]['author']['rendered']
);
}
/**
* @ticket 49906
*/
public function test_theme_author_uri() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'author_uri', $result[0] );
$this->assertSame( 'http://binarybonsai.com/?search=1&term=2', $result[0]['author_uri']['raw'] );
$this->assertSame( 'http://binarybonsai.com/?search=1&#038;term=2', $result[0]['author_uri']['rendered'] );
}
/**
* @ticket 49906
*/
public function test_theme_description() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'description', $result[0] );
$this->assertSame(
'The 9\' foot tall theme.',
$result[0]['description']['raw']
);
$this->assertSame(
'The 9&#8242; foot tall theme.',
$result[0]['description']['rendered']
);
}
/**
* @ticket 49906
*/
public function test_theme_requires_php() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'requires_php', $result[0] );
$this->assertSame( '5.6', $result[0]['requires_php'] );
}
/**
* @ticket 49906
*/
public function test_theme_requires_wp() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'requires_wp', $result[0] );
$this->assertSame( '5.3', $result[0]['requires_wp'] );
}
/**
* @ticket 49906
*/
public function test_theme_name() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'name', $result[0] );
$this->assertSame( 'REST Theme', $result[0]['name']['raw'] );
$this->assertSame( 'REST Theme', $result[0]['name']['rendered'] );
}
/**
* @ticket 49906
*/
public function test_theme_screenshot() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'screenshot', $result[0] );
$this->assertSame( '', $result[0]['screenshot'] ); // No screenshot for default theme
}
/**
* @ticket 49906
*/
public function test_theme_stylesheet() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'stylesheet', $result[0] );
$this->assertSame( 'rest-api', $result[0]['stylesheet'] );
}
/**
* @ticket 49906
*/
public function test_theme_tags() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'tags', $result[0] );
$this->assertSame( array( 'holiday', 'custom-menu' ), $result[0]['tags']['raw'] );
$this->assertSame( 'holiday, custom-menu', $result[0]['tags']['rendered'] );
}
/**
* @ticket 49906
*/
public function test_theme_template() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'template', $result[0] );
$this->assertSame( 'default', $result[0]['template'] );
}
/**
* @ticket 49906
*/
public function test_theme_textdomain() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'textdomain', $result[0] );
$this->assertSame( 'rest-api', $result[0]['textdomain'] );
}
public function test_theme_theme_uri() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'theme_uri', $result[0] );
$this->assertSame( 'http://wordpress.org/?search=1&term=2', $result[0]['theme_uri']['raw'] );
$this->assertSame( 'http://wordpress.org/?search=1&#038;term=2', $result[0]['theme_uri']['rendered'] );
}
/**
* @ticket 49906
*/
public function test_theme_version() {
$response = self::perform_active_theme_request();
$result = $response->get_data();
$this->assertArrayHasKey( 'version', $result[0] );
$this->assertSame( '1.6', $result[0]['version'] );
}
/**
* @ticket 49037
*/

View File

@ -163,6 +163,7 @@ class Tests_Theme_ThemeDir extends WP_UnitTestCase {
'Theme with Spaces in the Directory',
'Internationalized Theme',
'camelCase',
'REST Theme',
);
sort( $theme_names );