wp/wp-includes/block-supports/settings.php
changeset 21 48c4eec2b7e6
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
       
     1 <?php
       
     2 /**
       
     3  * Block level presets support.
       
     4  *
       
     5  * @package WordPress
       
     6  * @since 6.2.0
       
     7  */
       
     8 
       
     9 /**
       
    10  * Get the class name used on block level presets.
       
    11  *
       
    12  * @internal
       
    13  *
       
    14  * @since 6.2.0
       
    15  * @access private
       
    16  *
       
    17  * @param array $block Block object.
       
    18  * @return string      The unique class name.
       
    19  */
       
    20 function _wp_get_presets_class_name( $block ) {
       
    21 	return 'wp-settings-' . md5( serialize( $block ) );
       
    22 }
       
    23 
       
    24 /**
       
    25  * Update the block content with block level presets class name.
       
    26  *
       
    27  * @internal
       
    28  *
       
    29  * @since 6.2.0
       
    30  * @access private
       
    31  *
       
    32  * @param  string $block_content Rendered block content.
       
    33  * @param  array  $block         Block object.
       
    34  * @return string                Filtered block content.
       
    35  */
       
    36 function _wp_add_block_level_presets_class( $block_content, $block ) {
       
    37 	if ( ! $block_content ) {
       
    38 		return $block_content;
       
    39 	}
       
    40 
       
    41 	// return early if the block doesn't have support for settings.
       
    42 	$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
       
    43 	if ( ! block_has_support( $block_type, '__experimentalSettings', false ) ) {
       
    44 		return $block_content;
       
    45 	}
       
    46 
       
    47 	// return early if no settings are found on the block attributes.
       
    48 	$block_settings = isset( $block['attrs']['settings'] ) ? $block['attrs']['settings'] : null;
       
    49 	if ( empty( $block_settings ) ) {
       
    50 		return $block_content;
       
    51 	}
       
    52 
       
    53 	// Like the layout hook this assumes the hook only applies to blocks with a single wrapper.
       
    54 	// Add the class name to the first element, presuming it's the wrapper, if it exists.
       
    55 	$tags = new WP_HTML_Tag_Processor( $block_content );
       
    56 	if ( $tags->next_tag() ) {
       
    57 		$tags->add_class( _wp_get_presets_class_name( $block ) );
       
    58 	}
       
    59 
       
    60 	return $tags->get_updated_html();
       
    61 }
       
    62 
       
    63 /**
       
    64  * Render the block level presets stylesheet.
       
    65  *
       
    66  * @internal
       
    67  *
       
    68  * @since 6.2.0
       
    69  * @since 6.3.0 Updated preset styles to use Selectors API.
       
    70  * @access private
       
    71  *
       
    72  * @param string|null $pre_render   The pre-rendered content. Default null.
       
    73  * @param array       $block The block being rendered.
       
    74  *
       
    75  * @return null
       
    76  */
       
    77 function _wp_add_block_level_preset_styles( $pre_render, $block ) {
       
    78 	// Return early if the block has not support for descendent block styles.
       
    79 	$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
       
    80 	if ( ! block_has_support( $block_type, '__experimentalSettings', false ) ) {
       
    81 		return null;
       
    82 	}
       
    83 
       
    84 	// return early if no settings are found on the block attributes.
       
    85 	$block_settings = isset( $block['attrs']['settings'] ) ? $block['attrs']['settings'] : null;
       
    86 	if ( empty( $block_settings ) ) {
       
    87 		return null;
       
    88 	}
       
    89 
       
    90 	$class_name = '.' . _wp_get_presets_class_name( $block );
       
    91 
       
    92 	// the root selector for preset variables needs to target every possible block selector
       
    93 	// in order for the general setting to override any bock specific setting of a parent block or
       
    94 	// the site root.
       
    95 	$variables_root_selector = '*,[class*="wp-block"]';
       
    96 	$registry                = WP_Block_Type_Registry::get_instance();
       
    97 	$blocks                  = $registry->get_all_registered();
       
    98 	foreach ( $blocks as $block_type ) {
       
    99 		/*
       
   100 		 * We only want to append selectors for blocks using custom selectors
       
   101 		 * i.e. not `wp-block-<name>`.
       
   102 		 */
       
   103 		$has_custom_selector =
       
   104 			( isset( $block_type->supports['__experimentalSelector'] ) && is_string( $block_type->supports['__experimentalSelector'] ) ) ||
       
   105 			( isset( $block_type->selectors['root'] ) && is_string( $block_type->selectors['root'] ) );
       
   106 
       
   107 		if ( $has_custom_selector ) {
       
   108 			$variables_root_selector .= ',' . wp_get_block_css_selector( $block_type );
       
   109 		}
       
   110 	}
       
   111 	$variables_root_selector = WP_Theme_JSON::scope_selector( $class_name, $variables_root_selector );
       
   112 
       
   113 	// Remove any potentially unsafe styles.
       
   114 	$theme_json_shape  = WP_Theme_JSON::remove_insecure_properties(
       
   115 		array(
       
   116 			'version'  => WP_Theme_JSON::LATEST_SCHEMA,
       
   117 			'settings' => $block_settings,
       
   118 		)
       
   119 	);
       
   120 	$theme_json_object = new WP_Theme_JSON( $theme_json_shape );
       
   121 
       
   122 	$styles = '';
       
   123 
       
   124 	// include preset css variables declaration on the stylesheet.
       
   125 	$styles .= $theme_json_object->get_stylesheet(
       
   126 		array( 'variables' ),
       
   127 		null,
       
   128 		array(
       
   129 			'root_selector' => $variables_root_selector,
       
   130 			'scope'         => $class_name,
       
   131 		)
       
   132 	);
       
   133 
       
   134 	// include preset css classes on the the stylesheet.
       
   135 	$styles .= $theme_json_object->get_stylesheet(
       
   136 		array( 'presets' ),
       
   137 		null,
       
   138 		array(
       
   139 			'root_selector' => $class_name . ',' . $class_name . ' *',
       
   140 			'scope'         => $class_name,
       
   141 		)
       
   142 	);
       
   143 
       
   144 	if ( ! empty( $styles ) ) {
       
   145 		wp_enqueue_block_support_styles( $styles );
       
   146 	}
       
   147 
       
   148 	return null;
       
   149 }
       
   150 
       
   151 add_filter( 'render_block', '_wp_add_block_level_presets_class', 10, 2 );
       
   152 add_filter( 'pre_render_block', '_wp_add_block_level_preset_styles', 10, 2 );