Editor: Backport Elements API updates.
This commit backports the original PRs from Gutenberg repository: * [https://github.com/WordPress/gutenberg/pull/40260 #40260 Add support for button elements to theme.json] * [https://github.com/WordPress/gutenberg/pull/40889 #40889 Theme Json: Don't output double selectors for elements inside blocks] * [https://github.com/WordPress/gutenberg/pull/41140 #41140 Global Styles: Add support for caption elements] * [https://github.com/WordPress/gutenberg/pull/41160 #41160 Global Styles: Load block CSS conditionally] * [https://github.com/WordPress/gutenberg/pull/41240 #41240 Global Styles: Button Element: update button element selector] * [https://github.com/WordPress/gutenberg/pull/41335 #41335 Duotone: Fix CSS Selectors rendered by theme.json duotone/filter settings for blocks on public pages] * [https://github.com/WordPress/gutenberg/pull/41446 #41446 Block styles: Account for style block nodes that have no name] * [https://github.com/WordPress/gutenberg/pull/41696 #41696 Global Styles: Allow references to values in other locations in the tree] * [https://github.com/WordPress/gutenberg/pull/41753 #41753 Elements: Add an API make it easier to get class names] * [https://github.com/WordPress/gutenberg/pull/41786 #41786 Support pseudo selectors on elements in theme json] * [https://github.com/WordPress/gutenberg/pull/41822 #41822 Elements: Button - Fix element selectors] * [https://github.com/WordPress/gutenberg/pull/41981 #41981 Global Styles: Add support for heading elements] * [https://github.com/WordPress/gutenberg/pull/42072 #42072 Fix link element hover bleeding into button element default styles] * [https://github.com/WordPress/gutenberg/pull/42096 #42096 Add visited to link element allowed pseudo selector list] * [https://github.com/WordPress/gutenberg/pull/42669 #42669 Link elements: Add a :where selector to the :not to lower specificity] * [https://github.com/WordPress/gutenberg/pull/42776 #42776 Theme JSON: Add a static $blocks_metadata data definition to the Gutenberg instance of WP_Theme_JSON] * [https://github.com/WordPress/gutenberg/pull/43088 #43088 Pseudo elements supports on button elements] * [https://github.com/WordPress/gutenberg/pull/43167 #43167 Theme_JSON: Use existing append_to_selector for pseudo elements] * [https://github.com/WordPress/gutenberg/pull/43988 #43988 Styles API: Fixed selectors for nested elements] Props onemaggie, bernhard-reiter, cbravobernal, mmaattiiaass, scruffian, andraganescu, dpcalhoun, get_dave, Mamaduka, SergeyBiryukov. See #56467. Built from https://develop.svn.wordpress.org/trunk@54118 git-svn-id: http://core.svn.wordpress.org/trunk@53677 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
9ba0095255
commit
70c0f6f0e1
|
@ -343,15 +343,27 @@ class WP_Theme_JSON {
|
|||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Defines which pseudo selectors are enabled for which elements.
|
||||
*
|
||||
* Note: this will affect both top-level and block-level elements.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*/
|
||||
const VALID_ELEMENT_PSEUDO_SELECTORS = array(
|
||||
'link' => array( ':hover', ':focus', ':active', ':visited' ),
|
||||
'button' => array( ':hover', ':focus', ':active', ':visited' ),
|
||||
);
|
||||
|
||||
/**
|
||||
* The valid elements that can be found under styles.
|
||||
*
|
||||
* @since 5.8.0
|
||||
* @since 6.1.0 Added `heading`, `button`, and `caption` to the elements.
|
||||
* @since 6.1.0 Added `heading`, `button`. and `caption` elements.
|
||||
* @var string[]
|
||||
*/
|
||||
const ELEMENTS = array(
|
||||
'link' => 'a',
|
||||
'link' => 'a:where(:not(.wp-element-button))', // The `where` is needed to lower the specificity.
|
||||
'heading' => 'h1, h2, h3, h4, h5, h6',
|
||||
'h1' => 'h1',
|
||||
'h2' => 'h2',
|
||||
|
@ -365,6 +377,29 @@ class WP_Theme_JSON {
|
|||
'caption' => '.wp-element-caption, .wp-block-audio figcaption, .wp-block-embed figcaption, .wp-block-gallery figcaption, .wp-block-image figcaption, .wp-block-table figcaption, .wp-block-video figcaption',
|
||||
);
|
||||
|
||||
const __EXPERIMENTAL_ELEMENT_CLASS_NAMES = array(
|
||||
'button' => 'wp-element-button',
|
||||
'caption' => 'wp-element-caption',
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns a class name by an element name.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*
|
||||
* @param string $element The name of the element.
|
||||
* @return string The name of the class.
|
||||
*/
|
||||
public static function get_element_class_name( $element ) {
|
||||
$class_name = '';
|
||||
|
||||
if ( array_key_exists( $element, static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES ) ) {
|
||||
$class_name = static::__EXPERIMENTAL_ELEMENT_CLASS_NAMES[ $element ];
|
||||
}
|
||||
|
||||
return $class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options that settings.appearanceTools enables.
|
||||
*
|
||||
|
@ -488,16 +523,21 @@ class WP_Theme_JSON {
|
|||
* @return array The sanitized output.
|
||||
*/
|
||||
protected static function sanitize( $input, $valid_block_names, $valid_element_names ) {
|
||||
|
||||
$output = array();
|
||||
|
||||
if ( ! is_array( $input ) ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
// Preserve only the top most level keys.
|
||||
$output = array_intersect_key( $input, array_flip( static::VALID_TOP_LEVEL_KEYS ) );
|
||||
|
||||
// Some styles are only meant to be available at the top-level (e.g.: blockGap),
|
||||
// hence, the schema for blocks & elements should not have them.
|
||||
/*
|
||||
* Remove any rules that are annotated as "top" in VALID_STYLES constant.
|
||||
* Some styles are only meant to be available at the top-level (e.g.: blockGap),
|
||||
* hence, the schema for blocks & elements should not have them.
|
||||
*/
|
||||
$styles_non_top_level = static::VALID_STYLES;
|
||||
foreach ( array_keys( $styles_non_top_level ) as $section ) {
|
||||
foreach ( array_keys( $styles_non_top_level[ $section ] ) as $prop ) {
|
||||
|
@ -510,9 +550,24 @@ class WP_Theme_JSON {
|
|||
// Build the schema based on valid block & element names.
|
||||
$schema = array();
|
||||
$schema_styles_elements = array();
|
||||
|
||||
/*
|
||||
* Set allowed element pseudo selectors based on per element allow list.
|
||||
* Target data structure in schema:
|
||||
* e.g.
|
||||
* - top level elements: `$schema['styles']['elements']['link'][':hover']`.
|
||||
* - block level elements: `$schema['styles']['blocks']['core/button']['elements']['link'][':hover']`.
|
||||
*/
|
||||
foreach ( $valid_element_names as $element ) {
|
||||
$schema_styles_elements[ $element ] = $styles_non_top_level;
|
||||
|
||||
if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
|
||||
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
|
||||
$schema_styles_elements[ $element ][ $pseudo_selector ] = $styles_non_top_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$schema_styles_blocks = array();
|
||||
$schema_settings_blocks = array();
|
||||
foreach ( $valid_block_names as $block ) {
|
||||
|
@ -520,6 +575,7 @@ class WP_Theme_JSON {
|
|||
$schema_styles_blocks[ $block ] = $styles_non_top_level;
|
||||
$schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
|
||||
}
|
||||
|
||||
$schema['styles'] = static::VALID_STYLES;
|
||||
$schema['styles']['blocks'] = $schema_styles_blocks;
|
||||
$schema['styles']['elements'] = $schema_styles_elements;
|
||||
|
@ -549,6 +605,30 @@ class WP_Theme_JSON {
|
|||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a sub-selector to an existing one.
|
||||
*
|
||||
* Given the compounded $selector "h1, h2, h3"
|
||||
* and the $to_append selector ".some-class" the result will be
|
||||
* "h1.some-class, h2.some-class, h3.some-class".
|
||||
*
|
||||
* @since 5.8.0
|
||||
* @since 6.1.0 Added append position.
|
||||
*
|
||||
* @param string $selector Original selector.
|
||||
* @param string $to_append Selector to append.
|
||||
* @param string $position A position sub-selector should be appended. Default 'right'.
|
||||
* @return string
|
||||
*/
|
||||
protected static function append_to_selector( $selector, $to_append, $position = 'right' ) {
|
||||
$new_selectors = array();
|
||||
$selectors = explode( ',', $selector );
|
||||
foreach ( $selectors as $sel ) {
|
||||
$new_selectors[] = 'right' === $position ? $sel . $to_append : $to_append . $sel;
|
||||
}
|
||||
return implode( ',', $new_selectors );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metadata for each block.
|
||||
*
|
||||
|
@ -611,7 +691,11 @@ class WP_Theme_JSON {
|
|||
foreach ( static::ELEMENTS as $el_name => $el_selector ) {
|
||||
$element_selector = array();
|
||||
foreach ( $block_selectors as $selector ) {
|
||||
$element_selector[] = $selector . ' ' . $el_selector;
|
||||
if ( $selector === $el_selector ) {
|
||||
$element_selector = array( $el_selector );
|
||||
break;
|
||||
}
|
||||
$element_selector[] = static::append_to_selector( $el_selector, $selector . ' ', 'left' );
|
||||
}
|
||||
static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector );
|
||||
}
|
||||
|
@ -810,54 +894,7 @@ class WP_Theme_JSON {
|
|||
if ( null === $metadata['selector'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$node = _wp_array_get( $this->theme_json, $metadata['path'], array() );
|
||||
$selector = $metadata['selector'];
|
||||
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
|
||||
$declarations = static::compute_style_properties( $node, $settings );
|
||||
|
||||
// 1. Separate the ones who use the general selector
|
||||
// and the ones who use the duotone selector.
|
||||
$declarations_duotone = array();
|
||||
foreach ( $declarations as $index => $declaration ) {
|
||||
if ( 'filter' === $declaration['name'] ) {
|
||||
unset( $declarations[ $index ] );
|
||||
$declarations_duotone[] = $declaration;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset default browser margin on the root body element.
|
||||
* This is set on the root selector **before** generating the ruleset
|
||||
* from the `theme.json`. This is to ensure that if the `theme.json` declares
|
||||
* `margin` in its `spacing` declaration for the `body` element then these
|
||||
* user-generated values take precedence in the CSS cascade.
|
||||
* @link https://github.com/WordPress/gutenberg/issues/36147.
|
||||
*/
|
||||
if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
|
||||
$block_rules .= 'body { margin: 0; }';
|
||||
}
|
||||
|
||||
// 2. Generate the rules that use the general selector.
|
||||
$block_rules .= static::to_ruleset( $selector, $declarations );
|
||||
|
||||
// 3. Generate the rules that use the duotone selector.
|
||||
if ( isset( $metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
|
||||
$selector_duotone = static::scope_selector( $metadata['selector'], $metadata['duotone'] );
|
||||
$block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone );
|
||||
}
|
||||
|
||||
if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
|
||||
$block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
|
||||
$block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
|
||||
$block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
|
||||
|
||||
$has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
|
||||
if ( $has_block_gap_support ) {
|
||||
$block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
|
||||
$block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
|
||||
}
|
||||
}
|
||||
$block_rules .= static::get_styles_for_block( $metadata );
|
||||
}
|
||||
|
||||
return $block_rules;
|
||||
|
@ -972,29 +1009,6 @@ class WP_Theme_JSON {
|
|||
return $selector . '{' . $declaration_block . '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that appends a sub-selector to a existing one.
|
||||
*
|
||||
* Given the compounded $selector "h1, h2, h3"
|
||||
* and the $to_append selector ".some-class" the result will be
|
||||
* "h1.some-class, h2.some-class, h3.some-class".
|
||||
*
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param string $selector Original selector.
|
||||
* @param string $to_append Selector to append.
|
||||
* @return string
|
||||
*/
|
||||
protected static function append_to_selector( $selector, $to_append ) {
|
||||
$new_selectors = array();
|
||||
$selectors = explode( ',', $selector );
|
||||
foreach ( $selectors as $sel ) {
|
||||
$new_selectors[] = $sel . $to_append;
|
||||
}
|
||||
|
||||
return implode( ',', $new_selectors );
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a settings array, it returns the generated rulesets
|
||||
* for the preset classes.
|
||||
|
@ -1312,13 +1326,15 @@ class WP_Theme_JSON {
|
|||
*
|
||||
* @since 5.8.0
|
||||
* @since 5.9.0 Added the `$settings` and `$properties` parameters.
|
||||
* @since 6.1.0 Added the `$theme_json` parameter.
|
||||
*
|
||||
* @param array $styles Styles to process.
|
||||
* @param array $settings Theme settings.
|
||||
* @param array $properties Properties metadata.
|
||||
* @param array $theme_json Theme JSON array.
|
||||
* @return array Returns the modified $declarations.
|
||||
*/
|
||||
protected static function compute_style_properties( $styles, $settings = array(), $properties = null ) {
|
||||
protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $theme_json = null ) {
|
||||
if ( null === $properties ) {
|
||||
$properties = static::PROPERTIES_METADATA;
|
||||
}
|
||||
|
@ -1329,7 +1345,7 @@ class WP_Theme_JSON {
|
|||
}
|
||||
|
||||
foreach ( $properties as $css_property => $value_path ) {
|
||||
$value = static::get_property_value( $styles, $value_path );
|
||||
$value = static::get_property_value( $styles, $value_path, $theme_json );
|
||||
|
||||
// Look up protected properties, keyed by value path.
|
||||
// Skip protected properties that are explicitly set to `null`.
|
||||
|
@ -1365,20 +1381,58 @@ class WP_Theme_JSON {
|
|||
* "var:preset|color|secondary" to the form
|
||||
* "--wp--preset--color--secondary".
|
||||
*
|
||||
* It also converts references to a path to the value
|
||||
* stored at that location, e.g.
|
||||
* { "ref": "style.color.background" } => "#fff".
|
||||
*
|
||||
* @since 5.8.0
|
||||
* @since 5.9.0 Added support for values of array type, which are returned as is.
|
||||
* @since 6.1.0 Added the `$theme_json` parameter.
|
||||
*
|
||||
* @param array $styles Styles subtree.
|
||||
* @param array $path Which property to process.
|
||||
* @param array $theme_json Theme JSON array.
|
||||
* @return string|array Style property value.
|
||||
*/
|
||||
protected static function get_property_value( $styles, $path ) {
|
||||
protected static function get_property_value( $styles, $path, $theme_json = null ) {
|
||||
$value = _wp_array_get( $styles, $path, '' );
|
||||
|
||||
/*
|
||||
* This converts references to a path to the value at that path
|
||||
* where the values is an array with a "ref" key, pointing to a path.
|
||||
* For example: { "ref": "style.color.background" } => "#fff".
|
||||
*/
|
||||
if ( is_array( $value ) && array_key_exists( 'ref', $value ) ) {
|
||||
$value_path = explode( '.', $value['ref'] );
|
||||
$ref_value = _wp_array_get( $theme_json, $value_path );
|
||||
// Only use the ref value if we find anything.
|
||||
if ( ! empty( $ref_value ) && is_string( $ref_value ) ) {
|
||||
$value = $ref_value;
|
||||
}
|
||||
|
||||
if ( is_array( $ref_value ) && array_key_exists( 'ref', $ref_value ) ) {
|
||||
$path_string = json_encode( $path );
|
||||
$ref_value_string = json_encode( $ref_value );
|
||||
_doing_it_wrong(
|
||||
'get_property_value',
|
||||
sprintf(
|
||||
/* translators: 1: theme.json, 2: Value name, 3: Value path, 4: Another value name. */
|
||||
__( 'Your %1$s file uses a dynamic value (%2$s) for the path at %3$s. However, the value at %3$s is also a dynamic value (pointing to %4$s) and pointing to another dynamic value is not supported. Please update %3$s to point directly to %4$s.' ),
|
||||
'theme.json',
|
||||
$ref_value_string,
|
||||
$path_string,
|
||||
$ref_value['ref']
|
||||
),
|
||||
'6.1.0'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( '' === $value || is_array( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Convert custom CSS properties.
|
||||
$prefix = 'var:';
|
||||
$prefix_len = strlen( $prefix );
|
||||
$token_in = '|';
|
||||
|
@ -1490,6 +1544,19 @@ class WP_Theme_JSON {
|
|||
'path' => array( 'styles', 'elements', $element ),
|
||||
'selector' => static::ELEMENTS[ $element ],
|
||||
);
|
||||
|
||||
// Handle any pseudo selectors for the element.
|
||||
if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
|
||||
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
|
||||
|
||||
if ( isset( $theme_json['styles']['elements'][ $element ][ $pseudo_selector ] ) ) {
|
||||
$nodes[] = array(
|
||||
'path' => array( 'styles', 'elements', $element ),
|
||||
'selector' => static::append_to_selector( static::ELEMENTS[ $element ], $pseudo_selector ),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1498,6 +1565,51 @@ class WP_Theme_JSON {
|
|||
return $nodes;
|
||||
}
|
||||
|
||||
$nodes = array_merge( $nodes, static::get_block_nodes( $theme_json ) );
|
||||
|
||||
/**
|
||||
* Filters the list of style nodes with metadata.
|
||||
*
|
||||
* This allows for things like loading block CSS independently.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*
|
||||
* @param array $nodes Style nodes with metadata.
|
||||
*/
|
||||
return apply_filters( 'get_style_nodes', $nodes );
|
||||
}
|
||||
|
||||
/**
|
||||
* A public helper to get the block nodes from a theme.json file.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*
|
||||
* @return array The block nodes in theme.json.
|
||||
*/
|
||||
public function get_styles_block_nodes() {
|
||||
return static::get_block_nodes( $this->theme_json );
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal method to get the block nodes from a theme.json file.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*
|
||||
* @param array $theme_json The theme.json converted to an array.
|
||||
* @return array The block nodes in theme.json.
|
||||
*/
|
||||
private static function get_block_nodes( $theme_json ) {
|
||||
$selectors = static::get_blocks_metadata();
|
||||
$nodes = array();
|
||||
if ( ! isset( $theme_json['styles'] ) ) {
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
// Blocks.
|
||||
if ( ! isset( $theme_json['styles']['blocks'] ) ) {
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
foreach ( $theme_json['styles']['blocks'] as $name => $node ) {
|
||||
$selector = null;
|
||||
if ( isset( $selectors[ $name ]['selector'] ) ) {
|
||||
|
@ -1510,6 +1622,7 @@ class WP_Theme_JSON {
|
|||
}
|
||||
|
||||
$nodes[] = array(
|
||||
'name' => $name,
|
||||
'path' => array( 'styles', 'blocks', $name ),
|
||||
'selector' => $selector,
|
||||
'duotone' => $duotone_selector,
|
||||
|
@ -1521,6 +1634,18 @@ class WP_Theme_JSON {
|
|||
'path' => array( 'styles', 'blocks', $name, 'elements', $element ),
|
||||
'selector' => $selectors[ $name ]['elements'][ $element ],
|
||||
);
|
||||
|
||||
// Handle any pseudo selectors for the element.
|
||||
if ( array_key_exists( $element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
|
||||
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $element ] as $pseudo_selector ) {
|
||||
if ( isset( $theme_json['styles']['blocks'][ $name ]['elements'][ $element ][ $pseudo_selector ] ) ) {
|
||||
$nodes[] = array(
|
||||
'path' => array( 'styles', 'blocks', $name, 'elements', $element ),
|
||||
'selector' => static::append_to_selector( $selectors[ $name ]['elements'][ $element ], $pseudo_selector ),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1528,6 +1653,116 @@ class WP_Theme_JSON {
|
|||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CSS rules for a particular block from theme.json.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*
|
||||
* @param array $block_metadata Meta data about the block to get styles for.
|
||||
* @return array Styles for the block.
|
||||
*/
|
||||
public function get_styles_for_block( $block_metadata ) {
|
||||
|
||||
$node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
|
||||
|
||||
$selector = $block_metadata['selector'];
|
||||
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
|
||||
|
||||
/*
|
||||
* Get a reference to element name from path.
|
||||
* $block_metadata['path'] = array( 'styles','elements','link' );
|
||||
* Make sure that $block_metadata['path'] describes an element node, like [ 'styles', 'element', 'link' ].
|
||||
* Skip non-element paths like just ['styles'].
|
||||
*/
|
||||
$is_processing_element = in_array( 'elements', $block_metadata['path'], true );
|
||||
|
||||
$current_element = $is_processing_element ? $block_metadata['path'][ count( $block_metadata['path'] ) - 1 ] : null;
|
||||
|
||||
$element_pseudo_allowed = array();
|
||||
|
||||
if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
|
||||
$element_pseudo_allowed = static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ];
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for allowed pseudo classes (e.g. ":hover") from the $selector ("a:hover").
|
||||
* This also resets the array keys.
|
||||
*/
|
||||
$pseudo_matches = array_values(
|
||||
array_filter(
|
||||
$element_pseudo_allowed,
|
||||
function( $pseudo_selector ) use ( $selector ) {
|
||||
return str_contains( $selector, $pseudo_selector );
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$pseudo_selector = isset( $pseudo_matches[0] ) ? $pseudo_matches[0] : null;
|
||||
|
||||
/*
|
||||
* If the current selector is a pseudo selector that's defined in the allow list for the current
|
||||
* element then compute the style properties for it.
|
||||
* Otherwise just compute the styles for the default selector as normal.
|
||||
*/
|
||||
if ( $pseudo_selector && isset( $node[ $pseudo_selector ] ) &&
|
||||
array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS )
|
||||
&& in_array( $pseudo_selector, static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ], true )
|
||||
) {
|
||||
$declarations = static::compute_style_properties( $node[ $pseudo_selector ], $settings, null, $this->theme_json );
|
||||
} else {
|
||||
$declarations = static::compute_style_properties( $node, $settings, null, $this->theme_json );
|
||||
}
|
||||
|
||||
$block_rules = '';
|
||||
|
||||
/*
|
||||
* 1. Separate the declarations that use the general selector
|
||||
* from the ones using the duotone selector.
|
||||
*/
|
||||
$declarations_duotone = array();
|
||||
foreach ( $declarations as $index => $declaration ) {
|
||||
if ( 'filter' === $declaration['name'] ) {
|
||||
unset( $declarations[ $index ] );
|
||||
$declarations_duotone[] = $declaration;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset default browser margin on the root body element.
|
||||
* This is set on the root selector **before** generating the ruleset
|
||||
* from the `theme.json`. This is to ensure that if the `theme.json` declares
|
||||
* `margin` in its `spacing` declaration for the `body` element then these
|
||||
* user-generated values take precedence in the CSS cascade.
|
||||
* @link https://github.com/WordPress/gutenberg/issues/36147.
|
||||
*/
|
||||
if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
|
||||
$block_rules .= 'body { margin: 0; }';
|
||||
}
|
||||
|
||||
// 2. Generate and append the rules that use the general selector.
|
||||
$block_rules .= static::to_ruleset( $selector, $declarations );
|
||||
|
||||
// 3. Generate and append the rules that use the duotone selector.
|
||||
if ( isset( $block_metadata['duotone'] ) && ! empty( $declarations_duotone ) ) {
|
||||
$selector_duotone = static::scope_selector( $block_metadata['selector'], $block_metadata['duotone'] );
|
||||
$block_rules .= static::to_ruleset( $selector_duotone, $declarations_duotone );
|
||||
}
|
||||
|
||||
if ( static::ROOT_BLOCK_SELECTOR === $selector ) {
|
||||
$block_rules .= '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
|
||||
$block_rules .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
|
||||
$block_rules .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';
|
||||
|
||||
$has_block_gap_support = _wp_array_get( $this->theme_json, array( 'settings', 'spacing', 'blockGap' ) ) !== null;
|
||||
if ( $has_block_gap_support ) {
|
||||
$block_rules .= '.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
|
||||
$block_rules .= '.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
|
||||
}
|
||||
}
|
||||
|
||||
return $block_rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* For metadata values that can either be booleans or paths to booleans, gets the value.
|
||||
*
|
||||
|
@ -1837,10 +2072,12 @@ class WP_Theme_JSON {
|
|||
|
||||
$valid_block_names = array_keys( static::get_blocks_metadata() );
|
||||
$valid_element_names = array_keys( static::ELEMENTS );
|
||||
$theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names );
|
||||
|
||||
$theme_json = static::sanitize( $theme_json, $valid_block_names, $valid_element_names );
|
||||
|
||||
$blocks_metadata = static::get_blocks_metadata();
|
||||
$style_nodes = static::get_style_nodes( $theme_json, $blocks_metadata );
|
||||
|
||||
foreach ( $style_nodes as $metadata ) {
|
||||
$input = _wp_array_get( $theme_json, $metadata['path'], array() );
|
||||
if ( empty( $input ) ) {
|
||||
|
@ -1848,6 +2085,25 @@ class WP_Theme_JSON {
|
|||
}
|
||||
|
||||
$output = static::remove_insecure_styles( $input );
|
||||
|
||||
/*
|
||||
* Get a reference to element name from path.
|
||||
* $metadata['path'] = array( 'styles', 'elements', 'link' );
|
||||
*/
|
||||
$current_element = $metadata['path'][ count( $metadata['path'] ) - 1 ];
|
||||
|
||||
/*
|
||||
* $output is stripped of pseudo selectors. Re-add and process them
|
||||
* or insecure styles here.
|
||||
*/
|
||||
if ( array_key_exists( $current_element, static::VALID_ELEMENT_PSEUDO_SELECTORS ) ) {
|
||||
foreach ( static::VALID_ELEMENT_PSEUDO_SELECTORS[ $current_element ] as $pseudo_selector ) {
|
||||
if ( isset( $input[ $pseudo_selector ] ) ) {
|
||||
$output[ $pseudo_selector ] = static::remove_insecure_styles( $input[ $pseudo_selector ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $output ) ) {
|
||||
_wp_array_set( $sanitized, $metadata['path'], $output );
|
||||
}
|
||||
|
|
|
@ -192,3 +192,45 @@ function wp_get_global_styles_svg_filters() {
|
|||
|
||||
return $svgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds global style rules to the inline style for each block.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*/
|
||||
function wp_add_global_styles_for_blocks() {
|
||||
$tree = WP_Theme_JSON_Resolver::get_merged_data();
|
||||
$block_nodes = $tree->get_styles_block_nodes();
|
||||
foreach ( $block_nodes as $metadata ) {
|
||||
$block_css = $tree->get_styles_for_block( $metadata );
|
||||
|
||||
if ( isset( $metadata['name'] ) ) {
|
||||
$block_name = str_replace( 'core/', '', $metadata['name'] );
|
||||
/*
|
||||
* These block styles are added on block_render.
|
||||
* This hooks inline CSS to them so that they are loaded conditionally
|
||||
* based on whether or not the block is used on the page.
|
||||
*/
|
||||
wp_add_inline_style( 'wp-block-' . $block_name, $block_css );
|
||||
}
|
||||
|
||||
// The likes of block element styles from theme.json do not have $metadata['name'] set.
|
||||
if ( ! isset( $metadata['name'] ) && ! empty( $metadata['path'] ) ) {
|
||||
$result = array_values(
|
||||
array_filter(
|
||||
$metadata['path'],
|
||||
function ( $item ) {
|
||||
if ( strpos( $item, 'core/' ) !== false ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
)
|
||||
);
|
||||
if ( isset( $result[0] ) ) {
|
||||
$block_name = str_replace( 'core/', '', $result[0] );
|
||||
wp_add_inline_style( 'wp-block-' . $block_name, $block_css );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2353,6 +2353,30 @@ function wp_common_block_scripts_and_styles() {
|
|||
do_action( 'enqueue_block_assets' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a filter to the list of style nodes that comes from WP_Theme_JSON::get_style_nodes().
|
||||
*
|
||||
* This particular filter removes all of the blocks from the array.
|
||||
*
|
||||
* We want WP_Theme_JSON to be ignorant of the implementation details of how the CSS is being used.
|
||||
* This filter allows us to modify the output of WP_Theme_JSON depending on whether or not we are
|
||||
* loading separate assets, without making the class aware of that detail.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*
|
||||
* @param array $nodes The nodes to filter.
|
||||
* @return array A filtered array of style nodes.
|
||||
*/
|
||||
function wp_filter_out_block_nodes( $nodes ) {
|
||||
return array_filter(
|
||||
$nodes,
|
||||
function( $node ) {
|
||||
return ! in_array( 'blocks', $node['path'], true );
|
||||
},
|
||||
ARRAY_FILTER_USE_BOTH
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the global styles defined via theme.json.
|
||||
*
|
||||
|
@ -2377,6 +2401,16 @@ function wp_enqueue_global_styles() {
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are loading CSS for each block separately, then we can load the theme.json CSS conditionally.
|
||||
* This removes the CSS from the global-styles stylesheet and adds it to the inline CSS for each block.
|
||||
*/
|
||||
if ( $separate_assets ) {
|
||||
add_filter( 'get_style_nodes', 'wp_filter_out_block_nodes' );
|
||||
// Add each block as an inline css.
|
||||
wp_add_global_styles_for_blocks();
|
||||
}
|
||||
|
||||
$stylesheet = wp_get_global_stylesheet();
|
||||
|
||||
if ( empty( $stylesheet ) ) {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '6.1-alpha-54117';
|
||||
$wp_version = '6.1-alpha-54118';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue