Make WordPress Core

Changeset 57115


Ignore:
Timestamp:
11/17/2023 06:11:31 AM (5 months 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.