<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[58590] branches/6.6/src/wp-includes/html-api/class-wp-html-processor.php: HTML API: Report breadcrumbs properly when visiting virtual nodes.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { white-space: pre-line; overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/58590">58590</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/58590","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>gziolo</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2024-06-28 07:11:25 +0000 (Fri, 28 Jun 2024)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>HTML API: Report breadcrumbs properly when visiting virtual nodes.

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.

Reviewed by jonsurrell, zieladam, gziolo.
Merges <a href="https://core.trac.wordpress.org/changeset/58588">[58588]</a> to the 6.6 branch.

Follow-up to <a href="https://core.trac.wordpress.org/changeset/58304">[58304]</a>.

Props dmsnell, hellofromtonya, joemcgill, jonsurrell, zieladam.
Fixes <a href="https://core.trac.wordpress.org/ticket/61348">#61348</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branches66srcwpincludeshtmlapiclasswphtmlopenelementsphp">branches/6.6/src/wp-includes/html-api/class-wp-html-open-elements.php</a></li>
<li><a href="#branches66srcwpincludeshtmlapiclasswphtmlprocessorphp">branches/6.6/src/wp-includes/html-api/class-wp-html-processor.php</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#branches66">branches/6.6/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<span class="cx" style="display: block; padding: 0 10px">Index: branches/6.6
</span><span class="cx" style="display: block; padding: 0 10px">===================================================================
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">--- branches/6.6 2024-06-27 23:15:53 UTC (rev 58589)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+++ branches/6.6  2024-06-28 07:11:25 UTC (rev 58590)
</ins><a id="branches66"></a>
<div class="propset"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Property changes: branches/6.6</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: svn:mergeinfo</h4></div>
<span class="cx" style="display: block; padding: 0 10px"> /branches/5.0:43681-43682,43684-43688,43719-43720,43723,43726-43727,43729-43731,43734-43744,43747,43751-43754,43758,43760-43765,43767-43770,43772,43774-43781,43783,43785,43790-43806,43808-43821,43825,43828,43830-43834,43836-43843,43846-43863,43867-43889,43891-43894,43897-43905,43908-43909,43911-43929,43931-43942,43946-43947,43949-43956,43959-43964,43967-43969,43988,43994,44014,44017,44047,44183,44185,44187-44206,44208-44213,44231-44232,44235,44248,44284,44287-44288
</span><span class="cx" style="display: block; padding: 0 10px"> /branches/5.5:49373-49379,49381
</span><span class="cx" style="display: block; padding: 0 10px"> /branches/5.8:51889
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/trunk:58570,58585
</del><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/trunk:58570,58585,58588
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="branches66srcwpincludeshtmlapiclasswphtmlopenelementsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/6.6/src/wp-includes/html-api/class-wp-html-open-elements.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/6.6/src/wp-includes/html-api/class-wp-html-open-elements.php     2024-06-27 23:15:53 UTC (rev 58589)
+++ branches/6.6/src/wp-includes/html-api/class-wp-html-open-elements.php       2024-06-28 07:11:25 UTC (rev 58590)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -308,11 +308,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function pop() {
</span><span class="cx" style="display: block; padding: 0 10px">                $item = array_pop( $this->stack );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">                 if ( null === $item ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return false;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( 'context-node' === $item->bookmark_name ) {
+                       $this->stack[] = $item;
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 $this->after_element_pop( $item );
</span><span class="cx" style="display: block; padding: 0 10px">                return true;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -329,6 +333,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function pop_until( $tag_name ) {
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $this->walk_up() as $item ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        if ( 'context-node' === $item->bookmark_name ) {
+                               return true;
+                       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->pop();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        if (
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -369,6 +377,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return bool Whether the node was found and removed from the stack of open elements.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function remove_node( $token ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                if ( 'context-node' === $token->bookmark_name ) {
+                       return false;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 foreach ( $this->walk_up() as $position_from_end => $item ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( $token->bookmark_name !== $item->bookmark_name ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                continue;
</span></span></pre></div>
<a id="branches66srcwpincludeshtmlapiclasswphtmlprocessorphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: branches/6.6/src/wp-includes/html-api/class-wp-html-processor.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- branches/6.6/src/wp-includes/html-api/class-wp-html-processor.php 2024-06-27 23:15:53 UTC (rev 58589)
+++ branches/6.6/src/wp-includes/html-api/class-wp-html-processor.php   2024-06-28 07:11:25 UTC (rev 58590)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -519,10 +519,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        return false;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( 0 === count( $this->element_queue ) && ! $this->step() ) {
-                       while ( $this->state->stack_of_open_elements->pop() ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         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() ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                 continue;
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        $this->has_seen_context_node = 'done';
+                       return $this->next_token();
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->current_element = array_shift( $this->element_queue );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -537,7 +539,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! isset( $this->current_element ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        return $this->next_token();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 if ( 'done' === $this->has_seen_context_node ) {
+                               return false;
+                       } else {
+                               return $this->next_token();
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( isset( $this->context_node ) && WP_HTML_Stack_Event::POP === $this->current_element->operation && $this->context_node === $this->current_element->token ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -782,16 +788,48 @@
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @since 6.4.0
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @todo make aware of queue of elements, because stack operations have already been done by now.
-        *
</del><span class="cx" style="display: block; padding: 0 10px">          * @return string[]|null Array of tag names representing path to matched node, if matched, otherwise NULL.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function get_breadcrumbs() {
</span><span class="cx" style="display: block; padding: 0 10px">                $breadcrumbs = array();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                 foreach ( $this->state->stack_of_open_elements->walk_down() as $stack_item ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $breadcrumbs[] = $stack_item->node_name;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                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;
+               }
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 return $breadcrumbs;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -821,7 +859,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @return int Nesting-depth of current location in the document.
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function get_current_depth() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return $this->state->stack_of_open_elements->count();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return $this->is_virtual()
+                       ? count( $this->get_breadcrumbs() )
+                       : $this->state->stack_of_open_elements->count();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        /**
</span></span></pre>
</div>
</div>

</body>
</html>