From 511dcb752044cf012ceea81392545b8176889b9b Mon Sep 17 00:00:00 2001 From: Bernhard Reiter Date: Wed, 13 Dec 2023 17:53:19 +0000 Subject: [PATCH] HTML API: Add support for H1-H6 elements in the HTML Processor. Previously these have been unsupported, but in this patch, support is added for the tags so that the HTML Processor can process documents containing them. There was a design discussion about introducing a constant to communicate "any of the H1 - H6 elements" but this posed a number of challenges that don't need to be answered in this patch. For the time being, because the HTML specification treats H1 - H6 specially as a single kind of element, the HTML Processor uses an internal hard-coded string to indicate this. By using a hard-coded string it's possible to avoid introducing a class constant which cannot be made private due to PHP's class design. In the future, this will probably appear as a special constant in a new constant-containing class. Props dmsnell, jonsurrell. Fixes #60060. Built from https://develop.svn.wordpress.org/trunk@57186 git-svn-id: http://core.svn.wordpress.org/trunk@56697 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- .../html-api/class-wp-html-open-elements.php | 14 +++++ .../html-api/class-wp-html-processor.php | 56 ++++++++++++++++++- wp-includes/version.php | 2 +- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/wp-includes/html-api/class-wp-html-open-elements.php b/wp-includes/html-api/class-wp-html-open-elements.php index fe5625545b..55c4d3a663 100644 --- a/wp-includes/html-api/class-wp-html-open-elements.php +++ b/wp-includes/html-api/class-wp-html-open-elements.php @@ -116,6 +116,13 @@ class WP_HTML_Open_Elements { return true; } + if ( + '(internal: H1 through H6 - do not use)' === $tag_name && + in_array( $node->node_name, array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ), true ) + ) { + return true; + } + switch ( $node->node_name ) { case 'HTML': return false; @@ -270,6 +277,13 @@ class WP_HTML_Open_Elements { foreach ( $this->walk_up() as $item ) { $this->pop(); + if ( + '(internal: H1 through H6 - do not use)' === $tag_name && + in_array( $item->node_name, array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ), true ) + ) { + return true; + } + if ( $tag_name === $item->node_name ) { return true; } diff --git a/wp-includes/html-api/class-wp-html-processor.php b/wp-includes/html-api/class-wp-html-processor.php index 779c7afec3..14dfc3aa86 100644 --- a/wp-includes/html-api/class-wp-html-processor.php +++ b/wp-includes/html-api/class-wp-html-processor.php @@ -102,7 +102,7 @@ * - Containers: ADDRESS, BLOCKQUOTE, DETAILS, DIALOG, DIV, FOOTER, HEADER, MAIN, MENU, SPAN, SUMMARY. * - Form elements: BUTTON, FIELDSET, SEARCH. * - Formatting elements: B, BIG, CODE, EM, FONT, I, SMALL, STRIKE, STRONG, TT, U. - * - Heading elements: HGROUP. + * - Heading elements: H1, H2, H3, H4, H5, H6, HGROUP. * - Links: A. * - Lists: DL. * - Media elements: FIGCAPTION, FIGURE, IMG. @@ -697,6 +697,60 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor { $this->state->stack_of_open_elements->pop_until( $tag_name ); return true; + /* + * > A start tag whose tag name is one of: "h1", "h2", "h3", "h4", "h5", "h6" + */ + case '+H1': + case '+H2': + case '+H3': + case '+H4': + case '+H5': + case '+H6': + if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) { + $this->close_a_p_element(); + } + + if ( + in_array( + $this->state->stack_of_open_elements->current_node()->node_name, + array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ), + true + ) + ) { + // @TODO: Indicate a parse error once it's possible. + $this->state->stack_of_open_elements->pop(); + } + + $this->insert_html_element( $this->state->current_token ); + return true; + + /* + * > An end tag whose tag name is one of: "h1", "h2", "h3", "h4", "h5", "h6" + */ + case '-H1': + case '-H2': + case '-H3': + case '-H4': + case '-H5': + case '-H6': + if ( ! $this->state->stack_of_open_elements->has_element_in_scope( '(internal: H1 through H6 - do not use)' ) ) { + /* + * This is a parse error; ignore the token. + * + * @TODO: Indicate a parse error once it's possible. + */ + return $this->step(); + } + + $this->generate_implied_end_tags(); + + if ( $this->state->stack_of_open_elements->current_node()->node_name !== $tag_name ) { + // @TODO: Record parse error: this error doesn't impact parsing. + } + + $this->state->stack_of_open_elements->pop_until( '(internal: H1 through H6 - do not use)' ); + return true; + /* * > An end tag whose tag name is "p" */ diff --git a/wp-includes/version.php b/wp-includes/version.php index 91eeea0f78..6648723d44 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.5-alpha-57185'; +$wp_version = '6.5-alpha-57186'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.