diff --git a/core-data/actions.js b/core-data/actions.js index cd74beb40dfa1..dee2f1e0326e7 100644 --- a/core-data/actions.js +++ b/core-data/actions.js @@ -64,3 +64,17 @@ export function receivePostTypes( postTypes ) { postTypes: castArray( postTypes ), }; } + +/** + * Returns an action object used in signalling that the index has been received. + * + * @param {Object} index Index received. + * + * @return {Object} Action object. + */ +export function receiveIndex( index ) { + return { + type: 'RECEIVE_INDEX', + index: index, + }; +} diff --git a/core-data/reducer.js b/core-data/reducer.js index 6ca7f358335e1..950d542c2d9d1 100644 --- a/core-data/reducer.js +++ b/core-data/reducer.js @@ -82,8 +82,29 @@ export function postTypes( state = {}, action ) { return state; } +/** + * Reducer managing indexes data. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + * + * @return {Object} Updated state. + */ +export function indexData( state = {}, action ) { + switch ( action.type ) { + case 'RECEIVE_INDEX': + return { + ...state, + ...action.index, + }; + } + + return state; +} + export default combineReducers( { terms, media, postTypes, + indexData, } ); diff --git a/core-data/resolvers.js b/core-data/resolvers.js index 7870a42bb6881..f8a74a29acbf8 100644 --- a/core-data/resolvers.js +++ b/core-data/resolvers.js @@ -11,6 +11,7 @@ import { receiveTerms, receiveMedia, receivePostTypes, + receiveIndex, } from './actions'; /** @@ -44,3 +45,11 @@ export async function* getPostType( state, slug ) { const postType = await apiRequest( { path: `/wp/v2/types/${ slug }?context=edit` } ); yield receivePostTypes( postType ); } + +/** + * Requests theme supports data from the index. + */ +export async function* getThemeSupports() { + const index = await apiRequest( { path: '/' } ); + yield receiveIndex( index ); +} diff --git a/core-data/selectors.js b/core-data/selectors.js index 560708c6c5dfc..05ee50f1c9a37 100644 --- a/core-data/selectors.js +++ b/core-data/selectors.js @@ -69,3 +69,14 @@ export function getMedia( state, id ) { export function getPostType( state, slug ) { return state.postTypes[ slug ]; } + +/** + * Return theme suports data in the index. + * + * @param {Object} state Data state. + * + * @return {Mixed?} Index data. + */ +export function getThemeSupports( state ) { + return state.indexData.theme_supports; +} diff --git a/editor/components/post-format/index.js b/editor/components/post-format/index.js index db3383190fbad..abc4049253720 100644 --- a/editor/components/post-format/index.js +++ b/editor/components/post-format/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { find, get } from 'lodash'; +import { find, get, union } from 'lodash'; /** * WordPress dependencies @@ -71,11 +71,14 @@ function PostFormat( { onUpdatePostFormat, postFormat = 'standard', supportedFor export default compose( [ withSelect( ( select ) => { const { getEditedPostAttribute, getSuggestedPostFormat } = select( 'core/editor' ); - const { getPostType } = select( 'core' ); - const postType = getPostType( getEditedPostAttribute( 'type' ) ); + const format = getEditedPostAttribute( 'format' ); + const themeSupports = select( 'core' ).getThemeSupports(); + // Ensure current format is always in the set. + // The current format may not be a format supported by the theme. + const supportedFormats = union( [ format ], get( themeSupports, 'formats', [] ) ); return { postFormat: getEditedPostAttribute( 'format' ), - supportedFormats: get( postType, [ 'formats' ], [] ), + supportedFormats, suggestedFormat: getSuggestedPostFormat(), }; } ), diff --git a/lib/compat.php b/lib/compat.php index 79bafbfd973c8..7b5237c0ff92e 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -238,6 +238,30 @@ function gutenberg_ensure_wp_json_has_permalink_structure( $response ) { } add_filter( 'rest_index', 'gutenberg_ensure_wp_json_has_permalink_structure' ); +/** + * Ensure that the wp-json index contains the 'theme-supports' setting as + * part of its site info elements. + * + * @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; + } + $response->set_data( $site_info ); + return $response; +} +add_filter( 'rest_index', 'gutenberg_ensure_wp_json_has_theme_supports' ); + /** * As a substitute for the default content `wpautop` filter, applies autop * behavior only for posts where content does not contain blocks. @@ -490,26 +514,6 @@ function gutenberg_get_post_type_viewable( $post_type ) { return is_post_type_viewable( $post_type['slug'] ); } -/** - * Includes the value for the 'formats' attribute of a post type resource. - * - * @see https://core.trac.wordpress.org/ticket/43817 - * - * @param object $post_type Post type response object. - * @return array The list of post formats that the post type supports. - */ -function gutenberg_get_post_type_formats( $post_type ) { - if ( ! post_type_supports( $post_type['slug'], 'post-formats' ) ) { - return array(); - } - - $formats = get_theme_support( 'post-formats' ); - $formats = is_array( $formats ) ? array_values( $formats[0] ) : array(); - $formats = array_merge( array( 'standard' ), $formats ); - - return $formats; -} - /** * Adds extra fields to the REST API post type response. * @@ -530,17 +534,5 @@ function gutenberg_register_rest_api_post_type_fields() { ) ); - register_rest_field( 'type', - 'formats', - array( - 'get_callback' => 'gutenberg_get_post_type_formats', - 'schema' => array( - 'description' => __( 'The list of post formats that this post type supports', 'gutenberg' ), - 'type' => 'array', - 'context' => array( 'edit', 'view' ), - 'readonly' => true, - ), - ) - ); } add_action( 'rest_api_init', 'gutenberg_register_rest_api_post_type_fields' ); diff --git a/phpunit/class-gutenberg-rest-api-test.php b/phpunit/class-gutenberg-rest-api-test.php index 7e019da27a54e..322b5557f0169 100644 --- a/phpunit/class-gutenberg-rest-api-test.php +++ b/phpunit/class-gutenberg-rest-api-test.php @@ -119,4 +119,16 @@ function test_viewable_field_without_context() { $result = $response->get_data(); $this->assertFalse( isset( $result['viewable'] ) ); } + + /** + * Should include relevant data in the 'theme_supports' key of index. + */ + function test_theme_supports_index() { + $request = new WP_REST_Request( 'GET', '/' ); + $response = rest_do_request( $request ); + $result = $response->get_data(); + $this->assertTrue( isset( $result['theme_supports'] ) ); + $this->assertTrue( isset( $result['theme_supports']['formats'] ) ); + $this->assertTrue( in_array( 'standard', $result['theme_supports']['formats'] ) ); + } }