diff --git a/src/wp-includes/html-api/class-wp-html-open-elements.php b/src/wp-includes/html-api/class-wp-html-open-elements.php
index 7f148a7af7068..15479801dda10 100644
--- a/src/wp-includes/html-api/class-wp-html-open-elements.php
+++ b/src/wp-includes/html-api/class-wp-html-open-elements.php
@@ -308,11 +308,15 @@ public function has_p_in_button_scope() {
*/
public function pop() {
$item = array_pop( $this->stack );
-
if ( null === $item ) {
return false;
}
+ if ( 'context-node' === $item->bookmark_name ) {
+ $this->stack[] = $item;
+ return false;
+ }
+
$this->after_element_pop( $item );
return true;
}
@@ -329,6 +333,10 @@ public function pop() {
*/
public function pop_until( $tag_name ) {
foreach ( $this->walk_up() as $item ) {
+ if ( 'context-node' === $item->bookmark_name ) {
+ return true;
+ }
+
$this->pop();
if (
@@ -369,6 +377,10 @@ public function push( $stack_item ) {
* @return bool Whether the node was found and removed from the stack of open elements.
*/
public function remove_node( $token ) {
+ if ( 'context-node' === $token->bookmark_name ) {
+ return false;
+ }
+
foreach ( $this->walk_up() as $position_from_end => $item ) {
if ( $token->bookmark_name !== $item->bookmark_name ) {
continue;
diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php
index 0eb597edcd803..29f1c7ac6d4cc 100644
--- a/src/wp-includes/html-api/class-wp-html-processor.php
+++ b/src/wp-includes/html-api/class-wp-html-processor.php
@@ -519,10 +519,12 @@ public function next_token() {
return false;
}
- if ( 0 === count( $this->element_queue ) && ! $this->step() ) {
- while ( $this->state->stack_of_open_elements->pop() ) {
+ if ( 'done' !== $this->has_seen_context_node && 0 === count( $this->element_queue ) && ! $this->step() ) {
+ while ( 'context-node' !== $this->state->stack_of_open_elements->current_node()->bookmark_name && $this->state->stack_of_open_elements->pop() ) {
continue;
}
+ $this->has_seen_context_node = 'done';
+ return $this->next_token();
}
$this->current_element = array_shift( $this->element_queue );
@@ -537,7 +539,11 @@ public function next_token() {
}
if ( ! isset( $this->current_element ) ) {
- return $this->next_token();
+ if ( 'done' === $this->has_seen_context_node ) {
+ return false;
+ } else {
+ return $this->next_token();
+ }
}
if ( isset( $this->context_node ) && WP_HTML_Stack_Event::POP === $this->current_element->operation && $this->context_node === $this->current_element->token ) {
@@ -782,16 +788,48 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
*
* @since 6.4.0
*
- * @todo make aware of queue of elements, because stack operations have already been done by now.
- *
* @return string[]|null Array of tag names representing path to matched node, if matched, otherwise NULL.
*/
public function get_breadcrumbs() {
$breadcrumbs = array();
+
foreach ( $this->state->stack_of_open_elements->walk_down() as $stack_item ) {
$breadcrumbs[] = $stack_item->node_name;
}
+ if ( ! $this->is_virtual() ) {
+ return $breadcrumbs;
+ }
+
+ foreach ( $this->element_queue as $queue_item ) {
+ if ( $this->current_element->token->bookmark_name === $queue_item->token->bookmark_name ) {
+ break;
+ }
+
+ if ( 'context-node' === $queue_item->token->bookmark_name ) {
+ break;
+ }
+
+ if ( 'real' === $queue_item->provenance ) {
+ break;
+ }
+
+ if ( WP_HTML_Stack_Event::PUSH === $queue_item->operation ) {
+ $breadcrumbs[] = $queue_item->token->node_name;
+ } else {
+ array_pop( $breadcrumbs );
+ }
+ }
+
+ if ( null !== parent::get_token_name() && ! parent::is_tag_closer() ) {
+ array_pop( $breadcrumbs );
+ }
+
+ // Add the virtual node we're at.
+ if ( WP_HTML_Stack_Event::PUSH === $this->current_element->operation ) {
+ $breadcrumbs[] = $this->current_element->token->node_name;
+ }
+
return $breadcrumbs;
}
@@ -821,7 +859,9 @@ public function get_breadcrumbs() {
* @return int Nesting-depth of current location in the document.
*/
public function get_current_depth() {
- return $this->state->stack_of_open_elements->count();
+ return $this->is_virtual()
+ ? count( $this->get_breadcrumbs() )
+ : $this->state->stack_of_open_elements->count();
}
/**