Skip to content

Commit 413cd3e

Browse files
committed
1 parent 9311668 commit 413cd3e

5 files changed

Lines changed: 735 additions & 85 deletions

File tree

src/wp-includes/block-supports/settings.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function _wp_add_block_level_presets_class( $block_content, $block ) {
6666
* @internal
6767
*
6868
* @since 6.2.0
69-
* @since 6.3.0 Updates preset styles to use Selectors API.
69+
* @since 6.3.0 Updated preset styles to use Selectors API.
7070
* @access private
7171
*
7272
* @param string|null $pre_render The pre-rendered content. Default null.

src/wp-includes/class-wp-theme-json.php

Lines changed: 183 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,7 @@ protected static function prepend_to_selector( $selector, $to_prepend ) {
865865
* @since 5.8.0
866866
* @since 5.9.0 Added `duotone` key with CSS selector.
867867
* @since 6.1.0 Added `features` key with block support feature level selectors.
868+
* @since 6.3.0 Refactored and stabilized selectors API.
868869
*
869870
* @return array Block metadata.
870871
*/
@@ -879,56 +880,33 @@ protected static function get_blocks_metadata() {
879880
}
880881

881882
foreach ( $blocks as $block_name => $block_type ) {
882-
if (
883-
isset( $block_type->supports['__experimentalSelector'] ) &&
884-
is_string( $block_type->supports['__experimentalSelector'] )
885-
) {
886-
static::$blocks_metadata[ $block_name ]['selector'] = $block_type->supports['__experimentalSelector'];
887-
} else {
888-
static::$blocks_metadata[ $block_name ]['selector'] = '.wp-block-' . str_replace( '/', '-', str_replace( 'core/', '', $block_name ) );
889-
}
883+
$root_selector = wp_get_block_css_selector( $block_type );
890884

891-
if (
892-
isset( $block_type->supports['color']['__experimentalDuotone'] ) &&
893-
is_string( $block_type->supports['color']['__experimentalDuotone'] )
894-
) {
895-
static::$blocks_metadata[ $block_name ]['duotone'] = $block_type->supports['color']['__experimentalDuotone'];
885+
static::$blocks_metadata[ $block_name ]['selector'] = $root_selector;
886+
static::$blocks_metadata[ $block_name ]['selectors'] = static::get_block_selectors( $block_type, $root_selector );
887+
888+
$elements = static::get_block_element_selectors( $root_selector );
889+
if ( ! empty( $elements ) ) {
890+
static::$blocks_metadata[ $block_name ]['elements'] = $elements;
896891
}
897892

898-
// Generate block support feature level selectors if opted into
899-
// for the current block.
900-
$features = array();
901-
foreach ( static::BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS as $key => $feature ) {
902-
if (
903-
isset( $block_type->supports[ $key ]['__experimentalSelector'] ) &&
904-
$block_type->supports[ $key ]['__experimentalSelector']
905-
) {
906-
$features[ $feature ] = static::scope_selector(
907-
static::$blocks_metadata[ $block_name ]['selector'],
908-
$block_type->supports[ $key ]['__experimentalSelector']
909-
);
893+
// The block may or may not have a duotone selector.
894+
$duotone_selector = wp_get_block_css_selector( $block_type, 'filter.duotone' );
895+
896+
// Keep backwards compatibility for support.color.__experimentalDuotone.
897+
if ( null === $duotone_selector ) {
898+
$duotone_support = _wp_array_get( $block_type->supports, array( 'color', '__experimentalDuotone' ), null );
899+
900+
if ( $duotone_support ) {
901+
$root_selector = wp_get_block_css_selector( $block_type );
902+
$duotone_selector = WP_Theme_JSON::scope_selector( $root_selector, $duotone_support );
910903
}
911904
}
912905

913-
if ( ! empty( $features ) ) {
914-
static::$blocks_metadata[ $block_name ]['features'] = $features;
906+
if ( null !== $duotone_selector ) {
907+
static::$blocks_metadata[ $block_name ]['duotone'] = $duotone_selector;
915908
}
916909

917-
// Assign defaults, then overwrite those that the block sets by itself.
918-
// If the block selector is compounded, will append the element to each
919-
// individual block selector.
920-
$block_selectors = explode( ',', static::$blocks_metadata[ $block_name ]['selector'] );
921-
foreach ( static::ELEMENTS as $el_name => $el_selector ) {
922-
$element_selector = array();
923-
foreach ( $block_selectors as $selector ) {
924-
if ( $selector === $el_selector ) {
925-
$element_selector = array( $el_selector );
926-
break;
927-
}
928-
$element_selector[] = static::prepend_to_selector( $el_selector, $selector . ' ' );
929-
}
930-
static::$blocks_metadata[ $block_name ]['elements'][ $el_name ] = implode( ',', $element_selector );
931-
}
932910
// If the block has style variations, append their selectors to the block metadata.
933911
if ( ! empty( $block_type->styles ) ) {
934912
$style_selectors = array();
@@ -2222,6 +2200,7 @@ private static function update_separator_declarations( $declarations ) {
22222200
* An internal method to get the block nodes from a theme.json file.
22232201
*
22242202
* @since 6.1.0
2203+
* @since 6.3.0 Refactored and stabilized selectors API.
22252204
*
22262205
* @param array $theme_json The theme.json converted to an array.
22272206
* @return array The block nodes in theme.json.
@@ -2250,8 +2229,8 @@ private static function get_block_nodes( $theme_json ) {
22502229
}
22512230

22522231
$feature_selectors = null;
2253-
if ( isset( $selectors[ $name ]['features'] ) ) {
2254-
$feature_selectors = $selectors[ $name ]['features'];
2232+
if ( isset( $selectors[ $name ]['selectors'] ) ) {
2233+
$feature_selectors = $selectors[ $name ]['selectors'];
22552234
}
22562235

22572236
$variation_selectors = array();
@@ -2268,6 +2247,7 @@ private static function get_block_nodes( $theme_json ) {
22682247
'name' => $name,
22692248
'path' => array( 'styles', 'blocks', $name ),
22702249
'selector' => $selector,
2250+
'selectors' => $feature_selectors,
22712251
'duotone' => $duotone_selector,
22722252
'features' => $feature_selectors,
22732253
'variations' => $variation_selectors,
@@ -2310,45 +2290,11 @@ private static function get_block_nodes( $theme_json ) {
23102290
* @return string Styles for the block.
23112291
*/
23122292
public function get_styles_for_block( $block_metadata ) {
2313-
$node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
2314-
$use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];
2315-
$selector = $block_metadata['selector'];
2316-
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
2317-
2318-
/*
2319-
* Process style declarations for block support features the current
2320-
* block contains selectors for. Values for a feature with a custom
2321-
* selector are filtered from the theme.json node before it is
2322-
* processed as normal.
2323-
*/
2324-
$feature_declarations = array();
2325-
2326-
if ( ! empty( $block_metadata['features'] ) ) {
2327-
foreach ( $block_metadata['features'] as $feature_name => $feature_selector ) {
2328-
if ( ! empty( $node[ $feature_name ] ) ) {
2329-
// Create temporary node containing only the feature data
2330-
// to leverage existing `compute_style_properties` function.
2331-
$feature = array( $feature_name => $node[ $feature_name ] );
2332-
// Generate the feature's declarations only.
2333-
$new_feature_declarations = static::compute_style_properties( $feature, $settings, null, $this->theme_json );
2334-
2335-
// Merge new declarations with any that already exist for
2336-
// the feature selector. This may occur when multiple block
2337-
// support features use the same custom selector.
2338-
if ( isset( $feature_declarations[ $feature_selector ] ) ) {
2339-
foreach ( $new_feature_declarations as $new_feature_declaration ) {
2340-
$feature_declarations[ $feature_selector ][] = $new_feature_declaration;
2341-
}
2342-
} else {
2343-
$feature_declarations[ $feature_selector ] = $new_feature_declarations;
2344-
}
2345-
2346-
// Remove the feature from the block's node now the
2347-
// styles will be included under the feature level selector.
2348-
unset( $node[ $feature_name ] );
2349-
}
2350-
}
2351-
}
2293+
$node = _wp_array_get( $this->theme_json, $block_metadata['path'], array() );
2294+
$use_root_padding = isset( $this->theme_json['settings']['useRootPaddingAwareAlignments'] ) && true === $this->theme_json['settings']['useRootPaddingAwareAlignments'];
2295+
$selector = $block_metadata['selector'];
2296+
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
2297+
$feature_declarations = static::get_feature_declarations_for_node( $block_metadata, $node );
23522298

23532299
// If there are style variations, generate the declarations for them, including any feature selectors the block may have.
23542300
$style_variation_declarations = array();
@@ -3486,4 +3432,158 @@ public function set_spacing_sizes() {
34863432

34873433
_wp_array_set( $this->theme_json, array( 'settings', 'spacing', 'spacingSizes', 'default' ), $spacing_sizes );
34883434
}
3435+
3436+
3437+
/**
3438+
* Returns the selectors metadata for a block.
3439+
*
3440+
* @since 6.3.0
3441+
*
3442+
* @param object $block_type The block type.
3443+
* @param string $root_selector The block's root selector.
3444+
*
3445+
* @return array The custom selectors set by the block.
3446+
*/
3447+
protected static function get_block_selectors( $block_type, $root_selector ) {
3448+
if ( ! empty( $block_type->selectors ) ) {
3449+
return $block_type->selectors;
3450+
}
3451+
3452+
$selectors = array( 'root' => $root_selector );
3453+
foreach ( static::BLOCK_SUPPORT_FEATURE_LEVEL_SELECTORS as $key => $feature ) {
3454+
$feature_selector = wp_get_block_css_selector( $block_type, $key );
3455+
if ( null !== $feature_selector ) {
3456+
$selectors[ $feature ] = array( 'root' => $feature_selector );
3457+
}
3458+
}
3459+
3460+
return $selectors;
3461+
}
3462+
3463+
/**
3464+
* Generates all the element selectors for a block.
3465+
*
3466+
* @since 6.3.0
3467+
*
3468+
* @param string $root_selector The block's root CSS selector.
3469+
* @return array The block's element selectors.
3470+
*/
3471+
protected static function get_block_element_selectors( $root_selector ) {
3472+
// Assign defaults, then override those that the block sets by itself.
3473+
// If the block selector is compounded, will append the element to each
3474+
// individual block selector.
3475+
$block_selectors = explode( ',', $root_selector );
3476+
$element_selectors = array();
3477+
3478+
foreach ( static::ELEMENTS as $el_name => $el_selector ) {
3479+
$element_selector = array();
3480+
foreach ( $block_selectors as $selector ) {
3481+
if ( $selector === $el_selector ) {
3482+
$element_selector = array( $el_selector );
3483+
break;
3484+
}
3485+
$element_selector[] = static::prepend_to_selector( $el_selector, $selector . ' ' );
3486+
}
3487+
$element_selectors[ $el_name ] = implode( ',', $element_selector );
3488+
}
3489+
3490+
return $element_selectors;
3491+
}
3492+
3493+
/**
3494+
* Generates style declarations for a node's features e.g., color, border,
3495+
* typography etc. that have custom selectors in their related block's
3496+
* metadata.
3497+
*
3498+
* @since 6.3.0
3499+
*
3500+
* @param object $metadata The related block metadata containing selectors.
3501+
* @param object $node A merged theme.json node for block or variation.
3502+
*
3503+
* @return array The style declarations for the node's features with custom
3504+
* selectors.
3505+
*/
3506+
protected function get_feature_declarations_for_node( $metadata, &$node ) {
3507+
$declarations = array();
3508+
3509+
if ( ! isset( $metadata['selectors'] ) ) {
3510+
return $declarations;
3511+
}
3512+
3513+
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
3514+
3515+
foreach ( $metadata['selectors'] as $feature => $feature_selectors ) {
3516+
// Skip if this is the block's root selector or the block doesn't
3517+
// have any styles for the feature.
3518+
if ( 'root' === $feature || empty( $node[ $feature ] ) ) {
3519+
continue;
3520+
}
3521+
3522+
if ( is_array( $feature_selectors ) ) {
3523+
foreach ( $feature_selectors as $subfeature => $subfeature_selector ) {
3524+
if ( 'root' === $subfeature || empty( $node[ $feature ][ $subfeature ] ) ) {
3525+
continue;
3526+
}
3527+
3528+
// Create temporary node containing only the subfeature data
3529+
// to leverage existing `compute_style_properties` function.
3530+
$subfeature_node = array(
3531+
$feature => array(
3532+
$subfeature => $node[ $feature ][ $subfeature ],
3533+
),
3534+
);
3535+
3536+
// Generate style declarations.
3537+
$new_declarations = static::compute_style_properties( $subfeature_node, $settings, null, $this->theme_json );
3538+
3539+
// Merge subfeature declarations into feature declarations.
3540+
if ( isset( $declarations[ $subfeature_selector ] ) ) {
3541+
foreach ( $new_declarations as $new_declaration ) {
3542+
$declarations[ $subfeature_selector ][] = $new_declaration;
3543+
}
3544+
} else {
3545+
$declarations[ $subfeature_selector ] = $new_declarations;
3546+
}
3547+
3548+
// Remove the subfeature from the block's node now its
3549+
// styles will be included under its own selector not the
3550+
// block's.
3551+
unset( $node[ $feature ][ $subfeature ] );
3552+
}
3553+
}
3554+
3555+
// Now subfeatures have been processed and removed we can process
3556+
// feature root selector or simple string selector.
3557+
if (
3558+
is_string( $feature_selectors ) ||
3559+
( isset( $feature_selectors['root'] ) && $feature_selectors['root'] )
3560+
) {
3561+
$feature_selector = is_string( $feature_selectors ) ? $feature_selectors : $feature_selectors['root'];
3562+
3563+
// Create temporary node containing only the feature data
3564+
// to leverage existing `compute_style_properties` function.
3565+
$feature_node = array( $feature => $node[ $feature ] );
3566+
3567+
// Generate the style declarations.
3568+
$new_declarations = static::compute_style_properties( $feature_node, $settings, null, $this->theme_json );
3569+
3570+
// Merge new declarations with any that already exist for
3571+
// the feature selector. This may occur when multiple block
3572+
// support features use the same custom selector.
3573+
if ( isset( $declarations[ $feature_selector ] ) ) {
3574+
foreach ( $new_declarations as $new_declaration ) {
3575+
$declarations[ $feature_selector ][] = $new_declaration;
3576+
}
3577+
} else {
3578+
$declarations[ $feature_selector ] = $new_declarations;
3579+
}
3580+
3581+
// Remove the feature from the block's node now its styles
3582+
// will be included under its own selector not the block's.
3583+
unset( $node[ $feature ] );
3584+
}
3585+
}
3586+
3587+
return $declarations;
3588+
}
34893589
}

0 commit comments

Comments
 (0)