Editor: Fix layout support classes to be generated with a stable ID.

This fixes a bug reported in https://github.com/WordPress/gutenberg/issues/67308 related to the Interactivity API's client-side navigation feature by replacing the incrementally generated IDs with stable hashes derived from the block's layout style definition.

Fixes #62985.
Props darerodz.

Built from https://develop.svn.wordpress.org/trunk@60038


git-svn-id: http://core.svn.wordpress.org/trunk@59374 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Joe McGill
2025-03-18 12:43:24 +00:00
parent 299978551a
commit 1c43cd6743
3 changed files with 77 additions and 12 deletions

View File

@@ -580,7 +580,33 @@ function wp_render_layout_support_flag( $block_content, $block ) {
// Child layout specific logic.
if ( $child_layout ) {
$container_content_class = wp_unique_prefixed_id( 'wp-container-content-' );
/*
* Generates a unique class for child block layout styles.
*
* To ensure consistent class generation across different page renders,
* only properties that affect layout styling are used. These properties
* come from `$block['attrs']['style']['layout']` and `$block['parentLayout']`.
*
* As long as these properties coincide, the generated class will be the same.
*/
$container_content_class = wp_unique_id_from_values(
array(
'layout' => array_intersect_key(
$block['attrs']['style']['layout'] ?? array(),
array_flip(
array( 'selfStretch', 'flexSize', 'columnStart', 'columnSpan', 'rowStart', 'rowSpan' )
)
),
'parentLayout' => array_intersect_key(
$block['parentLayout'] ?? array(),
array_flip(
array( 'minimumColumnWidth', 'columnCount' )
)
),
),
'wp-container-content-'
);
$child_layout_declarations = array();
$child_layout_styles = array();
@@ -706,16 +732,6 @@ function wp_render_layout_support_flag( $block_content, $block ) {
$class_names = array();
$layout_definitions = wp_get_layout_definitions();
/*
* Uses an incremental ID that is independent per prefix to make sure that
* rendering different numbers of blocks doesn't affect the IDs of other
* blocks. Makes the CSS class names stable across paginations
* for features like the enhanced pagination of the Query block.
*/
$container_class = wp_unique_prefixed_id(
'wp-container-' . sanitize_title( $block['blockName'] ) . '-is-layout-'
);
// Set the correct layout type for blocks using legacy content width.
if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] || isset( $used_layout['contentSize'] ) && $used_layout['contentSize'] ) {
$used_layout['type'] = 'constrained';
@@ -806,6 +822,25 @@ function wp_render_layout_support_flag( $block_content, $block ) {
: null;
$has_block_gap_support = isset( $block_gap );
/*
* Generates a unique ID based on all the data required to obtain the
* corresponding layout style. Keeps the CSS class names the same
* even for different blocks on different places, as long as they have
* the same layout definition. Makes the CSS class names stable across
* paginations for features like the enhanced pagination of the Query block.
*/
$container_class = wp_unique_id_from_values(
array(
$used_layout,
$has_block_gap_support,
$gap_value,
$should_skip_gap_serialization,
$fallback_gap_value,
$block_spacing,
),
'wp-container-' . sanitize_title( $block['blockName'] ) . '-is-layout-'
);
$style = wp_get_layout_style(
".$container_class",
$used_layout,

View File

@@ -9174,3 +9174,33 @@ function wp_verify_fast_hash(
return hash_equals( $hash, wp_fast_hash( $message ) );
}
/**
* Generates a unique ID based on the structure and values of a given array.
*
* This function serializes the array into a JSON string and generates a hash
* that serves as a unique identifier. Optionally, a prefix can be added to
* the generated ID for context or categorization.
*
* @since 6.8.0
*
* @param array $data The input array to generate an ID from.
* @param string $prefix Optional. A prefix to prepend to the generated ID. Default ''.
*
* @return string The generated unique ID for the array.
*/
function wp_unique_id_from_values( array $data, string $prefix = '' ): string {
if ( empty( $data ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
__( 'The $data argument must not be empty.' ),
gettype( $data )
),
'6.8.0'
);
}
$serialized = wp_json_encode( $data );
$hash = substr( md5( $serialized ), 0, 8 );
return $prefix . $hash;
}

View File

@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.8-beta2-60037';
$wp_version = '6.8-beta2-60038';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.