Skip to content

Commit

Permalink
HTML API: Report breadcrumbs properly when visiting virtual nodes.
Browse files Browse the repository at this point in the history
When [58304] introduced the abililty to visit virtual nodes in the HTML document,
those being the nodes which are implied by the HTML but no explicitly present in
the raw text, a bug was introduced in the `get_breadcrumbs()` method because it
wasn't updated to be aware of the virtual nodes. Therefore it would report the
wrong breadcrumbs for virtual nodes. Since the new `get_depth()` method is based
on the same logic it was also broken for virtual nodes.

In this patch, the breadcrumbs have been updated to account for the virtual nodes
and the depth method has been updated to rely on the fixed breadcrumb logic.

Developed in #6914
Discussed in https://core.trac.wordpress.org/ticket/61348

Follow-up to [58304].

Props dmsnell, jonsurrell, zieladam.
See #61348.


git-svn-id: https://develop.svn.wordpress.org/trunk@58588 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
dmsnell committed Jun 27, 2024
1 parent d6bbd8d commit 9cbaee3
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 7 deletions.
14 changes: 13 additions & 1 deletion src/wp-includes/html-api/class-wp-html-open-elements.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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 (
Expand Down Expand Up @@ -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;
Expand Down
52 changes: 46 additions & 6 deletions src/wp-includes/html-api/class-wp-html-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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 ) {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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();
}

/**
Expand Down

0 comments on commit 9cbaee3

Please sign in to comment.