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

theme.json: add appearanceTools flag to opt-in into appearance UI controls #36646

Merged
merged 10 commits into from Nov 23, 2021
10 changes: 10 additions & 0 deletions docs/how-to-guides/themes/theme-json.md
Expand Up @@ -218,6 +218,7 @@ The settings section has the following structure:
{
"version": 1,
"settings": {
"appearanceTools": false,
"border": {
"color": false,
"radius": false,
Expand Down Expand Up @@ -282,6 +283,15 @@ Each block can configure any of these settings separately, providing a more fine

Note, however, that not all settings are relevant for all blocks. The settings section provides an opt-in/opt-out mechanism for themes, but it's the block's responsibility to add support for the features that are relevant to it. For example, if a block doesn't implement the `dropCap` feature, a theme can't enable it for such a block through `theme.json`.

### Opt-in into UI controls

There's one special setting property, `appearanceTools`, which is a boolean and its default value is false. Themes can use this setting to enable the following ones:

- border: color, radius, style, width
- color: link
- spacing: blockGap, margin, padding
- typography: lineHeight

#### Backward compatibility with add_theme_support

To retain backward compatibility, the existing `add_theme_support` declarations that configure the block editor are retrofit in the proper categories for the top-level section. For example, if a theme uses `add_theme_support('disable-custom-colors')`, it'll be the same as setting `settings.color.custom` to `false`. If the `theme.json` contains any settings, these will take precedence over the values declared via `add_theme_support`. This is the complete list of equivalences:
Expand Down
67 changes: 60 additions & 7 deletions lib/class-wp-theme-json-gutenberg.php
Expand Up @@ -81,13 +81,14 @@ class WP_Theme_JSON_Gutenberg {
);

const VALID_SETTINGS = array(
'border' => array(
'appearanceTools' => null,
'border' => array(
'color' => null,
'radius' => null,
'style' => null,
'width' => null,
),
'color' => array(
'color' => array(
'background' => null,
'custom' => null,
'customDuotone' => null,
Expand All @@ -100,18 +101,18 @@ class WP_Theme_JSON_Gutenberg {
'palette' => null,
'text' => null,
),
'custom' => null,
'layout' => array(
'custom' => null,
'layout' => array(
'contentSize' => null,
'wideSize' => null,
),
'spacing' => array(
'spacing' => array(
'blockGap' => null,
'margin' => null,
'padding' => null,
'units' => null,
),
'typography' => array(
'typography' => array(
'customFontSize' => null,
'dropCap' => null,
'fontFamilies' => null,
Expand Down Expand Up @@ -292,7 +293,8 @@ public function __construct( $theme_json = array(), $origin = 'theme' ) {

$valid_block_names = array_keys( self::get_blocks_metadata() );
$valid_element_names = array_keys( self::ELEMENTS );
$this->theme_json = self::sanitize( $theme_json, $valid_block_names, $valid_element_names );
$theme_json = self::sanitize( $theme_json, $valid_block_names, $valid_element_names );
$this->theme_json = self::maybe_opt_in_into_settings( $theme_json );

// Internally, presets are keyed by origin.
$nodes = self::get_setting_nodes( $this->theme_json );
Expand All @@ -307,6 +309,57 @@ public function __construct( $theme_json = array(), $origin = 'theme' ) {
}
}

/**
* Enables some opt-in settings if theme declared support.
*
* @param array $theme_json A theme.json structure to modify.
* @return array The modified theme.json structure.
*/
private static function maybe_opt_in_into_settings( $theme_json ) {
$new_theme_json = $theme_json;

if ( isset( $new_theme_json['settings']['appearanceTools'] ) ) {
self::do_opt_in_into_settings( $new_theme_json['settings'] );
}

if ( isset( $new_theme_json['settings']['blocks'] ) && is_array( $new_theme_json['settings']['blocks'] ) ) {
foreach ( $new_theme_json['settings']['blocks'] as &$block ) {
if ( isset( $block['appearanceTools'] ) ) {
self::do_opt_in_into_settings( $block );
}
}
}

return $new_theme_json;
}

/**
* Enables some settings.
*
* @param array $context The context to which the settings belong.
*/
private static function do_opt_in_into_settings( &$context ) {
$to_opt_in = array(
array( 'border', 'color' ),
array( 'border', 'radius' ),
array( 'border', 'style' ),
array( 'border', 'width' ),
array( 'color', 'link' ),
array( 'spacing', 'blockGap' ),
array( 'spacing', 'margin' ),
array( 'spacing', 'padding' ),
array( 'typography', 'lineHeight' ),
);

foreach ( $to_opt_in as $path ) {
if ( null === _wp_array_get( $context, $path, null ) ) {
_wp_array_set( $context, $path, true );
}
}

unset( $context['appearanceTools'] );
}

/**
* Sanitizes the input according to the schemas.
*
Expand Down
1 change: 1 addition & 0 deletions lib/theme.json
@@ -1,6 +1,7 @@
{
"version": 2,
"settings": {
"appearanceTools": false,
"color": {
"background": true,
"palette": [
Expand Down
73 changes: 73 additions & 0 deletions phpunit/class-wp-theme-json-test.php
Expand Up @@ -188,6 +188,79 @@ function test_get_settings_presets_are_keyed_by_origin() {
$this->assertEqualSetsWithIndex( $expected_no_origin, $actual_no_origin );
}

function test_get_settings_using_opt_in_key() {
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA,
'settings' => array(
'appearanceTools' => true,
'blocks' => array(
'core/paragraph' => array(
'typography' => array(
'lineHeight' => false,
),
),
'core/group' => array(
'appearanceTools' => true,
'typography' => array(
'lineHeight' => false, // This should override appearanceTools.
),
),
),
),
)
);

$actual = $theme_json->get_settings();
$expected = array(
'border' => array(
'width' => true,
'style' => true,
'radius' => true,
'color' => true,
),
'color' => array(
'link' => true,
),
'spacing' => array(
'blockGap' => true,
'margin' => true,
'padding' => true,
),
'typography' => array(
'lineHeight' => true,
),
'blocks' => array(
'core/paragraph' => array(
'typography' => array(
'lineHeight' => false,
),
),
'core/group' => array(
'border' => array(
'width' => true,
'style' => true,
'radius' => true,
'color' => true,
),
'color' => array(
'link' => true,
),
'spacing' => array(
'blockGap' => true,
'margin' => true,
'padding' => true,
),
'typography' => array(
'lineHeight' => false,
),
),
),
);

$this->assertEqualSetsWithIndex( $expected, $actual );
}

function test_get_stylesheet_support_for_shorthand_and_longhand_values() {
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
Expand Down
5 changes: 5 additions & 0 deletions schemas/json/theme.json
Expand Up @@ -9,6 +9,11 @@
},
"settingsProperties": {
"properties": {
"appearanceTools": {
"description": "Setting that enables ui tools. \nGutenberg plugin required.",
"type": "boolean",
"default": false
},
"border": {
"description": "Settings related to borders.\nGutenberg plugin required.",
"type": "object",
Expand Down