Make WordPress Core

Changeset 61310


Ignore:
Timestamp:
11/26/2025 04:26:45 AM (3 weeks ago)
Author:
wildworks
Message:

Command Palette: Use HTML API for more reliable menu labels and URLs.

Replace regex-based HTML parsing with WP_HTML_Tag_Processor to properly extract text nodes from menu labels. This ensures only root-level text nodes are
collected.

Additionally, replace html_entity_decode() with WP_HTML_Decoder::decode_attribute() with the menu URL for consistent attribute decoding.

Follow-up to [61124], [61126], [61127], [61142].

Props: dmsnell, madhavishah01, peterwilsoncc, wildworks.
Fixes #64233.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/script-loader.php

    r61174 r61310  
    34393439    );
    34403440
     3441    /**
     3442     * Extracts root-level text nodes from HTML string.
     3443     *
     3444     * @ignore
     3445     * @param string $label HTML string to extract text from.
     3446     * @return string Extracted text content, trimmed.
     3447     */
     3448    $extract_root_text = static function ( string $label ): string {
     3449        if ( '' === $label ) {
     3450            return '';
     3451        }
     3452
     3453        $processor  = new WP_HTML_Tag_Processor( $label );
     3454        $text_parts = array();
     3455        $depth      = 0;
     3456
     3457        while ( $processor->next_token() ) {
     3458            $token_type = $processor->get_token_type();
     3459
     3460            if ( '#text' === $token_type ) {
     3461                if ( 0 === $depth ) {
     3462                    $text_parts[] = $processor->get_modifiable_text();
     3463                }
     3464                continue;
     3465            }
     3466
     3467            if ( '#tag' !== $token_type ) {
     3468                continue;
     3469            }
     3470
     3471            if ( $processor->is_tag_closer() ) {
     3472                if ( $depth > 0 ) {
     3473                    --$depth;
     3474                }
     3475                continue;
     3476            }
     3477
     3478            $token_name = $processor->get_tag();
     3479            if ( $token_name && ! WP_HTML_Processor::is_void( $token_name ) ) {
     3480                ++$depth;
     3481            }
     3482        }
     3483
     3484        return trim( implode( '', $text_parts ) );
     3485    };
     3486
    34413487    if ( $menu ) {
    34423488        $menu_commands = array();
    34433489        foreach ( $menu as $menu_item ) {
    3444             if ( empty( $menu_item[0] ) || ! empty( $menu_item[1] ) && ! current_user_can( $menu_item[1] ) ) {
     3490            if ( empty( $menu_item[0] ) || ! is_string( $menu_item[0] ) || ! empty( $menu_item[1] ) && ! current_user_can( $menu_item[1] ) ) {
    34453491                continue;
    34463492            }
    34473493
    3448             // Remove all HTML tags and their contents.
    3449             $menu_label = $menu_item[0];
    3450             while ( preg_match( '/<[^>]*>/', $menu_label ) ) {
    3451                 $menu_label = preg_replace( '/<[^>]*>.*?<\/[^>]*>|<[^>]*\/>|<[^>]*>/s', '', $menu_label );
    3452             }
    3453             $menu_label = trim( $menu_label );
     3494            $menu_label = $extract_root_text( $menu_item[0] );
    34543495            $menu_url   = '';
    34553496            $menu_slug  = $menu_item[2];
     
    34583499                $menu_url = $menu_slug;
    34593500            } elseif ( ! empty( menu_page_url( $menu_slug, false ) ) ) {
    3460                 $menu_url = html_entity_decode( menu_page_url( $menu_slug, false ), ENT_QUOTES, get_bloginfo( 'charset' ) );
     3501                $menu_url = WP_HTML_Decoder::decode_attribute( menu_page_url( $menu_slug, false ) );
    34613502            }
    34623503
     
    34753516                    }
    34763517
    3477                     // Remove all HTML tags and their contents.
    3478                     $submenu_label = $submenu_item[0];
    3479                     while ( preg_match( '/<[^>]*>/', $submenu_label ) ) {
    3480                         $submenu_label = preg_replace( '/<[^>]*>.*?<\/[^>]*>|<[^>]*\/>|<[^>]*>/s', '', $submenu_label );
    3481                     }
    3482                     $submenu_label = trim( $submenu_label );
     3518                    $submenu_label = $extract_root_text( $submenu_item[0] );
    34833519                    $submenu_url   = '';
    34843520                    $submenu_slug  = $submenu_item[2];
     
    34873523                        $submenu_url = $submenu_slug;
    34883524                    } elseif ( ! empty( menu_page_url( $submenu_slug, false ) ) ) {
    3489                         $submenu_url = html_entity_decode( menu_page_url( $submenu_slug, false ), ENT_QUOTES, get_bloginfo( 'charset' ) );
     3525                        $submenu_url = WP_HTML_Decoder::decode_attribute( menu_page_url( $submenu_slug, false ) );
    34903526                    }
    3491 
    34923527                    if ( $submenu_url ) {
    34933528                        $menu_commands[] = array(
Note: See TracChangeset for help on using the changeset viewer.