Skip to content

Commit 332397e

Browse files
authored
REST API: Sync /themes endpoint with Core's (#23321)
In #21578, I added a few fields to Core's `/themes` endpoint, for use by the Site Editor's Template Switcher (see both #21578 and #21768). I then submitted those changes as a [PR](WordPress/wordpress-develop#222) against Core. That PR underwent a number of modifications and was eventually merged; the new fields will be part of the `/themes` endpoint exposed by Core starting from the next WP release. This PR updates the fields added by Gutenberg to follow the same semantics, as well as the callsites that use that endpoint.
1 parent 969d26f commit 332397e

File tree

3 files changed

+71
-24
lines changed

3 files changed

+71
-24
lines changed

lib/rest-api.php

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,34 +55,73 @@ function gutenberg_filter_oembed_result( $response, $handler, $request ) {
5555
/**
5656
* Add fields required for site editing to the /themes endpoint.
5757
*
58-
* @todo Remove once https://core.trac.wordpress.org/ticket/49906 is fixed.
58+
* @todo Remove once Gutenberg's minimum required WordPress version is v5.5.
59+
* @see https://core.trac.wordpress.org/ticket/49906
5960
* @see https://github.com/WordPress/wordpress-develop/pull/222
6061
*
6162
* @param WP_REST_Response $response The response object.
6263
* @param WP_Theme $theme Theme object used to create response.
6364
* @param WP_REST_Request $request Request object.
6465
*/
6566
function gutenberg_filter_rest_prepare_theme( $response, $theme, $request ) {
66-
$data = $response->get_data();
67-
$field_mappings = array(
67+
$data = $response->get_data();
68+
$fields = array_keys( $data );
69+
70+
/**
71+
* The following is basically copied from Core's WP_REST_Themes_Controller::prepare_item_for_response()
72+
* (as of WP v5.5), with `rest_is_field_included()` replaced by `! in_array()`.
73+
* This makes sure that we add all the fields that are missing from Core.
74+
*
75+
* @see https://github.com/WordPress/WordPress/blob/019bc2d244c4d536338d2c634419583e928143df/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php#L118-L167
76+
*/
77+
if ( ! in_array( 'stylesheet', $fields, true ) ) {
78+
$data['stylesheet'] = $theme->get_stylesheet();
79+
}
80+
81+
if ( ! in_array( 'template', $fields, true ) ) {
82+
/**
83+
* Use the get_template() method, not the 'Template' header, for finding the template.
84+
* The 'Template' header is only good for what was written in the style.css, while
85+
* get_template() takes into account where WordPress actually located the theme and
86+
* whether it is actually valid.
87+
*/
88+
$data['template'] = $theme->get_template();
89+
}
90+
91+
$plain_field_mappings = array(
92+
'requires_php' => 'RequiresPHP',
93+
'requires_wp' => 'RequiresWP',
94+
'textdomain' => 'TextDomain',
95+
'version' => 'Version',
96+
);
97+
98+
foreach ( $plain_field_mappings as $field => $header ) {
99+
if ( ! in_array( $field, $fields, true ) ) {
100+
$data[ $field ] = $theme->get( $header );
101+
}
102+
}
103+
104+
if ( ! in_array( 'screenshot', $fields, true ) ) {
105+
// Using $theme->get_screenshot() with no args to get absolute URL.
106+
$data['screenshot'] = $theme->get_screenshot() ? $theme->get_screenshot() : '';
107+
}
108+
109+
$rich_field_mappings = array(
68110
'author' => 'Author',
69-
'author_name' => 'Author Name',
70-
'author_uri' => 'Author URI',
111+
'author_uri' => 'AuthorURI',
71112
'description' => 'Description',
72113
'name' => 'Name',
73-
'stylesheet' => 'Stylesheet',
74-
'template' => 'Template',
75-
'theme_uri' => 'Theme URI',
76-
'version' => 'Version',
114+
'tags' => 'Tags',
115+
'theme_uri' => 'ThemeURI',
77116
);
78117

79-
foreach ( $field_mappings as $field => $theme_field ) {
80-
$data[ $field ] = $theme[ $theme_field ];
118+
foreach ( $rich_field_mappings as $field => $header ) {
119+
if ( ! in_array( $field, $fields, true ) ) {
120+
$data[ $field ]['raw'] = $theme->display( $header, false, true );
121+
$data[ $field ]['rendered'] = $theme->display( $header );
122+
}
81123
}
82124

83-
// Using $theme->get_screenshot() with no args to get absolute URL.
84-
$data['screenshot'] = $theme->get_screenshot();
85-
86125
$response->set_data( $data );
87126
return $response;
88127
}

packages/edit-site/src/components/template-switcher/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ export default function TemplateSwitcher( {
204204
onMouseEnter={ onMouseEnterTheme }
205205
onMouseLeave={ onMouseLeaveTheme }
206206
>
207-
{ currentTheme.name }
207+
{ currentTheme.name.raw }
208208
</MenuItem>
209209
</MenuGroup>
210210
{ !! hoveredTemplate?.id && (

packages/edit-site/src/components/template-switcher/theme-preview.js

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,24 @@ import { truncate } from 'lodash';
99
import { __, sprintf } from '@wordpress/i18n';
1010

1111
function ThemePreview( {
12-
theme: { author_name: authorName, description, name, screenshot, version },
12+
theme: { author, description, name, screenshot, version },
1313
} ) {
1414
return (
1515
<div className="edit-site-template-switcher__theme-preview">
16-
<span className="edit-site-template-switcher__theme-preview-name">
17-
{ name }
18-
</span>{ ' ' }
16+
<span
17+
className="edit-site-template-switcher__theme-preview-name"
18+
dangerouslySetInnerHTML={ {
19+
/* name.rendered is sanitized on the server side. */
20+
__html: name.rendered,
21+
} }
22+
/>{ ' ' }
1923
<span className="edit-site-template-switcher__theme-preview-version">
2024
{ 'v' + version }
2125
</span>
2226
<div className="edit-site-template-switcher__theme-preview-byline">
2327
{
2428
// translators: %s: theme author name.
25-
sprintf( __( 'By %s' ), [ authorName ] )
29+
sprintf( __( 'By %s' ), [ author.raw ] )
2630
}
2731
</div>
2832
<img
@@ -31,10 +35,14 @@ function ThemePreview( {
3135
alt={ 'Theme Preview' }
3236
/>
3337
<div className="edit-site-template-switcher__theme-preview-description">
34-
{ truncate( description, {
35-
length: 120,
36-
separator: /\. +/,
37-
} ) }
38+
{ truncate(
39+
/* Not using description.rendered here, as we might contain after an opening HTML tag. */
40+
description.raw,
41+
{
42+
length: 120,
43+
separator: /\. +/,
44+
}
45+
) }
3846
</div>
3947
</div>
4048
);

0 commit comments

Comments
 (0)