Skip to content

Commit 4a79036

Browse files
authored
Merge pull request #1872 from WordPress/try/allow-next-tag-query
Update `OD_HTML_Tag_Processor::next_tag()` to allow `$query` arg and prepare to skip visiting tag closers by default
2 parents 381c6e1 + 2f97645 commit 4a79036

File tree

8 files changed

+221
-66
lines changed

8 files changed

+221
-66
lines changed

plugins/embed-optimizer/hooks.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ function embed_optimizer_update_markup( WP_HTML_Tag_Processor $html_processor, b
187187
$trigger_error = static function ( string $message ) use ( $function_name ): void {
188188
wp_trigger_error( $function_name, esc_html( $message ) );
189189
};
190+
191+
// As of 1.0.0-beta3, next_tag() allows $query and is beginning to migrate to skip tag closers by default.
192+
// In versions prior to this, the method always visited closers and passing a $query actually threw an exception.
193+
$tag_query = version_compare( OPTIMIZATION_DETECTIVE_VERSION, '1.0.0-beta3', '>=' )
194+
? array( 'tag_closers' => 'visit' ) : null;
190195
try {
191196
/*
192197
* Determine how to lazy load the embed.
@@ -253,7 +258,7 @@ function embed_optimizer_update_markup( WP_HTML_Tag_Processor $html_processor, b
253258
}
254259
}
255260
}
256-
} while ( $html_processor->next_tag() );
261+
} while ( $html_processor->next_tag( $tag_query ) );
257262
// If there was only one non-inline script, make it lazy.
258263
if ( 1 === $script_count && ! $has_inline_script && $html_processor->has_bookmark( $bookmark_names['script'] ) ) {
259264
$needs_lazy_script = true;

plugins/image-prioritizer/class-image-prioritizer-img-tag-visitor.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ private function process_picture( OD_HTML_Tag_Processor $processor, OD_Tag_Visit
226226
$crossorigin = null;
227227

228228
// Loop through child tags until we reach the closing PICTURE tag.
229-
while ( $processor->next_tag() ) {
229+
// As of 1.0.0-beta3, next_tag() allows $query and is beginning to migrate to skip tag closers by default.
230+
// In versions prior to this, the method always visited closers and passing a $query actually threw an exception.
231+
$tag_query = version_compare( OPTIMIZATION_DETECTIVE_VERSION, '1.0.0-beta3', '>=' )
232+
? array( 'tag_closers' => 'visit' ) : null;
233+
while ( $processor->next_tag( $tag_query ) ) {
230234
$tag = $processor->get_tag();
231235

232236
// If we reached the closing PICTURE tag, break.

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

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -246,43 +246,40 @@ final class OD_HTML_Tag_Processor extends WP_HTML_Tag_Processor {
246246
/**
247247
* Finds the next tag.
248248
*
249-
* Unlike the base class, this subclass disallows querying. This is to ensure the breadcrumbs can be tracked.
250-
* It will _always_ visit tag closers.
249+
* Unlike the base class, this subclass currently visits tag closers by default.
250+
* However, for the 1.0.0 release this method will behave the same as the method in
251+
* the base class, where it skips tag closers by default.
251252
*
252253
* @inheritDoc
253254
* @since 0.4.0
255+
* @since n.e.x.t Passing a $query is now allowed. In the 1.0.0 release, this will default to skipping tag closers.
254256
*
255-
* @param array{tag_name?: string|null, match_offset?: int|null, class_name?: string|null, tag_closers?: string|null}|null $query Query, but only null is accepted for this subclass.
257+
* @param array{tag_name?: string|null, match_offset?: int|null, class_name?: string|null, tag_closers?: string|null}|null $query Query.
256258
* @return bool Whether a tag was matched.
257-
*
258-
* @throws InvalidArgumentException If attempting to pass a query.
259259
*/
260260
public function next_tag( $query = null ): bool {
261-
if ( null !== $query ) {
262-
throw new InvalidArgumentException( esc_html__( 'Processor subclass does not support queries.', 'optimization-detective' ) );
261+
if ( null === $query ) {
262+
$query = array( 'tag_closers' => 'visit' );
263+
$this->warn(
264+
__METHOD__,
265+
esc_html__( 'Previously this method always visited tag closers and did not allow a query to be supplied. Now, however, a query can be supplied. To align this method with the behavior of the base class, a future version of this method will default to skipping tag closers.', 'optimization-detective' )
266+
);
263267
}
264-
265-
// Elements in the Admin Bar are not relevant for optimization, so this loop ensures that no tags in the Admin Bar are visited.
266-
do {
267-
$matched = parent::next_tag( array( 'tag_closers' => 'visit' ) );
268-
} while ( $matched && $this->is_admin_bar() );
269-
return $matched;
268+
return parent::next_tag( $query );
270269
}
271270

272271
/**
273272
* Finds the next open tag.
274273
*
274+
* This method will soon be equivalent to calling {@see self::next_tag()} without passing any `$query`.
275+
*
275276
* @since 0.4.0
277+
* @deprecated n.e.x.t Use {@see self::next_tag()} instead.
276278
*
277279
* @return bool Whether a tag was matched.
278280
*/
279281
public function next_open_tag(): bool {
280-
while ( $this->next_tag() ) {
281-
if ( ! $this->is_tag_closer() ) {
282-
return true;
283-
}
284-
}
285-
return false;
282+
return $this->next_tag( array( 'tag_closers' => 'skip' ) );
286283
}
287284

288285
/**
@@ -719,11 +716,16 @@ public function get_stored_xpath(): string {
719716
/**
720717
* Returns whether the processor is currently at or inside the admin bar.
721718
*
719+
* This is only intended to be used internally by Optimization Detective as part of the "optimization loop". Tag
720+
* visitors should not rely on this method as it may be deprecated in the future, especially with a migration to
721+
* WP_HTML_Processor after {@link https://core.trac.wordpress.org/ticket/63020} is implemented.
722+
*
722723
* @since 1.0.0
724+
* @access private
723725
*
724726
* @return bool Whether at or inside the admin bar.
725727
*/
726-
private function is_admin_bar(): bool {
728+
public function is_admin_bar(): bool {
727729
return (
728730
isset( $this->open_stack_tags[2], $this->open_stack_attributes[2]['id'] )
729731
&&

plugins/optimization-detective/load.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Description: Provides a framework for leveraging real user metrics to detect optimizations for improving page performance.
66
* Requires at least: 6.6
77
* Requires PHP: 7.2
8-
* Version: 1.0.0-beta2
8+
* Version: 1.0.0-beta3
99
* Author: WordPress Performance Team
1010
* Author URI: https://make.wordpress.org/performance/
1111
* License: GPLv2 or later
@@ -71,7 +71,7 @@ static function ( string $global_var_name, string $version, Closure $load ): voi
7171
}
7272
)(
7373
'optimization_detective_pending_plugin',
74-
'1.0.0-beta2',
74+
'1.0.0-beta3',
7575
static function ( string $version ): void {
7676
if ( defined( 'OPTIMIZATION_DETECTIVE_VERSION' ) ) {
7777
return;

plugins/optimization-detective/optimization.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ function od_optimize_template_output_buffer( string $buffer ): string {
238238
// If the initial tag is not an open HTML tag, then abort since the buffer is not a complete HTML document.
239239
$processor = new OD_HTML_Tag_Processor( $buffer );
240240
if ( ! (
241-
$processor->next_tag() &&
241+
$processor->next_tag( array( 'tag_closers' => 'visit' ) ) &&
242242
! $processor->is_tag_closer() &&
243243
'HTML' === $processor->get_tag()
244244
) ) {
@@ -284,7 +284,12 @@ function od_optimize_template_output_buffer( string $buffer ): string {
284284

285285
do {
286286
// Never process anything inside NOSCRIPT since it will never show up in the DOM when scripting is enabled, and thus it can never be detected nor measured.
287-
if ( in_array( 'NOSCRIPT', $processor->get_breadcrumbs(), true ) ) {
287+
// Similarly, elements in the Admin Bar are not relevant for optimization, so this loop ensures that no tags in the Admin Bar are visited.
288+
if (
289+
in_array( 'NOSCRIPT', $processor->get_breadcrumbs(), true )
290+
||
291+
$processor->is_admin_bar()
292+
) {
288293
continue;
289294
}
290295

@@ -317,7 +322,7 @@ function od_optimize_template_output_buffer( string $buffer ): string {
317322
}
318323

319324
$visited_tag_state->reset();
320-
} while ( $processor->next_open_tag() );
325+
} while ( $processor->next_tag( array( 'tag_closers' => 'skip' ) ) );
321326

322327
// Send any preload links in a Link response header and in a LINK tag injected at the end of the HEAD.
323328
if ( count( $link_collection ) > 0 ) {

plugins/optimization-detective/tests/test-cases/admin-bar/set-up.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ static function ( OD_Tag_Visitor_Registry $registry ) use ( $test_case ): void {
66
$registry->register(
77
'everything',
88
static function ( OD_Tag_Visitor_Context $context ) use ( $test_case ): void {
9-
$test_case->assertNotEquals( 'wpadminbar', $context->processor->get_attribute( 'id' ) );
9+
$test_case->assertStringNotContainsString( 'wpadminbar', $context->processor->get_xpath() );
10+
$test_case->assertNotEquals( 'wpadminbar', $context->processor->get_attribute( 'id' ), $context->processor->get_xpath() );
1011
$test_case->assertNull( $context->url_metrics_id, 'Expected url_metrics_id to be null since no od_url_metrics_post exists for this URL.' );
1112
}
1213
);

0 commit comments

Comments
 (0)