Skip to content

Commit

Permalink
Template Switcher: Add current theme (#21578)
Browse files Browse the repository at this point in the history
Display the current theme name in the template selector of `edit-site`.

Since the `/themes` endpoint currently only exposes the `theme_supports` field for each theme, this PR adds a number of additional fields to it, using the `rest_prepare_theme` hook. (I also filed a WordPress/wordpress-develop#222 against Core to extend the, err, upstream endpoint accordingly so that we can eventually drop the filter.)

In addition, this PR adds a new `getCurrentTheme` selector and related reducer/resolver/action to `core-data` (including a `themes` reducer for better normalization).

Finally, that selector is used to render the theme name in `edit-site`'s template selector.

The fields I've chosen to add should be sufficient to implement the on-hover previews seen at #20469 (comment).

However, this PR doesn't implement those previews yet, since we need to implement the underlying fly-out menu component first (see #20470).
  • Loading branch information
ockham committed Apr 17, 2020
1 parent 63f708a commit a32e961
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 2 deletions.
24 changes: 24 additions & 0 deletions docs/designers-developers/developers/data/data-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ _Returns_

- `?Array`: An array of autosaves for the post, or undefined if there is none.

<a name="getCurrentTheme" href="#getCurrentTheme">#</a> **getCurrentTheme**

Return the current theme.

_Parameters_

- _state_ `Object`: Data state.

_Returns_

- `Object`: The current theme.

<a name="getCurrentUser" href="#getCurrentUser">#</a> **getCurrentUser**

Returns the current user.
Expand Down Expand Up @@ -491,6 +503,18 @@ _Returns_

- `Object`: Action object.

<a name="receiveCurrentTheme" href="#receiveCurrentTheme">#</a> **receiveCurrentTheme**

Returns an action object used in signalling that the current theme has been received.

_Parameters_

- _currentTheme_ `Object`: The current theme.

_Returns_

- `Object`: Action object.

<a name="receiveCurrentUser" href="#receiveCurrentUser">#</a> **receiveCurrentUser**

Returns an action used in signalling that the current user has been received.
Expand Down
34 changes: 34 additions & 0 deletions lib/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,41 @@ function gutenberg_filter_oembed_result( $response, $handler, $request ) {
}
add_filter( 'rest_request_after_callbacks', 'gutenberg_filter_oembed_result', 10, 3 );

/**
* Add fields required for site editing to the /themes endpoint.
*
* @todo Remove once https://core.trac.wordpress.org/ticket/49906 is fixed.
* @see https://github.com/WordPress/wordpress-develop/pull/222
*
* @param WP_REST_Response $response The response object.
* @param WP_Theme $theme Theme object used to create response.
* @param WP_REST_Request $request Request object.
*/
function gutenberg_filter_rest_prepare_theme( $response, $theme, $request ) {
$data = $response->get_data();
$field_mappings = array(
'author' => 'Author',
'author_name' => 'Author Name',
'author_uri' => 'Author URI',
'description' => 'Description',
'name' => 'Name',
'stylesheet' => 'Stylesheet',
'template' => 'Template',
'theme_uri' => 'Theme URI',
'version' => 'Version',
);

foreach ( $field_mappings as $field => $theme_field ) {
$data[ $field ] = $theme[ $theme_field ];
}

// Using $theme->get_screenshot() with no args to get absolute URL.
$data['screenshot'] = $theme->get_screenshot();

$response->set_data( $data );
return $response;
}
add_filter( 'rest_prepare_theme', 'gutenberg_filter_rest_prepare_theme', 10, 3 );

/**
* Start: Include for phase 2
Expand Down
24 changes: 24 additions & 0 deletions packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ _Returns_

- `Object`: Action object.

<a name="receiveCurrentTheme" href="#receiveCurrentTheme">#</a> **receiveCurrentTheme**

Returns an action object used in signalling that the current theme has been received.

_Parameters_

- _currentTheme_ `Object`: The current theme.

_Returns_

- `Object`: Action object.

<a name="receiveCurrentUser" href="#receiveCurrentUser">#</a> **receiveCurrentUser**

Returns an action used in signalling that the current user has been received.
Expand Down Expand Up @@ -284,6 +296,18 @@ _Returns_

- `?Array`: An array of autosaves for the post, or undefined if there is none.

<a name="getCurrentTheme" href="#getCurrentTheme">#</a> **getCurrentTheme**

Return the current theme.

_Parameters_

- _state_ `Object`: Data state.

_Returns_

- `Object`: The current theme.

<a name="getCurrentUser" href="#getCurrentUser">#</a> **getCurrentUser**

Returns the current user.
Expand Down
14 changes: 14 additions & 0 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ export function receiveEntityRecords(
};
}

/**
* Returns an action object used in signalling that the current theme has been received.
*
* @param {Object} currentTheme The current theme.
*
* @return {Object} Action object.
*/
export function receiveCurrentTheme( currentTheme ) {
return {
type: 'RECEIVE_CURRENT_THEME',
currentTheme,
};
}

/**
* Returns an action object used in signalling that the index has been received.
*
Expand Down
39 changes: 39 additions & 0 deletions packages/core-data/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,43 @@ export function taxonomies( state = [], action ) {
return state;
}

/**
* Reducer managing the current theme.
*
* @param {string} state Current state.
* @param {Object} action Dispatched action.
*
* @return {string} Updated state.
*/
export function currentTheme( state = undefined, action ) {
switch ( action.type ) {
case 'RECEIVE_CURRENT_THEME':
return action.currentTheme.stylesheet;
}

return state;
}

/**
* Reducer managing installed themes.
*
* @param {Object} state Current state.
* @param {Object} action Dispatched action.
*
* @return {Object} Updated state.
*/
export function themes( state = {}, action ) {
switch ( action.type ) {
case 'RECEIVE_CURRENT_THEME':
return {
...state,
[ action.currentTheme.stylesheet ]: action.currentTheme,
};
}

return state;
}

/**
* Reducer managing theme supports data.
*
Expand Down Expand Up @@ -502,8 +539,10 @@ export function autosaves( state = {}, action ) {
export default combineReducers( {
terms,
users,
currentTheme,
currentUser,
taxonomies,
themes,
themeSupports,
entities,
undo,
Expand Down
11 changes: 11 additions & 0 deletions packages/core-data/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import deprecated from '@wordpress/deprecated';
*/
import {
receiveUserQuery,
receiveCurrentTheme,
receiveCurrentUser,
receiveEntityRecords,
receiveThemeSupports,
Expand Down Expand Up @@ -91,6 +92,16 @@ getEntityRecords.shouldInvalidate = ( action, kind, name ) => {
);
};

/**
* Requests the current theme.
*/
export function* getCurrentTheme() {
const activeThemes = yield apiFetch( {
path: '/wp/v2/themes?status=active',
} );
yield receiveCurrentTheme( activeThemes[ 0 ] );
}

/**
* Requests theme supports data from the index.
*/
Expand Down
11 changes: 11 additions & 0 deletions packages/core-data/src/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,17 @@ export function hasRedo( state ) {
return Boolean( getRedoEdit( state ) );
}

/**
* Return the current theme.
*
* @param {Object} state Data state.
*
* @return {Object} The current theme.
*/
export function getCurrentTheme( state ) {
return state.themes[ state.currentTheme ];
}

/**
* Return theme supports data in the index.
*
Expand Down
8 changes: 6 additions & 2 deletions packages/edit-site/src/components/template-switcher/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ export default function TemplateSwitcher( {
const onHoverTemplatePart = ( id ) => {
setHoveredTemplate( { id, type: 'template-part' } );
};
const { templates, templateParts } = useSelect(
const { currentTheme, templates, templateParts } = useSelect(
( select ) => {
const { getEntityRecord } = select( 'core' );
const { getCurrentTheme, getEntityRecord } = select( 'core' );
return {
currentTheme: getCurrentTheme(),
templates: ids.map( ( id ) => {
const template = getEntityRecord(
'postType',
Expand Down Expand Up @@ -134,6 +135,9 @@ export default function TemplateSwitcher( {
onHover={ onHoverTemplatePart }
/>
</MenuGroup>
<MenuGroup label={ __( 'Current theme' ) }>
<MenuItem>{ currentTheme.name }</MenuItem>
</MenuGroup>
{ !! hoveredTemplate?.id && (
<TemplatePreview item={ hoveredTemplate } />
) }
Expand Down

0 comments on commit a32e961

Please sign in to comment.