From 9eed18532d03558198137d22bdda2be234aef67e Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Thu, 14 Mar 2024 15:12:10 +0000 Subject: [PATCH] Interactivity API: Do not propagate context from void tags to its siblings. Resolves an issue where context on a void tag element such as `` was incorrectly passed to following elements. Adds tests. Reviewed by gziolo. Merges [57832] to the to the 6.5 branch. Props santosguillamot, luisherranz, cbravobernal, dmsnell, gziolo, swissspidy. Fixes #60768. Built from https://develop.svn.wordpress.org/branches/6.5@57834 git-svn-id: http://core.svn.wordpress.org/branches/6.5@57335 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- .../class-wp-interactivity-api.php | 96 +++++++++++-------- wp-includes/version.php | 2 +- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/wp-includes/interactivity-api/class-wp-interactivity-api.php b/wp-includes/interactivity-api/class-wp-interactivity-api.php index 28cb7ee20a..a1c94594f9 100644 --- a/wp-includes/interactivity-api/class-wp-interactivity-api.php +++ b/wp-includes/interactivity-api/class-wp-interactivity-api.php @@ -294,34 +294,42 @@ final class WP_Interactivity_API { } } /* - * If the matching opener tag didn't have any directives, it can skip the - * processing. - */ + * If the matching opener tag didn't have any directives, it can skip the + * processing. + */ if ( 0 === count( $directives_prefixes ) ) { continue; } - /* - * Sorts the attributes by the order of the `directives_processor` array - * and checks what directives are present in this element. The processing - * order is reversed for tag closers. - */ - $directives_prefixes = array_intersect( - $p->is_tag_closer() - ? $directive_processor_prefixes_reversed - : $directive_processor_prefixes, - $directives_prefixes + // Directive processing might be different depending on if it is entering the tag or exiting it. + $modes = array( + 'enter' => ! $p->is_tag_closer(), + 'exit' => $p->is_tag_closer() || ! $p->has_and_visits_its_closer_tag(), ); - // Executes the directive processors present in this element. - foreach ( $directives_prefixes as $directive_prefix ) { - $func = is_array( self::$directive_processors[ $directive_prefix ] ) - ? self::$directive_processors[ $directive_prefix ] - : array( $this, self::$directive_processors[ $directive_prefix ] ); - call_user_func_array( - $func, - array( $p, &$context_stack, &$namespace_stack, &$tag_stack ) + foreach ( $modes as $mode => $should_run ) { + if ( ! $should_run ) { + continue; + } + + /* + * Sorts the attributes by the order of the `directives_processor` array + * and checks what directives are present in this element. + */ + $existing_directives_prefixes = array_intersect( + 'enter' === $mode ? $directive_processor_prefixes : $directive_processor_prefixes_reversed, + $directives_prefixes ); + foreach ( $existing_directives_prefixes as $directive_prefix ) { + $func = is_array( self::$directive_processors[ $directive_prefix ] ) + ? self::$directive_processors[ $directive_prefix ] + : array( $this, self::$directive_processors[ $directive_prefix ] ); + + call_user_func_array( + $func, + array( $p, $mode, &$context_stack, &$namespace_stack, &$tag_stack ) + ); + } } } @@ -474,12 +482,13 @@ final class WP_Interactivity_API { * @since 6.5.0 * * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. * @param array $context_stack The reference to the context stack. * @param array $namespace_stack The reference to the store namespace stack. */ - private function data_wp_interactive_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) { - // In closing tags, it removes the last namespace from the stack. - if ( $p->is_tag_closer() ) { + private function data_wp_interactive_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) { + // When exiting tags, it removes the last namespace from the stack. + if ( 'exit' === $mode ) { array_pop( $namespace_stack ); return; } @@ -518,12 +527,13 @@ final class WP_Interactivity_API { * @since 6.5.0 * * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. * @param array $context_stack The reference to the context stack. * @param array $namespace_stack The reference to the store namespace stack. */ - private function data_wp_context_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) { - // In closing tags, it removes the last context from the stack. - if ( $p->is_tag_closer() ) { + private function data_wp_context_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) { + // When exiting tags, it removes the last context from the stack. + if ( 'exit' === $mode ) { array_pop( $context_stack ); return; } @@ -564,11 +574,12 @@ final class WP_Interactivity_API { * @since 6.5.0 * * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. * @param array $context_stack The reference to the context stack. * @param array $namespace_stack The reference to the store namespace stack. */ - private function data_wp_bind_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) { - if ( ! $p->is_tag_closer() ) { + private function data_wp_bind_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) { + if ( 'enter' === $mode ) { $all_bind_directives = $p->get_attribute_names_with_prefix( 'data-wp-bind--' ); foreach ( $all_bind_directives as $attribute_name ) { @@ -608,11 +619,12 @@ final class WP_Interactivity_API { * @since 6.5.0 * * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. * @param array $context_stack The reference to the context stack. * @param array $namespace_stack The reference to the store namespace stack. */ - private function data_wp_class_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) { - if ( ! $p->is_tag_closer() ) { + private function data_wp_class_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) { + if ( 'enter' === $mode ) { $all_class_directives = $p->get_attribute_names_with_prefix( 'data-wp-class--' ); foreach ( $all_class_directives as $attribute_name ) { @@ -642,11 +654,12 @@ final class WP_Interactivity_API { * @since 6.5.0 * * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. * @param array $context_stack The reference to the context stack. * @param array $namespace_stack The reference to the store namespace stack. */ - private function data_wp_style_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) { - if ( ! $p->is_tag_closer() ) { + private function data_wp_style_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) { + if ( 'enter' === $mode ) { $all_style_attributes = $p->get_attribute_names_with_prefix( 'data-wp-style--' ); foreach ( $all_style_attributes as $attribute_name ) { @@ -734,11 +747,12 @@ final class WP_Interactivity_API { * @since 6.5.0 * * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. * @param array $context_stack The reference to the context stack. * @param array $namespace_stack The reference to the store namespace stack. */ - private function data_wp_text_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) { - if ( ! $p->is_tag_closer() ) { + private function data_wp_text_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) { + if ( 'enter' === $mode ) { $attribute_value = $p->get_attribute( 'data-wp-text' ); $result = $this->evaluate( $attribute_value, end( $namespace_stack ), end( $context_stack ) ); @@ -831,10 +845,11 @@ HTML; * * @since 6.5.0 * - * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. */ - private function data_wp_router_region_processor( WP_Interactivity_API_Directives_Processor $p ) { - if ( ! $p->is_tag_closer() && ! $this->has_processed_router_region ) { + private function data_wp_router_region_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) { + if ( 'enter' === $mode && ! $this->has_processed_router_region ) { $this->has_processed_router_region = true; // Initialize the `core/router` store. @@ -870,12 +885,13 @@ HTML; * @since 6.5.0 * * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. + * @param string $mode Whether the processing is entering or exiting the tag. * @param array $context_stack The reference to the context stack. * @param array $namespace_stack The reference to the store namespace stack. * @param array $tag_stack The reference to the tag stack. */ - private function data_wp_each_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack, array &$tag_stack ) { - if ( ! $p->is_tag_closer() && 'TEMPLATE' === $p->get_tag() ) { + private function data_wp_each_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack, array &$tag_stack ) { + if ( 'enter' === $mode && 'TEMPLATE' === $p->get_tag() ) { $attribute_name = $p->get_attribute_names_with_prefix( 'data-wp-each' )[0]; $extracted_suffix = $this->extract_prefix_and_suffix( $attribute_name ); $item_name = isset( $extracted_suffix[1] ) ? $this->kebab_to_camel_case( $extracted_suffix[1] ) : 'item'; diff --git a/wp-includes/version.php b/wp-includes/version.php index fcbc58d00f..a765703279 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.5-RC2-57830'; +$wp_version = '6.5-RC2-57834'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.