Block Editor: Backport the Global Styles Variations endpoint.

This include the /global-styles/themes/{theme}/variations rest endpoint into core.
The endpoint will be used by the site editor to display alternative theme styles to the user.

Props gziolo, oandregal.
See #55505.


git-svn-id: https://develop.svn.wordpress.org/trunk@53072 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Riad Benguella 2022-04-05 09:50:13 +00:00
parent 9a9ec776a8
commit ed1f411c56
7 changed files with 183 additions and 1 deletions

2
package-lock.json generated
View File

@ -7750,7 +7750,7 @@
},
"browserify-aes": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true,
"requires": {

View File

@ -449,4 +449,32 @@ class WP_Theme_JSON_Resolver {
static::$i18n_schema = null;
}
/**
* Returns the style variations defined by the theme.
*
* @since 6.0.0
*
* @return array
*/
public static function get_style_variations() {
$variations = array();
$base_directory = get_stylesheet_directory() . '/styles';
if ( is_dir( $base_directory ) ) {
$nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $base_directory ) );
$nested_html_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) );
ksort( $nested_html_files );
foreach ( $nested_html_files as $path => $file ) {
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
if ( is_array( $decoded_file ) ) {
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
$variation = ( new WP_Theme_JSON( $translated ) )->get_raw_data();
if ( empty( $variation['title'] ) ) {
$variation['title'] = basename( $path, '.json' );
}
$variations[] = $variation;
}
}
}
return $variations;
}
}

View File

@ -38,6 +38,24 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
* @return void
*/
public function register_routes() {
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)/variations',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_theme_items' ),
'permission_callback' => array( $this, 'get_theme_items_permissions_check' ),
'args' => array(
'stylesheet' => array(
'description' => __( 'The theme identifier' ),
'type' => 'string',
),
),
),
)
);
// List themes global styles.
register_rest_route(
$this->namespace,
@ -585,4 +603,53 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
return $response;
}
/**
* Checks if a given request has access to read a single theme global styles config.
*
* @since 6.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, WP_Error object otherwise.
*/
public function get_theme_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
// Verify if the current user has edit_theme_options capability.
// This capability is required to edit/view/delete templates.
if ( ! current_user_can( 'edit_theme_options' ) ) {
return new WP_Error(
'rest_cannot_manage_global_styles',
__( 'Sorry, you are not allowed to access the global styles on this site.' ),
array(
'status' => rest_authorization_required_code(),
)
);
}
return true;
}
/**
* Returns the given theme global styles variations.
*
* @since 6.0.0
*
* @param WP_REST_Request $request The request instance.
*
* @return WP_REST_Response|WP_Error
*/
public function get_theme_items( $request ) {
if ( wp_get_theme()->get_stylesheet() !== $request['stylesheet'] ) {
// This endpoint only supports the active theme for now.
return new WP_Error(
'rest_theme_not_found',
__( 'Theme not found.' ),
array( 'status' => 404 )
);
}
$variations = WP_Theme_JSON_Resolver::get_style_variations();
$response = rest_ensure_response( $variations );
return $response;
}
}

View File

@ -0,0 +1,23 @@
{
"version": 2,
"settings": {
"color": {
"palette": [
{
"slug": "foreground",
"color": "#3F67C6",
"name": "Foreground"
}
]
}
},
"styles": {
"blocks": {
"core/post-title": {
"typography": {
"fontWeight": "700"
}
}
}
}
}

View File

@ -117,6 +117,11 @@ class WP_REST_Global_Styles_Controller_Test extends WP_Test_REST_Controller_Test
$routes['/wp/v2/global-styles/themes/(?P<stylesheet>[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)'],
'Theme global styles route does not have exactly one element'
);
$this->assertArrayHasKey(
'/wp/v2/global-styles/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)/variations',
$routes,
'Theme global styles variations route does not exist'
);
}
public function test_context_param() {
@ -455,4 +460,42 @@ class WP_REST_Global_Styles_Controller_Test extends WP_Test_REST_Controller_Test
$this->assertArrayHasKey( 'settings', $properties, 'Schema properties array does not have "settings" key' );
$this->assertArrayHasKey( 'title', $properties, 'Schema properties array does not have "title" key' );
}
public function test_get_theme_items() {
wp_set_current_user( self::$admin_id );
switch_theme( 'block-theme' );
$request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/block-theme/variations' );
$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();
$expected = array(
array(
'version' => 2,
'settings' => array(
'color' => array(
'palette' => array(
'theme' => array(
array(
'slug' => 'foreground',
'color' => '#3F67C6',
'name' => 'Foreground',
),
),
),
),
),
'styles' => array(
'blocks' => array(
'core/post-title' => array(
'typography' => array(
'fontWeight' => '700',
),
),
),
),
'title' => 'variation',
),
);
$this->assertSameSetsWithIndex( $data, $expected );
}
}

View File

@ -136,6 +136,7 @@ class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase {
'/wp/v2/comments',
'/wp/v2/comments/(?P<id>[\\d]+)',
'/wp/v2/global-styles/(?P<id>[\/\w-]+)',
'/wp/v2/global-styles/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)/variations',
'/wp/v2/global-styles/themes/(?P<stylesheet>[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
'/wp/v2/search',
'/wp/v2/block-renderer/(?P<name>[a-z0-9-]+/[a-z0-9-]+)',

View File

@ -9424,6 +9424,26 @@ mockedApiResponse.Schema = {
}
]
},
"/wp/v2/global-styles/themes/(?P<stylesheet>[\\/\\s%\\w\\.\\(\\)\\[\\]\\@_\\-]+)/variations": {
"namespace": "wp/v2",
"methods": [
"GET"
],
"endpoints": [
{
"methods": [
"GET"
],
"args": {
"stylesheet": {
"description": "The theme identifier",
"type": "string",
"required": false
}
}
}
]
},
"/wp/v2/global-styles/themes/(?P<stylesheet>[^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)": {
"namespace": "wp/v2",
"methods": [