Skip to content

Commit 8c526e5

Browse files
Eliminate boolean arg to get_xpath in favor of new get_stored_xpath method
Add todos to remove transitional XPath logic Co-authored-by: felixarntz <[email protected]>
1 parent c259b59 commit 8c526e5

File tree

4 files changed

+53
-34
lines changed

4 files changed

+53
-34
lines changed

plugins/optimization-detective/class-od-element.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class OD_Element implements ArrayAccess, JsonSerializable {
3737
* Transitional XPath.
3838
*
3939
* @since n.e.x.t
40+
* @todo Remove logic related to transitional_xpath in a subsequent release once URL Metrics have been collected with the new format.
4041
* @var non-empty-string|null
4142
*/
4243
protected $transitional_xpath = null;
@@ -131,6 +132,7 @@ public function is_lcp_candidate(): bool {
131132
*
132133
* @since 0.7.0
133134
* @since n.e.x.t Returns the transitional XPath format. To access the underlying raw XPath, access the 'xpath' key of the jsonSerialize response.
135+
* @todo Remove logic related to transitional_xpath in a subsequent release once URL Metrics have been collected with the new format.
134136
*
135137
* @return non-empty-string XPath.
136138
*/

plugins/optimization-detective/class-od-html-tag-processor.php

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -186,26 +186,28 @@ final class OD_HTML_Tag_Processor extends WP_HTML_Tag_Processor {
186186
private $bookmarked_open_stacks = array();
187187

188188
/**
189-
* XPath for the current tag.
189+
* Stored XPath for the current tag.
190190
*
191-
* This is used so that repeated calls to {@see self::get_xpath()} won't needlessly reconstruct the string. This
192-
* gets cleared whenever {@see self::open_tags()} iterates to the next tag.
191+
* This is used so that repeated calls to {@see self::get_stored_xpath()} won't needlessly reconstruct the string.
192+
* This gets cleared whenever {@see self::open_tags()} iterates to the next tag.
193+
*
194+
* @todo Remove this once the XPath transitional period is over.
193195
*
194196
* @since 0.4.0
195197
* @var string|null
196198
*/
197-
private $current_xpath = null;
199+
private $current_stored_xpath = null;
198200

199201
/**
200-
* Transitional XPath for the current tag.
202+
* (Transitional) XPath for the current tag.
201203
*
202204
* This is used to store the old XPath format in a transitional period until which new URL Metrics are expected to
203205
* have been collected to purge out references to the old format.
204206
*
205207
* @since n.e.x.t
206208
* @var string|null
207209
*/
208-
private $transitional_current_xpath = null;
210+
private $current_xpath = null;
209211

210212
/**
211213
* Whether the previous tag does not expect a closer.
@@ -312,8 +314,8 @@ public function expects_closer( ?string $tag_name = null ): bool {
312314
* @return bool Whether a token was parsed.
313315
*/
314316
public function next_token(): bool {
315-
$this->current_xpath = null; // Clear cache.
316-
$this->transitional_current_xpath = null; // Clear cache.
317+
$this->current_stored_xpath = null; // Clear cache.
318+
$this->current_xpath = null; // Clear cache.
317319
++$this->cursor_move_count;
318320
if ( ! parent::next_token() ) {
319321
$this->open_stack_tags = array();
@@ -639,40 +641,55 @@ private function is_foreign_element(): bool {
639641
* index of the preceding node set. So it has to rather be written `.../*[1][self::DIV]/*[2][self::DIV]`.
640642
* Note that the first three levels lack any node index whereas the third level includes a disambiguating
641643
* attribute predicate (e.g. `/HTML/BODY/DIV[@id="page"]`) for the reasons explained in {@see self::XPATH_PATTERN}.
644+
* This predicate will be included once the transitional period is over.
642645
*
643646
* @since 0.4.0
647+
* @todo Replace the logic herein with what is in get_stored_xpath() once the transitional period is over.
644648
*
645-
* @param bool $transitional_format Whether to use the transitional XPath format. Default true.
646649
* @return string XPath.
647650
*/
648-
public function get_xpath( bool $transitional_format = true ): string {
651+
public function get_xpath(): string {
649652
/*
650653
* This transitional format is used by default for all extensions. The non-transitional format is used only in
651654
* od_optimize_template_output_buffer() when setting the data-od-xpath attribute. This is so that the new format
652655
* will replace the old format as new URL Metrics are collected. After a month of the new format being live, the
653656
* transitional format can be eliminated. See the corresponding logic in OD_Element for normalizing both the
654657
* old and new XPath formats to use the transitional format.
655658
*/
656-
if ( $transitional_format ) {
657-
if ( null === $this->transitional_current_xpath ) {
658-
$this->transitional_current_xpath = '';
659-
foreach ( $this->get_indexed_breadcrumbs() as $i => list( $tag_name, $index, $attributes ) ) {
660-
if ( $i < 2 || ( 2 === $i && '/HTML/BODY' === $this->transitional_current_xpath ) ) {
661-
$this->transitional_current_xpath .= "/$tag_name";
662-
} else {
663-
$this->transitional_current_xpath .= sprintf( '/*[%d][self::%s]', $index + 1, $tag_name );
664-
}
659+
if ( null === $this->current_xpath ) {
660+
$this->current_xpath = '';
661+
foreach ( $this->get_indexed_breadcrumbs() as $i => list( $tag_name, $index, $attributes ) ) {
662+
if ( $i < 2 || ( 2 === $i && '/HTML/BODY' === $this->current_xpath ) ) {
663+
$this->current_xpath .= "/$tag_name";
664+
} else {
665+
$this->current_xpath .= sprintf( '/*[%d][self::%s]', $index + 1, $tag_name );
665666
}
666667
}
667-
return $this->transitional_current_xpath;
668668
}
669+
return $this->current_xpath;
670+
}
669671

670-
if ( null === $this->current_xpath ) {
671-
$this->current_xpath = '';
672+
/**
673+
* Gets stored XPath for the current open tag.
674+
*
675+
* This method is temporary for a transition period while new URL Metrics are collected for active installs. Once
676+
* the transition period is over, the logic in this method can be moved to {@see self::get_xpath()} and this method
677+
* can simply be an alias for that one. See related logic in {@see OD_Element::get_xpath()}. This function is only
678+
* used internally by Optimization Detective in {@see od_optimize_template_output_buffer()}.
679+
*
680+
* @since n.e.x.t
681+
* @todo Move the logic in this method to the get_xpath() method and let this be an alias for that method once the transitional period is over.
682+
* @access private
683+
*
684+
* @return string XPath.
685+
*/
686+
public function get_stored_xpath(): string {
687+
if ( null === $this->current_stored_xpath ) {
688+
$this->current_stored_xpath = '';
672689
foreach ( $this->get_indexed_breadcrumbs() as $i => list( $tag_name, $index, $attributes ) ) {
673690
if ( $i < 2 ) {
674-
$this->current_xpath .= "/$tag_name";
675-
} elseif ( 2 === $i && '/HTML/BODY' === $this->current_xpath ) {
691+
$this->current_stored_xpath .= "/$tag_name";
692+
} elseif ( 2 === $i && '/HTML/BODY' === $this->current_stored_xpath ) {
676693
$segment = "/$tag_name";
677694
foreach ( $attributes as $attribute_name => $attribute_value ) {
678695
$segment .= sprintf(
@@ -681,13 +698,13 @@ public function get_xpath( bool $transitional_format = true ): string {
681698
$attribute_value // Note: $attribute_value has already been validated to only contain safe characters /^[a-zA-Z0-9_.\s:-]*/ which do not need escaping.
682699
);
683700
}
684-
$this->current_xpath .= $segment;
701+
$this->current_stored_xpath .= $segment;
685702
} else {
686-
$this->current_xpath .= sprintf( '/*[%d][self::%s]', $index + 1, $tag_name );
703+
$this->current_stored_xpath .= sprintf( '/*[%d][self::%s]', $index + 1, $tag_name );
687704
}
688705
}
689706
}
690-
return $this->current_xpath;
707+
return $this->current_stored_xpath;
691708
}
692709

693710
/**

plugins/optimization-detective/optimization.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ function od_optimize_template_output_buffer( string $buffer ): string {
249249
$processor->release_bookmark( $current_tag_bookmark );
250250

251251
if ( $tracked_in_url_metrics && $needs_detection ) {
252-
// Note: This is explicitly using the non-transitional XPath format since this is what will get saved in newly-submitted URL Metrics.
253-
$xpath = $processor->get_xpath( false );
252+
// TODO: Replace get_stored_xpath with get_xpath once the transitional period is over.
253+
$xpath = $processor->get_stored_xpath();
254254
$processor->set_meta_attribute( 'xpath', $xpath );
255255
}
256256
} while ( $processor->next_open_tag() );

plugins/optimization-detective/tests/test-class-od-html-tag-processor.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -433,18 +433,18 @@ public function data_provider_sample_documents(): array {
433433
*/
434434
public function test_next_tag_and_get_xpath( string $document, array $open_tags, array $xpath_breadcrumbs ): void {
435435
$p = new OD_HTML_Tag_Processor( $document );
436-
$this->assertSame( '', $p->get_xpath( false ), 'Expected empty XPath since iteration has not started.' );
436+
$this->assertSame( '', $p->get_stored_xpath(), 'Expected empty XPath since iteration has not started.' );
437437
$actual_open_tags = array();
438438
$actual_xpath_breadcrumbs_mapping = array();
439439
while ( $p->next_open_tag() ) {
440440
$actual_open_tags[] = $p->get_tag();
441441

442-
$xpath = $p->get_xpath( false );
442+
$xpath = $p->get_stored_xpath();
443443
$this->assertArrayNotHasKey( $xpath, $actual_xpath_breadcrumbs_mapping, 'Each tag must have a unique XPath.' );
444444

445445
$actual_xpath_breadcrumbs_mapping[ $xpath ] = $p->get_breadcrumbs();
446446

447-
$transitional_xpath = $p->get_xpath( true );
447+
$transitional_xpath = $p->get_xpath();
448448
$this->assertRegExp(
449449
'#^/HTML(
450450
/HEAD(/\*\[\d+]\[self::\w+])?
@@ -625,7 +625,7 @@ public function test_bookmarking_and_seeking(): void {
625625
$bookmarks[] = $bookmark;
626626
$actual_figure_contents[] = array(
627627
'tag' => $processor->get_tag(),
628-
'xpath' => $processor->get_xpath( false ),
628+
'xpath' => $processor->get_stored_xpath(),
629629
'depth' => $processor->get_current_depth(),
630630
);
631631
}
@@ -666,7 +666,7 @@ public function test_bookmarking_and_seeking(): void {
666666
$processor->seek( $bookmark );
667667
$sought_actual_contents[] = array(
668668
'tag' => $processor->get_tag(),
669-
'xpath' => $processor->get_xpath( false ),
669+
'xpath' => $processor->get_stored_xpath(),
670670
'depth' => $processor->get_current_depth(),
671671
);
672672
}

0 commit comments

Comments
 (0)