Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose theme_supports data through a minimial theme controller #10518

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
049f30f
First pass at adding a Themes endpoint for the current active theme.
desrosj Oct 10, 2018
9187617
Don't return `false` when the theme does not support thumbnails. Only…
desrosj Oct 11, 2018
e013653
Use the new active theme endpoint for determining theme support.
desrosj Oct 11, 2018
08eb03d
Add unit tests for the new active theme controller.
desrosj Oct 11, 2018
5b5675d
Pre-load the active theme endpoint.
desrosj Oct 11, 2018
3af33f2
PR Review Feedback adjustments:
desrosj Oct 11, 2018
f18a663
Fix failing tests. Change default context to edit.
desrosj Oct 11, 2018
7a1c75e
Add missing textdomain.
desrosj Oct 11, 2018
06fb8cf
Remove contexts from themes (see https://wordpress.slack.com/archives…
desrosj Oct 11, 2018
2ff2fb4
Merge branch 'master' of github.com:WordPress/gutenberg into add/core…
desrosj Oct 11, 2018
2bbd6ba
Always include `post-thumbnails` property to ensure consistent respon…
desrosj Oct 12, 2018
f593169
Avoid using the `__get()` magic method.
desrosj Oct 12, 2018
6e8abc1
Change the `themes/active` route to `themes?status=active`. The forme…
desrosj Oct 12, 2018
c972f4a
Change variable name from `currentTheme` to `activeThemes`, as the en…
desrosj Oct 12, 2018
d3dbb6f
Remove `_links` from the response and adjust the theme supports prope…
desrosj Oct 15, 2018
9693640
Merge branch 'master' of github.com:WordPress/gutenberg into add/core…
desrosj Oct 15, 2018
b1fe1b7
Updating JavaScript documentation.
desrosj Oct 15, 2018
f7cd0a5
Rename `TotalThemes` to `TotalPages`
danielbachhuber Oct 15, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 251 additions & 0 deletions lib/class-wp-rest-themes-controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
<?php
/**
* REST API: WP_REST_Themes_Controller class
*
* @package WordPress
* @subpackage REST_API
* @since 5.0.0
*/

/**
* Core class used to manage themes via the REST API.
*
* @since 5.0.0
*
* @see WP_REST_Controller
*/
class WP_REST_Themes_Controller extends WP_REST_Controller {

/**
* Constructor.
*
* @since 5.0.0
*/
public function __construct() {
$this->namespace = 'wp/v2';
$this->rest_base = 'themes';
}

/**
* Registers the routes for the objects of the controller.
*
* @since 5.0.0
*
* @see register_rest_route()
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
'args' => $this->get_collection_params(),
),
'schema' => array( $this, 'get_item_schema' ),
)
);
}

/**
* Checks if a given request has access to read the theme.
*
* @since 5.0.0
*
* @param WP_REST_Request $request Full details about the request.
* @return true|WP_Error True if the request has read access for the item, otherwise WP_Error object.
*/
public function get_items_permissions_check( $request ) {
if ( ! is_user_logged_in() || ! current_user_can( 'edit_posts' ) ) {
return new WP_Error( 'rest_user_cannot_view', __( 'Sorry, you are not allowed to view themes.', 'gutenberg' ), array( 'status' => rest_authorization_required_code() ) );
}

return true;
}

/**
* Retrieves a collection of themes.
*
* @since 5.0.0
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_items( $request ) {
// Retrieve the list of registered collection query parameters.
$registered = $this->get_collection_params();
$themes = array();

if ( isset( $registered['status'], $request['status'] ) && in_array( 'active', $request['status'], true ) ) {
$active_theme = wp_get_theme();
$active_theme = $this->prepare_item_for_response( $active_theme, $request );
$themes[] = $this->prepare_response_for_collection( $active_theme );
}

$response = rest_ensure_response( $themes );

$response->header( 'X-WP-Total', count( $themes ) );
$response->header( 'X-WP-TotalThemes', count( $themes ) );

return $response;
}

/**
* Prepares a single theme output for response.
*
* @since 5.0.0
*
* @param WP_Theme $theme Theme object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response Response object.
*/
public function prepare_item_for_response( $theme, $request ) {
$data = array();
$fields = $this->get_fields_for_response( $request );

if ( in_array( 'theme_supports', $fields, true ) ) {
$formats = get_theme_support( 'post-formats' );
$formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
$formats = array_merge( array( 'standard' ), $formats );
$data['theme_supports']['formats'] = $formats;

$data['theme_supports']['post-thumbnails'] = false;
$post_thumbnails = get_theme_support( 'post-thumbnails' );

if ( $post_thumbnails ) {
desrosj marked this conversation as resolved.
Show resolved Hide resolved
// $post_thumbnails can contain a nested array of post types.
// e.g. array( array( 'post', 'page' ) ).
$data['theme_supports']['post-thumbnails'] = is_array( $post_thumbnails ) ? $post_thumbnails[0] : true;
}
}

$data = $this->add_additional_fields_to_object( $data, $request );

// Wrap the data in a response object.
$response = rest_ensure_response( $data );

$response->add_links( $this->prepare_links( $theme ) );

/**
* Filters theme data returned from the REST API.
*
* @since 5.0.0
*
* @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.
*/
return apply_filters( 'rest_prepare_theme', $response, $theme, $request );
}

/**
* Prepares links for the theme request.
*
* @since 5.0.0
*
* @param WP_Theme $theme Theme object.
* @return array Links for the given theme.
*/
protected function prepare_links( $theme ) {
$links = array(
'self' => array(
'href' => rest_url( sprintf( '%s/%s?status=active', $this->namespace, $this->rest_base ) ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think href is supposed to be /wp/v2/themes/<slug>, which we don't have right now. We could probably remove prepare_links() entirely.

),
);

return $links;
}

/**
* Retrieves the theme's schema, conforming to JSON Schema.
*
* @since 5.0.0
*
* @return array Item schema data.
*/
public function get_item_schema() {
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'theme',
'type' => 'object',
'properties' => array(
'theme_supports' => array(
'description' => __( 'A list of features this theme supports.', 'gutenberg' ),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Language tweak: Features supported by this theme.

'type' => 'array',
'readonly' => true,
'properties' => array(
'formats' => array(
'description' => __( 'Post formats supported.', 'gutenberg' ),
'type' => 'array',
'readonly' => true,
),
'post-thumbnails' => array(
'description' => __( 'Whether the theme supports post thumbnails.', 'gutenberg' ),
'type' => array( 'array', 'bool' ),
'readonly' => true,
),
),
),
),
);
danielbachhuber marked this conversation as resolved.
Show resolved Hide resolved

return $this->add_additional_fields_schema( $schema );
}

/**
* Retrieves the search params for the themes collection.
*
* @since 5.0.0
*
* @return array Collection parameters.
*/
public function get_collection_params() {
$query_params = parent::get_collection_params();

$query_params['status'] = array(
'description' => __( 'Limit result set to themes assigned one or more statuses.', 'gutenberg' ),
'type' => 'array',
'items' => array(
'enum' => array( 'active' ),
'type' => 'string',
),
'required' => true,
'sanitize_callback' => array( $this, 'sanitize_theme_status' ),
);

/**
* Filter collection parameters for the themes controller.
*
* @since 5.0.0
*
* @param array $query_params JSON Schema-formatted collection parameters.
*/
return apply_filters( 'rest_themes_collection_params', $query_params );
}

/**
* Sanitizes and validates the list of theme status.
*
* @since 5.0.0
*
* @param string|array $statuses One or more theme statuses.
* @param WP_REST_Request $request Full details about the request.
* @param string $parameter Additional parameter to pass to validation.
* @return array|WP_Error A list of valid statuses, otherwise WP_Error object.
*/
public function sanitize_theme_status( $statuses, $request, $parameter ) {
$statuses = wp_parse_slug_list( $statuses );

foreach ( $statuses as $status ) {
$result = rest_validate_request_arg( $status, $request, $parameter );

if ( is_wp_error( $result ) ) {
return $result;
}
}

return $statuses;
}
}
1 change: 1 addition & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,7 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
'/',
'/wp/v2/types?context=edit',
'/wp/v2/taxonomies?per_page=-1&context=edit',
'/wp/v2/themes?status=active',
sprintf( '/wp/v2/%s/%s?context=edit', $rest_base, $post->ID ),
sprintf( '/wp/v2/types/%s?context=edit', $post_type ),
sprintf( '/wp/v2/users/me?post_type=%s&context=edit', $post_type ),
Expand Down
4 changes: 4 additions & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
if ( ! class_exists( 'WP_REST_Autosaves_Controller' ) ) {
require dirname( __FILE__ ) . '/class-wp-rest-autosaves-controller.php';
}
if ( ! class_exists( 'WP_REST_Themes_Controller' ) ) {
require dirname( __FILE__ ) . '/class-wp-rest-themes-controller.php';
}
if ( ! class_exists( 'WP_REST_Block_Renderer_Controller' ) ) {
require dirname( __FILE__ ) . '/class-wp-rest-block-renderer-controller.php';
}
Expand All @@ -30,6 +33,7 @@
if ( ! class_exists( 'WP_REST_Post_Search_Handler' ) ) {
require dirname( __FILE__ ) . '/class-wp-rest-post-search-handler.php';
}

require dirname( __FILE__ ) . '/rest-api.php';
}

Expand Down
37 changes: 3 additions & 34 deletions lib/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ function gutenberg_register_rest_routes() {
$autosaves_controller = new WP_REST_Autosaves_Controller( $post_type->name );
$autosaves_controller->register_routes();
}

$themes_controller = new WP_REST_Themes_Controller();
$themes_controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_rest_routes' );

Expand Down Expand Up @@ -304,40 +307,6 @@ function gutenberg_register_taxonomy_prepare_functions( $taxonomy ) {
}
add_filter( 'registered_taxonomy', 'gutenberg_register_taxonomy_prepare_functions' );

/**
* Ensure that the wp-json index contains the 'theme-supports' setting as
* part of its site info elements.
*
* @see https://core.trac.wordpress.org/ticket/45016
*
* @param WP_REST_Response $response WP REST API response of the wp-json index.
* @return WP_REST_Response Response that contains theme-supports.
*/
function gutenberg_ensure_wp_json_has_theme_supports( $response ) {
$site_info = $response->get_data();
if ( ! array_key_exists( 'theme_supports', $site_info ) ) {
$site_info['theme_supports'] = array();
}
if ( ! array_key_exists( 'formats', $site_info['theme_supports'] ) ) {
$formats = get_theme_support( 'post-formats' );
$formats = is_array( $formats ) ? array_values( $formats[0] ) : array();
$formats = array_merge( array( 'standard' ), $formats );

$site_info['theme_supports']['formats'] = $formats;
}
if ( ! array_key_exists( 'post-thumbnails', $site_info['theme_supports'] ) ) {
$post_thumbnails = get_theme_support( 'post-thumbnails' );
if ( $post_thumbnails ) {
// $post_thumbnails can contain a nested array of post types.
// e.g. array( array( 'post', 'page' ) ).
$site_info['theme_supports']['post-thumbnails'] = is_array( $post_thumbnails ) ? $post_thumbnails[0] : true;
}
}
$response->set_data( $site_info );
return $response;
}
add_filter( 'rest_index', 'gutenberg_ensure_wp_json_has_theme_supports' );

/**
* Handle any necessary checks early.
*
Expand Down
6 changes: 3 additions & 3 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ export function receiveEntityRecords( kind, name, records, query ) {
/**
* Returns an action object used in signalling that the index has been received.
*
* @param {Object} index Index received.
* @param {Object} themeSupports Theme support for the current theme.
*
* @return {Object} Action object.
*/
export function receiveThemeSupportsFromIndex( index ) {
export function receiveThemeSupports( themeSupports ) {
return {
type: 'RECEIVE_THEME_SUPPORTS',
themeSupports: index.theme_supports,
themeSupports,
};
}

Expand Down
6 changes: 3 additions & 3 deletions packages/core-data/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { addQueryArgs } from '@wordpress/url';
import {
receiveUserQuery,
receiveEntityRecords,
receiveThemeSupportsFromIndex,
receiveThemeSupports,
receiveEmbedPreview,
} from './actions';
import { getKindEntities } from './entities';
Expand Down Expand Up @@ -70,8 +70,8 @@ export function* getEntityRecords( kind, name, query = {} ) {
* Requests theme supports data from the index.
*/
export function* getThemeSupports() {
const index = yield apiFetch( { path: '/' } );
yield receiveThemeSupportsFromIndex( index );
const activeThemes = yield apiFetch( { path: '/wp/v2/themes?status=active' } );
yield receiveThemeSupports( activeThemes[ 0 ].theme_supports );
}

/**
Expand Down
Loading