Make WordPress Core


Ignore:
Timestamp:
03/14/2024 01:32:56 PM (9 months ago)
Author:
swissspidy
Message:

Interactivity API: Do not propagate context from void tags to its siblings.

Resolves an issue where context on a void tag element such as <img> was incorrectly passed to following elements.
Adds tests.

Props santosguillamot, luisherranz, cbravobernal, dmsnell, gziolo, swissspidy.
Fixes #60768.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/interactivity-api/class-wp-interactivity-api.php

    r57824 r57832  
    295295            }
    296296            /*
    297                 * If the matching opener tag didn't have any directives, it can skip the
    298                 * processing.
    299                 */
     297             * If the matching opener tag didn't have any directives, it can skip the
     298             * processing.
     299             */
    300300            if ( 0 === count( $directives_prefixes ) ) {
    301301                continue;
    302302            }
    303303
    304             /*
    305              * Sorts the attributes by the order of the `directives_processor` array
    306              * and checks what directives are present in this element. The processing
    307              * order is reversed for tag closers.
    308              */
    309             $directives_prefixes = array_intersect(
    310                 $p->is_tag_closer()
    311                     ? $directive_processor_prefixes_reversed
    312                     : $directive_processor_prefixes,
    313                 $directives_prefixes
     304            // Directive processing might be different depending on if it is entering the tag or exiting it.
     305            $modes = array(
     306                'enter' => ! $p->is_tag_closer(),
     307                'exit'  => $p->is_tag_closer() || ! $p->has_and_visits_its_closer_tag(),
    314308            );
    315309
    316             // Executes the directive processors present in this element.
    317             foreach ( $directives_prefixes as $directive_prefix ) {
    318                 $func = is_array( self::$directive_processors[ $directive_prefix ] )
    319                     ? self::$directive_processors[ $directive_prefix ]
    320                     : array( $this, self::$directive_processors[ $directive_prefix ] );
    321                 call_user_func_array(
    322                     $func,
    323                     array( $p, &$context_stack, &$namespace_stack, &$tag_stack )
     310            foreach ( $modes as $mode => $should_run ) {
     311                if ( ! $should_run ) {
     312                    continue;
     313                }
     314
     315                /*
     316                 * Sorts the attributes by the order of the `directives_processor` array
     317                 * and checks what directives are present in this element.
     318                 */
     319                $existing_directives_prefixes = array_intersect(
     320                    'enter' === $mode ? $directive_processor_prefixes : $directive_processor_prefixes_reversed,
     321                    $directives_prefixes
    324322                );
     323                foreach ( $existing_directives_prefixes as $directive_prefix ) {
     324                    $func = is_array( self::$directive_processors[ $directive_prefix ] )
     325                        ? self::$directive_processors[ $directive_prefix ]
     326                        : array( $this, self::$directive_processors[ $directive_prefix ] );
     327
     328                    call_user_func_array(
     329                        $func,
     330                        array( $p, $mode, &$context_stack, &$namespace_stack, &$tag_stack )
     331                    );
     332                }
    325333            }
    326334        }
     
    475483     *
    476484     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     485     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
    477486     * @param array                                     $context_stack   The reference to the context stack.
    478487     * @param array                                     $namespace_stack The reference to the store namespace stack.
    479488     */
    480     private function data_wp_interactive_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
    481         // In closing tags, it removes the last namespace from the stack.
    482         if ( $p->is_tag_closer() ) {
     489    private function data_wp_interactive_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) {
     490        // When exiting tags, it removes the last namespace from the stack.
     491        if ( 'exit' === $mode ) {
    483492            array_pop( $namespace_stack );
    484493            return;
     
    519528     *
    520529     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     530     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
    521531     * @param array                                     $context_stack   The reference to the context stack.
    522532     * @param array                                     $namespace_stack The reference to the store namespace stack.
    523533     */
    524     private function data_wp_context_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
    525         // In closing tags, it removes the last context from the stack.
    526         if ( $p->is_tag_closer() ) {
     534    private function data_wp_context_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) {
     535        // When exiting tags, it removes the last context from the stack.
     536        if ( 'exit' === $mode ) {
    527537            array_pop( $context_stack );
    528538            return;
     
    565575     *
    566576     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     577     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
    567578     * @param array                                     $context_stack   The reference to the context stack.
    568579     * @param array                                     $namespace_stack The reference to the store namespace stack.
    569580     */
    570     private function data_wp_bind_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
    571         if ( ! $p->is_tag_closer() ) {
     581    private function data_wp_bind_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) {
     582        if ( 'enter' === $mode ) {
    572583            $all_bind_directives = $p->get_attribute_names_with_prefix( 'data-wp-bind--' );
    573584
     
    609620     *
    610621     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     622     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
    611623     * @param array                                     $context_stack   The reference to the context stack.
    612624     * @param array                                     $namespace_stack The reference to the store namespace stack.
    613625     */
    614     private function data_wp_class_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
    615         if ( ! $p->is_tag_closer() ) {
     626    private function data_wp_class_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) {
     627        if ( 'enter' === $mode ) {
    616628            $all_class_directives = $p->get_attribute_names_with_prefix( 'data-wp-class--' );
    617629
     
    643655     *
    644656     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     657     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
    645658     * @param array                                     $context_stack   The reference to the context stack.
    646659     * @param array                                     $namespace_stack The reference to the store namespace stack.
    647660     */
    648     private function data_wp_style_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
    649         if ( ! $p->is_tag_closer() ) {
     661    private function data_wp_style_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) {
     662        if ( 'enter' === $mode ) {
    650663            $all_style_attributes = $p->get_attribute_names_with_prefix( 'data-wp-style--' );
    651664
     
    735748     *
    736749     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     750     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
    737751     * @param array                                     $context_stack   The reference to the context stack.
    738752     * @param array                                     $namespace_stack The reference to the store namespace stack.
    739753     */
    740     private function data_wp_text_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
    741         if ( ! $p->is_tag_closer() ) {
     754    private function data_wp_text_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack ) {
     755        if ( 'enter' === $mode ) {
    742756            $attribute_value = $p->get_attribute( 'data-wp-text' );
    743757            $result          = $this->evaluate( $attribute_value, end( $namespace_stack ), end( $context_stack ) );
     
    832846     * @since 6.5.0
    833847     *
    834      * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
    835      */
    836     private function data_wp_router_region_processor( WP_Interactivity_API_Directives_Processor $p ) {
    837         if ( ! $p->is_tag_closer() && ! $this->has_processed_router_region ) {
     848     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     849     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
     850     */
     851    private function data_wp_router_region_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) {
     852        if ( 'enter' === $mode && ! $this->has_processed_router_region ) {
    838853            $this->has_processed_router_region = true;
    839854
     
    871886     *
    872887     * @param WP_Interactivity_API_Directives_Processor $p               The directives processor instance.
     888     * @param string                                    $mode            Whether the processing is entering or exiting the tag.
    873889     * @param array                                     $context_stack   The reference to the context stack.
    874890     * @param array                                     $namespace_stack The reference to the store namespace stack.
    875891     * @param array                                     $tag_stack       The reference to the tag stack.
    876892     */
    877     private function data_wp_each_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack, array &$tag_stack ) {
    878         if ( ! $p->is_tag_closer() && 'TEMPLATE' === $p->get_tag() ) {
     893    private function data_wp_each_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$context_stack, array &$namespace_stack, array &$tag_stack ) {
     894        if ( 'enter' === $mode && 'TEMPLATE' === $p->get_tag() ) {
    879895            $attribute_name   = $p->get_attribute_names_with_prefix( 'data-wp-each' )[0];
    880896            $extracted_suffix = $this->extract_prefix_and_suffix( $attribute_name );
Note: See TracChangeset for help on using the changeset viewer.