Commit 0f60e23276 for wordpress.org
commit 0f60e23276dc9c2b2ddd649db369f88828ad24cd
Author: westonruter <westonruter@git.wordpress.org>
Date: Sat Oct 10 17:52:51 2026 +0000
HTML API: Restore spec-mirroring structure in HTML Processor.
Some code in `WP_HTML_Processor` is written to mirror the steps of the HTML specification, so that it can be compared against the living standard as it changes and extended as more of it is supported. Static analysis reports parts of that structure as unreachable or redundant, which is accurate but beside the point. In r64250 two such places were restructured to satisfy PHPStan: the `else` branch for a `FORM` end tag in `step_in_body()`, which corresponds to the specification's "Otherwise" steps, and the `is_tag_closer()` checks for end tags in `step_in_foreign_content()`, which spell out the specification's "An end tag whose tag name is…" conditions. Both are reverted, along with the trailing `bail()` calls those methods need again.
The errors these intentional constructs produce, along with a false positive where PHPStan does not see that `bookmark_token()` sets `$last_error` before throwing, are now ignored in the HTML API section of `phpstan.neon.dist` with an explanation, rather than left in baselines that invite contributors to fix them. The remaining baseline errors for the HTML API are genuine and are fixed:
* The bookmark counter is cast to a string before being passed to `set_bookmark()`.
* The `$node` variable is initialized before a loop that may not iterate.
* The `$is_closing_tag` property is documented as nullable.
* Redundant `isset()` checks on the always-set `WP_HTML_Text_Replacement::$text` property are removed.
This empties the `catch.neverThrown` baseline, which is deleted.
Developed in https://github.com/WordPress/wordpress-develop/pull/14141.
Follow-up to r58779, r58871, r64250.
Props westonruter, dmsnell.
See #65817.
Built from https://develop.svn.wordpress.org/trunk@64294
git-svn-id: http://core.svn.wordpress.org/trunk@63444 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/html-api/class-wp-html-processor.php b/wp-includes/html-api/class-wp-html-processor.php
index 9eceb18729..f6d0d54822 100644
--- a/wp-includes/html-api/class-wp-html-processor.php
+++ b/wp-includes/html-api/class-wp-html-processor.php
@@ -2773,27 +2773,28 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
$this->state->stack_of_open_elements->remove_node( $node );
return true;
- }
+ } else {
+ /*
+ * > If the stack of open elements does not have a form element in scope,
+ * > then this is a parse error; return and ignore the token.
+ *
+ * Note that unlike in the clause above, this is checking for any FORM in scope.
+ */
+ if ( ! $this->state->stack_of_open_elements->has_element_in_scope( 'FORM' ) ) {
+ // Parse error: ignore the token.
+ return $this->step();
+ }
- /*
- * > If the stack of open elements does not have a form element in scope,
- * > then this is a parse error; return and ignore the token.
- *
- * Note that unlike in the clause above, this is checking for any FORM in scope.
- */
- if ( ! $this->state->stack_of_open_elements->has_element_in_scope( 'FORM' ) ) {
- // Parse error: ignore the token.
- return $this->step();
- }
+ $this->generate_implied_end_tags();
- $this->generate_implied_end_tags();
+ if ( ! $this->state->stack_of_open_elements->current_node_is( 'FORM' ) ) {
+ // @todo Indicate a parse error once it's possible. This error does not impact the logic here.
+ }
- if ( ! $this->state->stack_of_open_elements->current_node_is( 'FORM' ) ) {
- // @todo Indicate a parse error once it's possible. This error does not impact the logic here.
+ $this->state->stack_of_open_elements->pop_until( 'FORM' );
+ return true;
}
-
- $this->state->stack_of_open_elements->pop_until( 'FORM' );
- return true;
+ break;
/*
* > An end tag whose tag name is "p"
@@ -3355,6 +3356,8 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
*/
return $this->in_body_any_other_end_tag();
}
+
+ $this->bail( 'Should not have been able to reach end of IN BODY processing. Check HTML API code.' );
}
/**
@@ -3371,6 +3374,7 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
* @return bool Whether an element was found.
*/
private function in_body_any_other_end_tag(): bool {
+ $node = null;
$token_name = $this->get_token_name();
/*
@@ -4963,18 +4967,20 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
$this->state->stack_of_open_elements->pop();
}
return true;
- } else {
- /*
- * > An end tag whose name is "script", if the current node is an SVG script element.
- */
- if ( 'SCRIPT' === $this->state->current_token->node_name && 'svg' === $this->state->current_token->namespace ) {
- $this->state->stack_of_open_elements->pop();
- return true;
- }
+ }
- /*
- * > Any other end tag
- */
+ /*
+ * > An end tag whose name is "script", if the current node is an SVG script element.
+ */
+ if ( $this->is_tag_closer() && 'SCRIPT' === $this->state->current_token->node_name && 'svg' === $this->state->current_token->namespace ) {
+ $this->state->stack_of_open_elements->pop();
+ return true;
+ }
+
+ /*
+ * > Any other end tag
+ */
+ if ( $this->is_tag_closer() ) {
$node = $this->state->stack_of_open_elements->current_node();
if ( $tag_name !== $node->node_name ) {
// @todo Indicate a parse error once it's possible.
@@ -5074,6 +5080,8 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
$this->bail( "Unaware of the requested parsing mode: '{$this->state->insertion_mode}'." );
}
}
+
+ $this->bail( 'Should not have been able to reach end of IN FOREIGN CONTENT processing. Check HTML API code.' );
}
/*
@@ -5092,7 +5100,7 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
* @return string Name of created bookmark.
*/
private function bookmark_token() {
- if ( ! parent::set_bookmark( ++$this->bookmark_counter ) ) {
+ if ( ! parent::set_bookmark( (string) ++$this->bookmark_counter ) ) {
$this->last_error = self::ERROR_EXCEEDED_MAX_BOOKMARKS;
throw new Exception( 'could not allocate bookmark' );
}
diff --git a/wp-includes/html-api/class-wp-html-tag-processor.php b/wp-includes/html-api/class-wp-html-tag-processor.php
index 7a12fce2d1..afd4dca2c0 100644
--- a/wp-includes/html-api/class-wp-html-tag-processor.php
+++ b/wp-includes/html-api/class-wp-html-tag-processor.php
@@ -690,7 +690,7 @@ class WP_HTML_Tag_Processor {
* Whether the current tag is an opening tag, e.g. <div>, or a closing tag, e.g. </div>.
*
* @since 6.2.0
- * @var bool
+ * @var bool|null
*/
private $is_closing_tag;
@@ -2767,7 +2767,7 @@ class WP_HTML_Tag_Processor {
return $by_start;
}
- $by_text = isset( $a->text, $b->text ) ? strcmp( $a->text, $b->text ) : 0;
+ $by_text = strcmp( $a->text, $b->text );
if ( 0 !== $by_text ) {
return $by_text;
}
diff --git a/wp-includes/version.php b/wp-includes/version.php
index bc099cae45..c46130ea83 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-alpha-64293';
+$wp_version = '7.2-alpha-64294';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.