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

Update: Backport block settings to core. #4013

Closed
Show file tree
Hide file tree
Changes from all 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
146 changes: 146 additions & 0 deletions src/wp-includes/block-supports/settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php
/**
* Block level presets support.
*
* @package WordPress
* @since 6.2.0
*/

/**
* Get the class name used on block level presets.
*
* @internal
*
* @since 6.2.0
* @access private
*
* @param array $block Block object.
* @return string The unique class name.
*/
function _wp_get_presets_class_name( $block ) {
return 'wp-settings-' . md5( serialize( $block ) );
}

/**
* Update the block content with block level presets class name.
*
* @internal
*
* @since 6.2.0
* @access private
*
* @param string $block_content Rendered block content.
* @param array $block Block object.
* @return string Filtered block content.
*/
function _wp_add_block_level_presets_class( $block_content, $block ) {
if ( ! $block_content ) {
return $block_content;
}

// return early if the block doesn't have support for settings.
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
if ( ! block_has_support( $block_type, array( '__experimentalSettings' ), false ) ) {
return $block_content;
}

// return early if no settings are found on the block attributes.
$block_settings = _wp_array_get( $block, array( 'attrs', 'settings' ), null );
if ( empty( $block_settings ) ) {
return $block_content;
}

// Like the layout hook this assumes the hook only applies to blocks with a single wrapper.
// Add the class name to the first element, presuming it's the wrapper, if it exists.
$tags = new WP_HTML_Tag_Processor( $block_content );
if ( $tags->next_tag() ) {
$tags->add_class( _wp_get_presets_class_name( $block ) );
}

return $tags->get_updated_html();
}

/**
* Render the block level presets stylesheet.
*
* @internal
*
* @since 6.2.0
* @access private
*
* @param string|null $pre_render The pre-rendered content. Default null.
* @param array $block The block being rendered.
*
* @return null
*/
function _wp_add_block_level_preset_styles( $pre_render, $block ) {
// Return early if the block has not support for descendent block styles.
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
if ( ! block_has_support( $block_type, array( '__experimentalSettings' ), false ) ) {
return null;
}

// return early if no settings are found on the block attributes.
$block_settings = _wp_array_get( $block, array( 'attrs', 'settings' ), null );
if ( empty( $block_settings ) ) {
return null;
}

$class_name = '.' . _wp_get_presets_class_name( $block );

// the root selector for preset variables needs to target every possible block selector
// in order for the general setting to override any bock specific setting of a parent block or
// the site root.
$variables_root_selector = '*,[class*="wp-block"]';
$registry = WP_Block_Type_Registry::get_instance();
$blocks = $registry->get_all_registered();
foreach ( $blocks as $block_type ) {
if (
isset( $block_type->supports['__experimentalSelector'] ) &&
is_string( $block_type->supports['__experimentalSelector'] )
) {
$variables_root_selector .= ',' . $block_type->supports['__experimentalSelector'];
}
}
$variables_root_selector = WP_Theme_JSON::scope_selector( $class_name, $variables_root_selector );

// Remove any potentially unsafe styles.
$theme_json_shape = WP_Theme_JSON::remove_insecure_properties(
array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'settings' => $block_settings,
)
);
$theme_json_object = new WP_Theme_JSON( $theme_json_shape );

$styles = '';

// include preset css variables declaration on the stylesheet.
$styles .= $theme_json_object->get_stylesheet(
array( 'variables' ),
null,
array(
'root_selector' => $variables_root_selector,
'scope' => $class_name,
)
);

// include preset css classes on the the stylesheet.
$styles .= $theme_json_object->get_stylesheet(
array( 'presets' ),
null,
array(
'root_selector' => $class_name . ',' . $class_name . ' *',
'scope' => $class_name,
)
);

if ( ! empty( $styles ) ) {
wp_enqueue_block_support_styles( $styles );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method will be deprecated in favor of wp_style_engine_get_stylesheet_from_css_rules. See #4015.

Copy link
Member

@oandregal oandregal Feb 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested using the recommended method: it didn't work or I didn't know how to use it. It's best to look at this separately in a follow-up.

}

return null;
}

add_filter( 'render_block', '_wp_add_block_level_presets_class', 10, 2 );
add_filter( 'pre_render_block', '_wp_add_block_level_preset_styles', 10, 2 );
60 changes: 50 additions & 10 deletions src/wp-includes/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -943,9 +943,12 @@ public function get_settings() {
* - `styles`: only the styles section in theme.json.
* - `presets`: only the classes for the presets.
* @param array $origins A list of origins to include. By default it includes VALID_ORIGINS.
* @param array $options An array of options for now used for internal purposes only (may change without notice).
* The options currently supported are 'scope' that makes sure all style are scoped to a given selector,
* and root_selector which overwrites and forces a given selector to be used on the root node.
* @return string The resulting stylesheet.
*/
public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' ), $origins = null ) {
public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' ), $origins = null, $options = array() ) {
if ( null === $origins ) {
$origins = static::VALID_ORIGINS;
}
Expand All @@ -966,30 +969,58 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'
$style_nodes = static::get_style_nodes( $this->theme_json, $blocks_metadata );
$setting_nodes = static::get_setting_nodes( $this->theme_json, $blocks_metadata );

$root_style_key = array_search( static::ROOT_BLOCK_SELECTOR, array_column( $style_nodes, 'selector' ), true );
$root_settings_key = array_search( static::ROOT_BLOCK_SELECTOR, array_column( $setting_nodes, 'selector' ), true );

if ( ! empty( $options['scope'] ) ) {
foreach ( $setting_nodes as &$node ) {
$node['selector'] = static::scope_selector( $options['scope'], $node['selector'] );
}
foreach ( $style_nodes as &$node ) {
$node['selector'] = static::scope_selector( $options['scope'], $node['selector'] );
}
}

if ( ! empty( $options['root_selector'] ) ) {
if ( false !== $root_settings_key ) {
$setting_nodes[ $root_settings_key ]['selector'] = $options['root_selector'];
}
if ( false !== $root_style_key ) {
$setting_nodes[ $root_style_key ]['selector'] = $options['root_selector'];
}
}

$stylesheet = '';

if ( in_array( 'variables', $types, true ) ) {
$stylesheet .= $this->get_css_variables( $setting_nodes, $origins );
}

if ( in_array( 'styles', $types, true ) ) {
$root_block_key = array_search( static::ROOT_BLOCK_SELECTOR, array_column( $style_nodes, 'selector' ), true );

if ( false !== $root_block_key ) {
$stylesheet .= $this->get_root_layout_rules( static::ROOT_BLOCK_SELECTOR, $style_nodes[ $root_block_key ] );
if ( false !== $root_style_key ) {
$stylesheet .= $this->get_root_layout_rules( $style_nodes[ $root_style_key ]['selector'], $style_nodes[ $root_style_key ] );
}
$stylesheet .= $this->get_block_classes( $style_nodes );
} elseif ( in_array( 'base-layout-styles', $types, true ) ) {
$root_selector = static::ROOT_BLOCK_SELECTOR;
$columns_selector = '.wp-block-columns';
if ( ! empty( $options['scope'] ) ) {
$root_selector = static::scope_selector( $options['scope'], $root_selector );
$columns_selector = static::scope_selector( $options['scope'], $columns_selector );
}
if ( ! empty( $options['root_selector'] ) ) {
$root_selector = $options['root_selector'];
}
// Base layout styles are provided as part of `styles`, so only output separately if explicitly requested.
// For backwards compatibility, the Columns block is explicitly included, to support a different default gap value.
$base_styles_nodes = array(
array(
'path' => array( 'styles' ),
'selector' => static::ROOT_BLOCK_SELECTOR,
'selector' => $root_selector,
),
array(
'path' => array( 'styles', 'blocks', 'core/columns' ),
'selector' => '.wp-block-columns',
'selector' => $columns_selector,
'name' => 'core/columns',
),
);
Expand Down Expand Up @@ -1490,18 +1521,27 @@ protected static function compute_preset_classes( $settings, $selector, $origins
* @param string $selector Original selector.
* @return string Scoped selector.
*/
protected static function scope_selector( $scope, $selector ) {
public static function scope_selector( $scope, $selector ) {
$scopes = explode( ',', $scope );
$selectors = explode( ',', $selector );

$selectors_scoped = array();
foreach ( $scopes as $outer ) {
foreach ( $selectors as $inner ) {
$selectors_scoped[] = trim( $outer ) . ' ' . trim( $inner );
$outer = trim( $outer );
$inner = trim( $inner );
if ( ! empty( $outer ) && ! empty( $inner ) ) {
$selectors_scoped[] = $outer . ' ' . $inner;
} elseif ( empty( $outer ) ) {
$selectors_scoped[] = $inner;
} elseif ( empty( $inner ) ) {
$selectors_scoped[] = $outer;
}
}
}

return implode( ', ', $selectors_scoped );
$result = implode( ', ', $selectors_scoped );
return $result;
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/wp-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@
require ABSPATH . WPINC . '/block-supports/layout.php';
require ABSPATH . WPINC . '/block-supports/spacing.php';
require ABSPATH . WPINC . '/block-supports/typography.php';
require ABSPATH . WPINC . '/block-supports/settings.php';
require ABSPATH . WPINC . '/style-engine.php';
require ABSPATH . WPINC . '/style-engine/class-wp-style-engine.php';
require ABSPATH . WPINC . '/style-engine/class-wp-style-engine-css-declarations.php';
Expand Down