Make WordPress Core

Changeset 55619


Ignore:
Timestamp:
04/04/2023 10:04:45 AM (20 months ago)
Author:
Bernhard Reiter
Message:

HTML API: Add has_self_closing_flag() to Tag Processor.

In this patch we're adding has_self_closing_flag() to the HTML Tag Processor.
This exposes whether a currently-matched tag contains the self-closing flag /.

This information is critical for the evolution of the HTML API in order
to track and parse HTML structure, specifically, knowing whether an
HTML foreign element is self-closing or not.

Props dmsnell, zieladam.
Fixes #58009.

Location:
trunk
Files:
2 edited

Legend:

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

    r55555 r55619  
    17581758
    17591759        return strtoupper( $tag_name );
     1760    }
     1761
     1762    /**
     1763     * Indicates if the currently matched tag contains the self-closing flag.
     1764     *
     1765     * No HTML elements ought to have the self-closing flag and for those, the self-closing
     1766     * flag will be ignored. For void elements this is benign because they "self close"
     1767     * automatically. For non-void HTML elements though problems will appear if someone
     1768     * intends to use a self-closing element in place of that element with an empty body.
     1769     * For HTML foreign elements and custom elements the self-closing flag determines if
     1770     * they self-close or not.
     1771     *
     1772     * This function does not determine if a tag is self-closing,
     1773     * but only if the self-closing flag is present in the syntax.
     1774     *
     1775     * @since 6.3.0
     1776     *
     1777     * @return bool Whether the currently matched tag contains the self-closing flag.
     1778     */
     1779    public function has_self_closing_flag() {
     1780        if ( ! $this->tag_name_starts_at ) {
     1781            return false;
     1782        }
     1783
     1784        return '/' === $this->html[ $this->tag_ends_at - 1 ];
    17601785    }
    17611786
  • trunk/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php

    r55469 r55619  
    5050        $this->assertTrue( $p->next_tag( 'div' ), 'Querying an existing tag did not return true' );
    5151        $this->assertSame( 'DIV', $p->get_tag(), 'Accessing an existing tag name did not return "div"' );
     52    }
     53
     54    /**
     55     * @ticket 58009
     56     *
     57     * @covers WP_HTML_Tag_Processor::has_self_closing_flag
     58     *
     59     * @dataProvider data_has_self_closing_flag
     60     *
     61     * @param string $html Input HTML whose first tag might contain the self-closing flag `/`.
     62     * @param bool $flag_is_set Whether the input HTML's first tag contains the self-closing flag.
     63     */
     64    public function test_has_self_closing_flag_matches_input_html( $html, $flag_is_set ) {
     65        $p = new WP_HTML_Tag_Processor( $html );
     66        $p->next_tag( array( 'tag_closers' => 'visit' ) );
     67
     68        if ( $flag_is_set ) {
     69            $this->assertTrue( $p->has_self_closing_flag(), 'Did not find the self-closing tag when it was present.' );
     70        } else {
     71            $this->assertFalse( $p->has_self_closing_flag(), 'Found the self-closing tag when it was absent.' );
     72        }
     73    }
     74
     75    /**
     76     * Data provider. HTML tags which might have a self-closing flag, and an indicator if they do.
     77     *
     78     * @return array[]
     79     */
     80    public function data_has_self_closing_flag() {
     81        return array(
     82            // These should not have a self-closer, and will leave an element un-closed if it's assumed they are self-closing.
     83            'Self-closing flag on non-void HTML element' => array( '<div />', true ),
     84            'No self-closing flag on non-void HTML element' => array( '<div>', false ),
     85            // These should not have a self-closer, but are benign when used because the elements are void.
     86            'Self-closing flag on void HTML element'     => array( '<img />', true ),
     87            'No self-closing flag on void HTML element'  => array( '<img>', false ),
     88            'Self-closing flag on void HTML element without spacing' => array( '<img/>', true ),
     89            // These should not have a self-closer, but as part of a tag closer they are entirely ignored.
     90            'Self-closing flag on tag closer'            => array( '</textarea />', true ),
     91            'No self-closing flag on tag closer'         => array( '</textarea>', false ),
     92            // These can and should have self-closers, and will leave an element un-closed if it's assumed they aren't self-closing.
     93            'Self-closing flag on a foreign element'     => array( '<circle />', true ),
     94            'No self-closing flag on a foreign element'  => array( '<circle>', false ),
     95            // These involve syntax peculiarities.
     96            'Self-closing flag after extra spaces'       => array( '<div      />', true ),
     97            'Self-closing flag after attribute'          => array( '<div id=test/>', true ),
     98            'Self-closing flag after quoted attribute'   => array( '<div id="test"/>', true ),
     99            'Self-closing flag after boolean attribute'  => array( '<div enabled/>', true ),
     100            'Boolean attribute that looks like a self-closer' => array( '<div / >', false ),
     101        );
    52102    }
    53103
Note: See TracChangeset for help on using the changeset viewer.