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

Allow themes to use any styles in the theme.json whether or not the block supports it #29941

Merged
merged 7 commits into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
76 changes: 2 additions & 74 deletions docs/how-to-guides/themes/theme-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ The Block Editor already allows the control of specific settings such as alignme
Examples of what can be achieved are:

- Use a particular preset for a block (e.g.: table) but the common one for the rest of blocks.
- Enable font size UI controls for all blocks that support it but the headings block.
- Enable font size UI controls for all blocks but the headings block.
- etc.

### Some block styles are managed
Expand Down Expand Up @@ -315,7 +315,7 @@ Note that, the name of the variable is created by adding `--` in between each ne

### Styles

Each block declares which style properties it exposes via the [block supports mechanism](../block-api/block-supports.md). The support declarations are used to automatically generate the UI controls for the block in the editor, as well as being available through the `experimental-theme.json` file for themes to target.
Each block declares which style properties it exposes via the [block supports mechanism](../block-api/block-supports.md). The support declarations are used to automatically generate the UI controls for the block in the editor. Themes can use any style property via the `experimental-theme.json` for any block ― it's the theme's responsibility to verify that it works properly according the block markup, etc.
oandregal marked this conversation as resolved.
Show resolved Hide resolved

```json
{
Expand Down Expand Up @@ -401,78 +401,6 @@ h4 {

The `defaults` block selector can't be part of the `styles` section and will be ignored if it's present. The `root` block selector will generate a style rule with the `:root` CSS selector.

#### Border Properties

| Block | Color | Radius | Style | Width |
| --- | --- | --- | --- | --- |
| Group | Yes | Yes | Yes | Yes |
| Image | Yes | - | - | - |

#### Color Properties

These are the current color properties supported by blocks:

| Block | Background | Gradient | Link | Text |
| --- | --- | --- | --- | --- |
| Global | Yes | Yes | Yes | Yes |
| Columns | Yes | Yes | Yes | Yes |
| Group | Yes | Yes | Yes | Yes |
| Heading [1] | Yes | - | Yes | Yes |
| List | Yes | Yes | - | Yes |
| Media & text | Yes | Yes | Yes | Yes |
| Navigation | Yes | - | - | Yes |
| Paragraph | Yes | - | Yes | Yes |
| Post Author | Yes | Yes | Yes | Yes |
| Post Comments | Yes | Yes | Yes | Yes |
| Post Comments Count | Yes | Yes | - | Yes |
| Post Comments Form | Yes | Yes | Yes | Yes |
| Post Date | Yes | Yes | - | Yes |
| Post Excerpt | Yes | Yes | Yes | Yes |
| Post Hierarchical Terms | Yes | Yes | Yes | Yes |
| Post Tags | Yes | Yes | Yes | Yes |
| Post Title | Yes | Yes | - | Yes |
| Site Tagline | Yes | Yes | - | Yes |
| Site Title | Yes | Yes | Yes | - |
| Template Part | Yes | Yes | Yes | Yes |

[1] The heading block represents 6 distinct HTML elements: H1-H6. It comes with selectors to target each individual element (ex: core/heading/h1 for H1, etc).

#### Spacing Properties

| Block | Padding |
| --- | --- |
| Cover | Yes |
| Group | Yes |

#### Typography Properties

These are the current typography properties supported by blocks:

| Block | Font Family | Font Size | Font Style | Font Weight | Line Height | Text Decoration | Text Transform |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Global | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
| Code | - | Yes | - | - | - | - | - |
| Heading [1] | - | Yes | - | - | Yes | - | - |
| List | - | Yes | - | - | - | - | - |
| Navigation | Yes | Yes | Yes | Yes | - | Yes | Yes |
| Paragraph | - | Yes | - | - | Yes | - | - |
| Post Author | - | Yes | - | - | Yes | - | - |
| Post Comments | - | Yes | - | - | Yes | - | - |
| Post Comments Count | - | Yes | - | - | Yes | - | - |
| Post Comments Form | - | Yes | - | - | Yes | - | - |
| Post Date | - | Yes | - | - | Yes | - | - |
| Post Excerpt | - | Yes | - | - | Yes | - | - |
| Post Hierarchical Terms | - | Yes | - | - | Yes | - | - |
| Post Tags | - | Yes | - | - | Yes | - | - |
| Post Title | Yes | Yes | - | - | Yes | - | - |
| Preformatted | - | Yes | - | - | - | - | - |
| Site Tagline | Yes | Yes | - | - | Yes | - | - |
| Site Title | Yes | Yes | - | - | Yes | - | Yes |
| Verse | Yes | Yes | - | - | - | - | - |

[1] The heading block represents 6 distinct HTML elements: H1-H6. It comes with selectors to target each individual element (ex: core/heading/h1 for H1, etc).


### Other theme metadata

There's a growing need to add more theme metadata to the theme.json. This section lists those other fields:
Expand Down
109 changes: 19 additions & 90 deletions lib/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,6 @@ class WP_Theme_JSON {
*/
const ROOT_BLOCK_SELECTOR = ':root';

/**
* The supported properties of the root block.
*
* @var array
*/
const ROOT_BLOCK_SUPPORTS = array(
'--wp--style--color--link',
'background',
'backgroundColor',
'color',
'fontFamily',
'fontSize',
'fontStyle',
'fontWeight',
'lineHeight',
'textDecoration',
'textTransform',
);

/**
* Data schema of each block within a theme.json.
*
Expand Down Expand Up @@ -254,73 +235,56 @@ class WP_Theme_JSON {
* Each property declares:
*
* - 'value': path to the value in theme.json and block attributes.
* - 'support': path to the block support in block.json.
*/
const PROPERTIES_METADATA = array(
'--wp--style--color--link' => array(
'value' => array( 'color', 'link' ),
'support' => array( 'color', 'link' ),
'value' => array( 'color', 'link' ),
),
'background' => array(
'value' => array( 'color', 'gradient' ),
'support' => array( 'color', 'gradients' ),
'value' => array( 'color', 'gradient' ),
),
'backgroundColor' => array(
'value' => array( 'color', 'background' ),
'support' => array( 'color' ),
'value' => array( 'color', 'background' ),
),
'borderRadius' => array(
'value' => array( 'border', 'radius' ),
'support' => array( '__experimentalBorder', 'radius' ),
'value' => array( 'border', 'radius' ),
),
'borderColor' => array(
'value' => array( 'border', 'color' ),
'support' => array( '__experimentalBorder', 'color' ),
'value' => array( 'border', 'color' ),
),
'borderWidth' => array(
'value' => array( 'border', 'width' ),
'support' => array( '__experimentalBorder', 'width' ),
'value' => array( 'border', 'width' ),
),
'borderStyle' => array(
'value' => array( 'border', 'style' ),
'support' => array( '__experimentalBorder', 'style' ),
'value' => array( 'border', 'style' ),
),
'color' => array(
'value' => array( 'color', 'text' ),
'support' => array( 'color' ),
'value' => array( 'color', 'text' ),
),
'fontFamily' => array(
'value' => array( 'typography', 'fontFamily' ),
'support' => array( '__experimentalFontFamily' ),
'value' => array( 'typography', 'fontFamily' ),
),
'fontSize' => array(
'value' => array( 'typography', 'fontSize' ),
'support' => array( 'fontSize' ),
'value' => array( 'typography', 'fontSize' ),
),
'fontStyle' => array(
'value' => array( 'typography', 'fontStyle' ),
'support' => array( '__experimentalFontStyle' ),
'value' => array( 'typography', 'fontStyle' ),
),
'fontWeight' => array(
'value' => array( 'typography', 'fontWeight' ),
'support' => array( '__experimentalFontWeight' ),
'value' => array( 'typography', 'fontWeight' ),
),
'lineHeight' => array(
'value' => array( 'typography', 'lineHeight' ),
'support' => array( 'lineHeight' ),
'value' => array( 'typography', 'lineHeight' ),
),
'padding' => array(
'value' => array( 'spacing', 'padding' ),
'support' => array( 'spacing', 'padding' ),
'properties' => array( 'top', 'right', 'bottom', 'left' ),
),
'textDecoration' => array(
'value' => array( 'typography', 'textDecoration' ),
'support' => array( '__experimentalTextDecoration' ),
'value' => array( 'typography', 'textDecoration' ),
),
'textTransform' => array(
'value' => array( 'typography', 'textTransform' ),
'support' => array( '__experimentalTextTransform' ),
'value' => array( 'typography', 'textTransform' ),
),
);

Expand Down Expand Up @@ -360,14 +324,7 @@ public function __construct( $theme_json = array() ) {
continue;
}

// Remove the properties the block doesn't support.
// This is a subset of the full styles schema.
$styles_schema = self::SCHEMA['styles'];
foreach ( self::PROPERTIES_METADATA as $prop_name => $prop_meta ) {
if ( ! in_array( $prop_name, $metadata['supports'], true ) ) {
unset( $styles_schema[ $prop_meta['value'][0] ][ $prop_meta['value'][1] ] );
}
}
$styles_schema = self::SCHEMA['styles'];
$this->theme_json['styles'][ $block_selector ] = self::remove_keys_not_in_schema(
$this->theme_json['styles'][ $block_selector ],
$styles_schema
Expand Down Expand Up @@ -476,11 +433,9 @@ private static function get_case_mappings() {
* {
* 'root': {
* 'selector': ':root'
* 'supports': [ 'fontSize', 'backgroundColor' ],
* },
* 'core/heading/h1': {
* 'selector': 'h1'
* 'supports': [ 'fontSize', 'backgroundColor' ],
* }
* }
*
Expand All @@ -494,31 +449,15 @@ private static function get_blocks_metadata() {
self::$blocks_metadata = array(
self::ROOT_BLOCK_NAME => array(
'selector' => self::ROOT_BLOCK_SELECTOR,
'supports' => self::ROOT_BLOCK_SUPPORTS,
),
// By make supports an empty array
// this won't have any styles associated
// but still allows adding settings
// and generate presets.
self::ALL_BLOCKS_NAME => array(
'selector' => self::ALL_BLOCKS_SELECTOR,
'supports' => array(),
),
);

$registry = WP_Block_Type_Registry::get_instance();
$blocks = $registry->get_all_registered();
foreach ( $blocks as $block_name => $block_type ) {
/*
* Extract block support keys that are related to the style properties.
*/
$block_supports = array();
foreach ( self::PROPERTIES_METADATA as $key => $metadata ) {
if ( _wp_array_get( $block_type->supports, $metadata['support'] ) ) {
$block_supports[] = $key;
}
}

/*
* Assign the selector for the block.
*
Expand All @@ -544,7 +483,6 @@ private static function get_blocks_metadata() {
) {
self::$blocks_metadata[ $block_name ] = array(
'selector' => $block_type->supports['__experimentalSelector'],
'supports' => $block_supports,
);
} elseif (
isset( $block_type->supports['__experimentalSelector'] ) &&
Expand All @@ -557,13 +495,11 @@ private static function get_blocks_metadata() {

self::$blocks_metadata[ $key ] = array(
'selector' => $selector_metadata['selector'],
'supports' => $block_supports,
);
}
} else {
self::$blocks_metadata[ $block_name ] = array(
'selector' => '.wp-block-' . str_replace( '/', '-', str_replace( 'core/', '', $block_name ) ),
'supports' => $block_supports,
);
}
}
Expand Down Expand Up @@ -718,21 +654,16 @@ private static function has_properties( $metadata ) {
*
* @param array $declarations Holds the existing declarations.
* @param array $styles Styles to process.
* @param array $supports Supports information for this block.
*
* @return array Returns the modified $declarations.
*/
private static function compute_style_properties( $declarations, $styles, $supports ) {
private static function compute_style_properties( $declarations, $styles ) {
if ( empty( $styles ) ) {
return $declarations;
}

$properties = array();
foreach ( self::PROPERTIES_METADATA as $name => $metadata ) {
if ( ! in_array( $name, $supports, true ) ) {
continue;
}

// Some properties can be shorthand properties, meaning that
// they contain multiple values instead of a single one.
// An example of this is the padding property, see self::SCHEMA.
Expand Down Expand Up @@ -992,14 +923,12 @@ private function get_block_styles() {
}

$selector = $metadata['selector'];
$supports = $metadata['supports'];

$declarations = array();
if ( isset( $this->theme_json['styles'][ $block_selector ] ) ) {
$declarations = self::compute_style_properties(
$declarations,
$this->theme_json['styles'][ $block_selector ],
$supports
$this->theme_json['styles'][ $block_selector ]
);
}

Expand Down Expand Up @@ -1141,7 +1070,7 @@ public function remove_insecure_properties() {

// Style escaping.
if ( isset( $this->theme_json['styles'][ $block_selector ] ) ) {
$declarations = self::compute_style_properties( array(), $this->theme_json['styles'][ $block_selector ], $metadata['supports'] );
$declarations = self::compute_style_properties( array(), $this->theme_json['styles'][ $block_selector ] );
foreach ( $declarations as $declaration ) {
$style_to_validate = $declaration['name'] . ': ' . $declaration['value'];
if ( esc_html( safecss_filter_attr( $style_to_validate ) ) === $style_to_validate ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,14 @@ function flattenTree( input = {}, prefix, token ) {
/**
* Transform given style tree into a set of style declarations.
*
* @param {Object} blockSupports What styles the block supports.
* @param {Object} blockStyles Block styles.
*
* @return {Array} An array of style declarations.
*/
function getBlockStylesDeclarations( blockSupports, blockStyles = {} ) {
function getBlockStylesDeclarations( blockStyles = {} ) {
return reduce(
STYLE_PROPERTY,
( declarations, { value, properties }, key ) => {
if ( ! blockSupports.includes( key ) ) {
return declarations;
}

if ( !! properties ) {
properties.forEach( ( prop ) => {
if ( ! get( blockStyles, [ ...value, prop ], false ) ) {
Expand Down Expand Up @@ -171,7 +166,6 @@ export default ( blockData, tree, type = 'all' ) => {
}
if ( type === 'all' || type === 'blockStyles' ) {
const blockStyleDeclarations = getBlockStylesDeclarations(
blockData[ context ].supports,
tree?.styles?.[ context ]
);

Expand Down
Loading