Make WordPress Core

Changeset 59285


Ignore:
Timestamp:
10/23/2024 10:03:23 PM (2 years ago)
Author:
westonruter
Message:

HTML API: Fix extensibility of WP_HTML_Processor::next_token().

Break out logic from the next_token() method into a private method which may call itself recursively. This allows for subclasses to override the next_token() method and be assured that each call to next_token() corresponds with the consumption of one single token. This also parallels how WP_HTML_Tag_Processor::next_token() wraps a private base_class_next_token() method.

Props westonruter, jonsurrell.
Fixes #62269.

Location:
trunk
Files:
2 added
2 edited

Legend:

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

    r59248 r59285  
    605605
    606606        /**
    607          * Ensures internal accounting is maintained for HTML semantic rules while
    608          * the underlying Tag Processor class is seeking to a bookmark.
     607         * Finds the next token in the HTML document.
    609608         *
    610609         * This doesn't currently have a way to represent non-tags and doesn't process
    … …  
    613612         *
    614613         * @since 6.5.0 Added for internal support; do not use.
     614         * @since 6.7.1 Refactored so subclasses may extend.
     615         *
     616         * @return bool Whether a token was parsed.
     617         */
     618        public function next_token(): bool {
     619                return $this->_next_token();
     620        }
     621
     622        /**
     623         * Ensures internal accounting is maintained for HTML semantic rules while
     624         * the underlying Tag Processor class is seeking to a bookmark.
     625         *
     626         * This doesn't currently have a way to represent non-tags and doesn't process
     627         * semantic rules for text nodes. For access to the raw tokens consider using
     628         * WP_HTML_Tag_Processor instead.
     629         *
     630         * @since 6.7.1 Added for internal support; do not use.
    615631         *
    616632         * @access private
    … …  
    618634         * @return bool
    619635         */
    620         public function next_token(): bool {
     636        private function _next_token(): bool {
    621637                $this->current_element = null;
    622638
    … …  
    636652                 */
    637653                if ( empty( $this->element_queue ) && $this->step() ) {
    638                         return $this->next_token();
     654                        return $this->_next_token();
    639655                }
    640656
    … …  
    647663                        }
    648664
    649                         return empty( $this->element_queue ) ? false : $this->next_token();
     665                        return empty( $this->element_queue ) ? false : $this->_next_token();
    650666                }
    651667
    … …  
    658674                 */
    659675                if ( 'root-node' === $this->current_element->token->bookmark_name ) {
    660                         return $this->next_token();
     676                        return $this->_next_token();
    661677                }
    662678
    … …  
    670686                // Avoid sending close events for elements which don't expect a closing.
    671687                if ( $is_pop && ! $this->expects_closer( $this->current_element->token ) ) {
    672                         return $this->next_token();
     688                        return $this->_next_token();
    673689                }
    674690
  • trunk/tests/phpunit/tests/html-api/wpHtmlProcessor.php

    r59248 r59285  
    883883                $this->assertTrue( $processor->is_tag_closer() );
    884884        }
     885
     886        /**
     887         * Data provider.
     888         *
     889         * @return array
     890         */
     891        public function data_html_processor_with_extended_next_token() {
     892                return array(
     893                        'single_instance_per_tag'   => array(
     894                                'html'                  => '
     895                                        <html>
     896                                                <head>
     897                                                        <meta charset="utf-8">
     898                                                        <title>Hello World</title>
     899                                                </head>
     900                                                <body>
     901                                                        <h1>Hello World!</h1>
     902                                                        <img src="example.png">
     903                                                        <p>Each tag should occur only once in this document.<!--Closing P tag omitted intentionally.-->
     904                                                        <footer>The end.</footer>
     905                                                </body>
     906                                        </html>
     907                                ',
     908                                'expected_token_counts' => array(
     909                                        '+HTML'    => 1,
     910                                        '+HEAD'    => 1,
     911                                        '#text'    => 14,
     912                                        '+META'    => 1,
     913                                        '+TITLE'   => 1,
     914                                        '-HEAD'    => 1,
     915                                        '+BODY'    => 1,
     916                                        '+H1'      => 1,
     917                                        '-H1'      => 1,
     918                                        '+IMG'     => 1,
     919                                        '+P'       => 1,
     920                                        '#comment' => 1,
     921                                        '-P'       => 1,
     922                                        '+FOOTER'  => 1,
     923                                        '-FOOTER'  => 1,
     924                                        '-BODY'    => 1,
     925                                        '-HTML'    => 1,
     926                                        ''         => 1,
     927                                ),
     928                                'expected_xpaths'       => array(
     929                                        0 => '/*[1][self::HTML]',
     930                                        1 => '/*[1][self::HTML]/*[1][self::HEAD]',
     931                                        2 => '/*[1][self::HTML]/*[1][self::HEAD]/*[1][self::META]',
     932                                        3 => '/*[1][self::HTML]/*[1][self::HEAD]/*[2][self::TITLE]',
     933                                        4 => '/*[1][self::HTML]/*[2][self::BODY]',
     934                                        5 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::H1]',
     935                                        6 => '/*[1][self::HTML]/*[2][self::BODY]/*[2][self::IMG]',
     936                                        7 => '/*[1][self::HTML]/*[2][self::BODY]/*[3][self::P]',
     937                                        8 => '/*[1][self::HTML]/*[2][self::BODY]/*[4][self::FOOTER]',
     938                                ),
     939                        ),
     940
     941                        'multiple_tag_instances'    => array(
     942                                'html'                  => '
     943                                        <html>
     944                                                <body>
     945                                                        <h1>Hello World!</h1>
     946                                                        <p>First
     947                                                        <p>Second
     948                                                        <p>Third
     949                                                        <ul>
     950                                                                <li>1
     951                                                                <li>2
     952                                                                <li>3
     953                                                        </ul>
     954                                                </body>
     955                                        </html>
     956                                ',
     957                                'expected_token_counts' => array(
     958                                        '+HTML' => 1,
     959                                        '+HEAD' => 1,
     960                                        '-HEAD' => 1,
     961                                        '+BODY' => 1,
     962                                        '#text' => 13,
     963                                        '+H1'   => 1,
     964                                        '-H1'   => 1,
     965                                        '+P'    => 3,
     966                                        '-P'    => 3,
     967                                        '+UL'   => 1,
     968                                        '+LI'   => 3,
     969                                        '-LI'   => 3,
     970                                        '-UL'   => 1,
     971                                        '-BODY' => 1,
     972                                        '-HTML' => 1,
     973                                        ''      => 1,
     974                                ),
     975                                'expected_xpaths'       => array(
     976                                        0  => '/*[1][self::HTML]',
     977                                        1  => '/*[1][self::HTML]/*[1][self::HEAD]',
     978                                        2  => '/*[1][self::HTML]/*[2][self::BODY]',
     979                                        3  => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::H1]',
     980                                        4  => '/*[1][self::HTML]/*[2][self::BODY]/*[2][self::P]',
     981                                        5  => '/*[1][self::HTML]/*[2][self::BODY]/*[3][self::P]',
     982                                        6  => '/*[1][self::HTML]/*[2][self::BODY]/*[4][self::P]',
     983                                        7  => '/*[1][self::HTML]/*[2][self::BODY]/*[5][self::UL]',
     984                                        8  => '/*[1][self::HTML]/*[2][self::BODY]/*[5][self::UL]/*[1][self::LI]',
     985                                        9  => '/*[1][self::HTML]/*[2][self::BODY]/*[5][self::UL]/*[2][self::LI]',
     986                                        10 => '/*[1][self::HTML]/*[2][self::BODY]/*[5][self::UL]/*[3][self::LI]',
     987                                ),
     988                        ),
     989
     990                        'extreme_nested_formatting' => array(
     991                                'html'                  => '
     992                                        <html>
     993                                                <body>
     994                                                        <p>
     995                                                                <strong><em><strike><i><b><u>FORMAT</u></b></i></strike></em></strong>
     996                                                        </p>
     997                                                </body>
     998                                        </html>
     999                                ',
     1000                                'expected_token_counts' => array(
     1001                                        '+HTML'   => 1,
     1002                                        '+HEAD'   => 1,
     1003                                        '-HEAD'   => 1,
     1004                                        '+BODY'   => 1,
     1005                                        '#text'   => 7,
     1006                                        '+P'      => 1,
     1007                                        '+STRONG' => 1,
     1008                                        '+EM'     => 1,
     1009                                        '+STRIKE' => 1,
     1010                                        '+I'      => 1,
     1011                                        '+B'      => 1,
     1012                                        '+U'      => 1,
     1013                                        '-U'      => 1,
     1014                                        '-B'      => 1,
     1015                                        '-I'      => 1,
     1016                                        '-STRIKE' => 1,
     1017                                        '-EM'     => 1,
     1018                                        '-STRONG' => 1,
     1019                                        '-P'      => 1,
     1020                                        '-BODY'   => 1,
     1021                                        '-HTML'   => 1,
     1022                                        ''        => 1,
     1023                                ),
     1024                                'expected_xpaths'       => array(
     1025                                        0 => '/*[1][self::HTML]',
     1026                                        1 => '/*[1][self::HTML]/*[1][self::HEAD]',
     1027                                        2 => '/*[1][self::HTML]/*[2][self::BODY]',
     1028                                        3 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::P]',
     1029                                        4 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::P]/*[1][self::STRONG]',
     1030                                        5 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::P]/*[1][self::STRONG]/*[1][self::EM]',
     1031                                        6 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::P]/*[1][self::STRONG]/*[1][self::EM]/*[1][self::STRIKE]',
     1032                                        7 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::P]/*[1][self::STRONG]/*[1][self::EM]/*[1][self::STRIKE]/*[1][self::I]',
     1033                                        8 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::P]/*[1][self::STRONG]/*[1][self::EM]/*[1][self::STRIKE]/*[1][self::I]/*[1][self::B]',
     1034                                        9 => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::P]/*[1][self::STRONG]/*[1][self::EM]/*[1][self::STRIKE]/*[1][self::I]/*[1][self::B]/*[1][self::U]',
     1035                                ),
     1036                        ),
     1037                );
     1038        }
     1039
     1040        /**
     1041         * Ensures that subclasses to WP_HTML_Processor can do bookkeeping by extending the next_token() method.
     1042         *
     1043         * @ticket ?
     1044         * @dataProvider data_html_processor_with_extended_next_token
     1045         */
     1046        public function test_ensure_next_token_method_extensibility( $html, $expected_token_counts, $expected_xpaths ) {
     1047                require_once DIR_TESTDATA . '/html-api/html-xpath-generating-processor.php';
     1048
     1049                $processor     = HTML_XPath_Generating_Processor::create_full_parser( $html );
     1050                $actual_xpaths = array();
     1051                while ( $processor->next_tag() ) {
     1052                        if ( ! $processor->is_tag_closer() ) {
     1053                                $processor->set_attribute( 'xpath', $processor->get_xpath() );
     1054                                $actual_xpaths[] = $processor->get_xpath();
     1055                        }
     1056                }
     1057
     1058                $this->assertEquals( $expected_token_counts, $processor->token_seen_count, 'Snapshot: ' . var_export( $processor->token_seen_count, true ) );
     1059                $this->assertEquals( $expected_xpaths, $actual_xpaths, 'Snapshot: ' . var_export( $actual_xpaths, true ) );
     1060        }
    8851061}
Note: See TracChangeset for help on using the changeset viewer.