Make WordPress Core

Changeset 57115


Ignore:
Timestamp:
11/17/2023 06:11:31 AM (3 years ago)
Author:
Bernhard Reiter
Message:

HTML API: Add support for containers elements, including ARTICLE.

There are a handful of elements which behave similarly and are generically container elements. These are the following elements:

ADDRESS, ARTICLE, ASIDE, BLOCKQUOTE, CENTER, DETAILS, DIALOG, DIR,
DL, DIV, FIELDSET, FIGCAPTION, FIGURE, FOOTER, HEADER, HGROUP, MAIN,
MENU, NAV, SEARCH, SECTION, SUMMARY

This patch adds support to the HTML Processor for handling these elements. They do not require any additional logic in the rest of the class, and carry no specific semantic rules for parsing beyond what is listed in their group in the IN BODY section of the HTML5 specification.

Props dmsnell.
Fixes #59914.

Location:
trunk
Files:
3 edited

Legend:

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

    r57077 r57115  
    100100 * The following list specifies the HTML tags that _are_ supported:
    101101 *
     102 *  - Containers: ADDRESS, BLOCKQUOTE, DETAILS, DIALOG, DIV, FOOTER, HEADER, MAIN, MENU, SPAN, SUMMARY.
     103 *  - Form elements: BUTTON, FIELDSET, SEARCH.
     104 *  - Formatting elements: B, BIG, CODE, EM, FONT, I, SMALL, STRIKE, STRONG, TT, U.
     105 *  - Heading elements: HGROUP.
    102106 *  - Links: A.
    103  *  - The formatting elements: B, BIG, CODE, EM, FONT, I, SMALL, STRIKE, STRONG, TT, U.
    104  *  - Containers: DIV, FIGCAPTION, FIGURE, SPAN.
    105  *  - Form elements: BUTTON.
     107 *  - Lists: DL.
     108 *  - Media elements: FIGCAPTION, FIGURE, IMG.
    106109 *  - Paragraph: P.
    107  *  - Void elements: IMG.
     110 *  - Sectioning elements: ARTICLE, ASIDE, NAV, SECTION
     111 *  - Deprecated elements: CENTER, DIR
    108112 *
    109113 * ### Supported markup
     
    622626                         * > "main", "menu", "nav", "ol", "p", "search", "section", "summary", "ul"
    623627                         */
     628                        case '+ADDRESS':
     629                        case '+ARTICLE':
     630                        case '+ASIDE':
    624631                        case '+BLOCKQUOTE':
     632                        case '+CENTER':
     633                        case '+DETAILS':
     634                        case '+DIALOG':
     635                        case '+DIR':
    625636                        case '+DIV':
     637                        case '+DL':
     638                        case '+FIELDSET':
    626639                        case '+FIGCAPTION':
    627640                        case '+FIGURE':
     641                        case '+FOOTER':
     642                        case '+HEADER':
     643                        case '+HGROUP':
     644                        case '+MAIN':
     645                        case '+MENU':
     646                        case '+NAV':
    628647                        case '+P':
     648                        case '+SEARCH':
     649                        case '+SECTION':
     650                        case '+SUMMARY':
    629651                                if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
    630652                                        $this->close_a_p_element();
     
    640662                         * > "menu", "nav", "ol", "pre", "search", "section", "summary", "ul"
    641663                         */
     664                        case '-ADDRESS':
     665                        case '-ARTICLE':
     666                        case '-ASIDE':
    642667                        case '-BLOCKQUOTE':
    643668                        case '-BUTTON':
     669                        case '-CENTER':
     670                        case '-DETAILS':
     671                        case '-DIALOG':
     672                        case '-DIR':
    644673                        case '-DIV':
     674                        case '-DL':
     675                        case '-FIELDSET':
    645676                        case '-FIGCAPTION':
    646677                        case '-FIGURE':
     678                        case '-FOOTER':
     679                        case '-HEADER':
     680                        case '-HGROUP':
     681                        case '-MAIN':
     682                        case '-MENU':
     683                        case '-NAV':
     684                        case '-SEARCH':
     685                        case '-SECTION':
     686                        case '-SUMMARY':
    647687                                if ( ! $this->state->stack_of_open_elements->has_element_in_scope( $tag_name ) ) {
    648688                                        // @TODO: Report parse error.
  • trunk/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php

    r56943 r57115  
    3838                $supported_elements = array(
    3939                        'A',
     40                        'ADDRESS',
     41                        'ARTICLE',
     42                        'ASIDE',
    4043                        'B',
    4144                        'BIG',
    4245                        'BUTTON',
     46                        'CENTER', // Neutralized
    4347                        'CODE',
     48                        'DETAILS',
     49                        'DIALOG',
     50                        'DIR',
    4451                        'DIV',
     52                        'DL',
    4553                        'EM',
     54                        'FIELDSET',
    4655                        'FIGCAPTION',
    4756                        'FIGURE',
    4857                        'FONT',
     58                        'FOOTER',
     59                        'HEADER',
     60                        'HGROUP',
    4961                        'I',
    5062                        'IMG',
     63                        'MAIN',
     64                        'MENU',
     65                        'NAV',
    5166                        'P',
     67                        'SEARCH',
     68                        'SECTION',
    5269                        'SMALL',
    5370                        'SPAN',
    5471                        'STRIKE',
    5572                        'STRONG',
     73                        'SUMMARY',
    5674                        'TT',
    5775                        'U',
     
    100118                        'ABBR',
    101119                        'ACRONYM', // Neutralized
    102                         'ADDRESS',
    103120                        'APPLET', // Deprecated
    104121                        'AREA',
    105                         'ARTICLE',
    106                         'ASIDE',
    107122                        'AUDIO',
    108123                        'BASE',
     
    115130                        'CANVAS',
    116131                        'CAPTION',
    117                         'CENTER', // Neutralized
    118132                        'CITE',
    119133                        'COL',
     
    123137                        'DD',
    124138                        'DEL',
    125                         'DETAILS',
    126139                        'DEFN',
    127                         'DIALOG',
    128                         'DL',
    129140                        'DT',
    130141                        'EMBED',
    131                         'FIELDSET',
    132                         'FOOTER',
    133142                        'FORM',
    134143                        'FRAME',
     
    141150                        'H6',
    142151                        'HEAD',
    143                         'HEADER',
    144                         'HGROUP',
    145152                        'HR',
    146153                        'HTML',
     
    156163                        'LINK',
    157164                        'LISTING', // Deprecated, use PRE instead.
    158                         'MAIN',
    159165                        'MAP',
    160166                        'MARK',
    161167                        'MARQUEE', // Deprecated
    162168                        'MATH',
    163                         'MENU',
    164169                        'META',
    165170                        'METER',
    166171                        'MULTICOL', // Deprecated
    167                         'NAV',
    168172                        'NEXTID', // Deprecated
    169173                        'NOBR', // Neutralized
     
    188192                        'SAMP',
    189193                        'SCRIPT',
    190                         'SECTION',
    191194                        'SELECT',
    192195                        'SLOT',
     
    195198                        'STYLE',
    196199                        'SUB',
    197                         'SUMMARY',
    198200                        'SUP',
    199201                        'SVG',
     
    349351                                2,
    350352                        ),
     353                        'MAIN inside MAIN inside SPAN'          => array( '<span><main><main target>', array( 'HTML', 'BODY', 'SPAN', 'MAIN', 'MAIN' ), 1 ),
     354                        'MAIN next to unclosed P'               => array( '<p><main target>', array( 'HTML', 'BODY', 'MAIN' ), 1 ),
    351355                );
    352356        }
  • trunk/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRules.php

    r56790 r57115  
    1818
    1919        /**
     20         * Verifies that tags in the container group, including the ARTICLE element,
     21         * close out an open P element if one exists.
     22         *
     23         * @covers WP_HTML_Processor::step_in_body
     24         *
     25         * @ticket 59914
     26         *
     27         * @dataProvider data_article_container_group
     28         *
     29         * @param string $tag_name Name of tag in group under test.
     30         */
     31        public function test_in_body_article_group_closes_open_p_element( $tag_name ) {
     32                $processor = WP_HTML_Processor::create_fragment( "<p><p><p><p><{$tag_name} target>" );
     33
     34                while ( $processor->next_tag() && null === $processor->get_attribute( 'target' ) ) {
     35                        continue;
     36                }
     37
     38                $this->assertEquals(
     39                        $tag_name,
     40                        $processor->get_tag(),
     41                        "Expected to find {$tag_name} but found {$processor->get_tag()} instead."
     42                );
     43
     44                $this->assertSame(
     45                        array( 'HTML', 'BODY', $tag_name ),
     46                        $processor->get_breadcrumbs(),
     47                        "Expected to find {$tag_name} as direct child of BODY as a result of implicitly closing an open P element."
     48                );
     49        }
     50
     51        /**
     52         * Verifies that tags in the container group, including the ARTICLE element,
     53         * nest inside each other despite being invalid in most cases.
     54         *
     55         * @covers WP_HTML_Processor::step_in_body
     56         *
     57         * @ticket 59914
     58         *
     59         * @dataProvider data_article_container_group
     60         *
     61         * @param string $tag_name Name of tag in group under test.
     62         */
     63        public function test_in_body_article_group_can_nest_inside_itself( $tag_name ) {
     64                $processor = WP_HTML_Processor::create_fragment( "<div><{$tag_name}><{$tag_name}></{$tag_name}><{$tag_name}><span><{$tag_name} target>" );
     65
     66                while ( $processor->next_tag() && null === $processor->get_attribute( 'target' ) ) {
     67                        continue;
     68                }
     69
     70                $this->assertSame(
     71                        array( 'HTML', 'BODY', 'DIV', $tag_name, $tag_name, 'SPAN', $tag_name ),
     72                        $processor->get_breadcrumbs(),
     73                        "Expected to find {$tag_name} deeply nested inside itself."
     74                );
     75        }
     76
     77        /**
     78         * Data provider.
     79         *
     80         * @return array[].
     81         */
     82        public function data_article_container_group() {
     83                $group = array();
     84
     85                foreach (
     86                        array(
     87                                'ADDRESS',
     88                                'ARTICLE',
     89                                'ASIDE',
     90                                'BLOCKQUOTE',
     91                                'CENTER',
     92                                'DETAILS',
     93                                'DIALOG',
     94                                'DIR',
     95                                'DL',
     96                                'DIV',
     97                                'FIELDSET',
     98                                'FIGCAPTION',
     99                                'FIGURE',
     100                                'FOOTER',
     101                                'HEADER',
     102                                'HGROUP',
     103                                'MAIN',
     104                                'MENU',
     105                                'NAV',
     106                                'SEARCH',
     107                                'SECTION',
     108                                'SUMMARY',
     109                        )
     110                        as $tag_name
     111                ) {
     112                        $group[ $tag_name ] = array( $tag_name );
     113                }
     114
     115                return $group;
     116        }
     117
     118        /**
    20119         * Verifies that when encountering an end tag for which there is no corresponding
    21120         * element in scope, that it skips the tag entirely.
     
    143242         * element on the stack of open elements before the matching opening.
    144243         *
     244         * @covers WP_HTML_Processor::step_in_body
     245         *
    145246         * @ticket 58907
    146247         *
    147248         * @since 6.4.0
    148          *
    149          * @covers WP_HTML_Processor::step_in_body
    150249         */
    151250        public function test_in_body_any_other_end_tag_with_unclosed_special_element() {
     
    166265         * open elements up to the matching opening.
    167266         *
     267         * @covers WP_HTML_Processor::step_in_body
     268         *
    168269         * @ticket 58907
    169270         *
    170271         * @since 6.4.0
    171          *
    172          * @covers WP_HTML_Processor::step_in_body
    173272         */
    174273        public function test_in_body_any_other_end_tag_with_unclosed_non_special_element() {
Note: See TracChangeset for help on using the changeset viewer.