Skip to content

Commit 47eef00

Browse files
authored
Merge pull request #1919 from WordPress/update/od-initialization-timing
Fire actions before and after Optimization Detective processes a document
2 parents ab0b99a + a01d760 commit 47eef00

File tree

16 files changed

+268
-31
lines changed

16 files changed

+268
-31
lines changed

plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ private function get_common_lcp_element_external_background_image( OD_URL_Metric
143143
private function maybe_preload_external_lcp_background_image( OD_Tag_Visitor_Context $context ): void {
144144
// Gather the tuples of URL Metric group and the common LCP element external background image.
145145
// Note the groups of URL Metrics do not change across invocations, we just need to compute this once for all.
146+
// TODO: Instead of populating this here, it could be done once per invocation during the od_start_template_optimization action since the page's OD_URL_Metric_Group_Collection is available there.
146147
if ( ! is_array( $this->group_common_lcp_element_external_background_images ) ) {
147148
$this->group_common_lcp_element_external_background_images = array();
148149
foreach ( $context->url_metric_group_collection as $group ) {

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

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -702,29 +702,33 @@ public function is_admin_bar(): bool {
702702
}
703703

704704
/**
705-
* Append HTML to the HEAD.
705+
* Appends raw HTML to the HEAD.
706706
*
707-
* The provided HTML must be valid! No validation is performed.
707+
* The provided HTML must be valid for insertion in the HEAD. No validation is currently performed. However, in the
708+
* future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid
709+
* HTML is provided, this method may emit a `_doing_it_wrong()` warning.
708710
*
709711
* @since 0.4.0
710712
*
711-
* @param string $html HTML to inject.
713+
* @param string $raw_html Raw HTML to inject.
712714
*/
713-
public function append_head_html( string $html ): void {
714-
$this->buffered_text_replacements[ self::END_OF_HEAD_BOOKMARK ][] = $html;
715+
public function append_head_html( string $raw_html ): void {
716+
$this->buffered_text_replacements[ self::END_OF_HEAD_BOOKMARK ][] = $raw_html;
715717
}
716718

717719
/**
718-
* Append HTML to the BODY.
720+
* Appends raw HTML to the BODY.
719721
*
720-
* The provided HTML must be valid! No validation is performed.
722+
* The provided HTML must be valid for insertion in the BODY. No validation is currently performed. However, in the
723+
* future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid
724+
* HTML is provided, this method may emit a `_doing_it_wrong()` warning.
721725
*
722726
* @since 0.4.0
723727
*
724-
* @param string $html HTML to inject.
728+
* @param string $raw_html Raw HTML to inject.
725729
*/
726-
public function append_body_html( string $html ): void {
727-
$this->buffered_text_replacements[ self::END_OF_BODY_BOOKMARK ][] = $html;
730+
public function append_body_html( string $raw_html ): void {
731+
$this->buffered_text_replacements[ self::END_OF_BODY_BOOKMARK ][] = $raw_html;
728732
}
729733

730734
/**

plugins/optimization-detective/class-od-tag-visitor-context.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function track_tag(): void {
110110
* @throws Error When property is unknown.
111111
*/
112112
public function __get( string $name ) {
113-
// Note that there is intentionally not a case for 'visited_tag_state'.
113+
// Note: There is intentionally not a 'visited_tag_state' case to expose $this->visited_tag_state.
114114
switch ( $name ) {
115115
case 'processor':
116116
return $this->processor;
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
<?php
2+
/**
3+
* Optimization Detective: OD_Template_Optimization_Context class
4+
*
5+
* @package optimization-detective
6+
* @since n.e.x.t
7+
*/
8+
9+
// @codeCoverageIgnoreStart
10+
if ( ! defined( 'ABSPATH' ) ) {
11+
exit; // Exit if accessed directly.
12+
}
13+
// @codeCoverageIgnoreEnd
14+
15+
/**
16+
* Context for optimizing a template.
17+
*
18+
* @since n.e.x.t
19+
*
20+
* @property-read OD_URL_Metric_Group_Collection $url_metric_group_collection URL Metric group collection.
21+
* @property-read positive-int|null $url_metrics_id ID for the od_url_metrics post which provided the URL Metrics in the collection.
22+
* @property-read array<string, mixed> $normalized_query_vars Normalized query vars.
23+
* @property-read non-empty-string $url_metrics_slug Slug for the od_url_metrics post.
24+
* @property-read OD_Link_Collection $link_collection Link collection.
25+
*/
26+
final class OD_Template_Optimization_Context {
27+
28+
/**
29+
* URL Metric group collection.
30+
*
31+
* @since n.e.x.t
32+
* @var OD_URL_Metric_Group_Collection
33+
*/
34+
private $url_metric_group_collection;
35+
36+
/**
37+
* ID for the od_url_metrics post which provided the URL Metrics in the collection.
38+
*
39+
* May be null if no post has been created yet.
40+
*
41+
* @since n.e.x.t
42+
* @var positive-int|null
43+
*/
44+
private $url_metrics_id;
45+
46+
/**
47+
* Normalized query vars.
48+
*
49+
* @since n.e.x.t
50+
* @var array<string, mixed>
51+
*/
52+
private $normalized_query_vars;
53+
54+
/**
55+
* Slug for the od_url_metrics post.
56+
*
57+
* @since n.e.x.t
58+
* @var non-empty-string
59+
*/
60+
private $url_metrics_slug;
61+
62+
/**
63+
* Link collection.
64+
*
65+
* @since n.e.x.t
66+
* @var OD_Link_Collection
67+
*/
68+
private $link_collection;
69+
70+
/**
71+
* Constructor.
72+
*
73+
* @since n.e.x.t
74+
* @access private
75+
*
76+
* @param OD_URL_Metric_Group_Collection $url_metric_group_collection URL Metric group collection.
77+
* @param OD_Link_Collection $link_collection Link collection.
78+
* @param array<string, mixed> $normalized_query_vars Normalized query vars.
79+
* @param non-empty-string $url_metrics_slug Slug for the od_url_metrics post.
80+
* @param positive-int|null $url_metrics_id ID for the od_url_metrics post which provided the URL Metrics in the collection. May be null if no post has been created yet.
81+
*/
82+
public function __construct( OD_URL_Metric_Group_Collection $url_metric_group_collection, OD_Link_Collection $link_collection, array $normalized_query_vars, string $url_metrics_slug, ?int $url_metrics_id ) {
83+
$this->url_metric_group_collection = $url_metric_group_collection;
84+
$this->link_collection = $link_collection;
85+
$this->normalized_query_vars = $normalized_query_vars;
86+
$this->url_metrics_slug = $url_metrics_slug;
87+
$this->url_metrics_id = $url_metrics_id;
88+
}
89+
90+
/**
91+
* Gets a property.
92+
*
93+
* @since n.e.x.t
94+
*
95+
* @param string $name Property name.
96+
* @return mixed Property value.
97+
*
98+
* @throws Error When property is unknown.
99+
*/
100+
public function __get( string $name ) {
101+
// Note: There is intentionally not a 'processor' case to expose $this->processor.
102+
switch ( $name ) {
103+
case 'url_metrics_id':
104+
return $this->url_metrics_id;
105+
case 'url_metric_group_collection':
106+
return $this->url_metric_group_collection;
107+
case 'normalized_query_vars':
108+
return $this->normalized_query_vars;
109+
case 'url_metrics_slug':
110+
return $this->url_metrics_slug;
111+
case 'link_collection':
112+
return $this->link_collection;
113+
default:
114+
throw new Error(
115+
esc_html(
116+
sprintf(
117+
/* translators: %s is class member variable name */
118+
__( 'Unknown property %s.', 'optimization-detective' ),
119+
__CLASS__ . '::$' . $name
120+
)
121+
)
122+
);
123+
}
124+
}
125+
}

plugins/optimization-detective/load.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class_alias( OD_URL_Metric_Group_Collection::class, 'OD_URL_Metrics_Group_Collec
124124
require_once __DIR__ . '/detection.php';
125125

126126
// Optimization logic.
127+
require_once __DIR__ . '/class-od-template-optimization-context.php';
127128
require_once __DIR__ . '/class-od-link-collection.php';
128129
require_once __DIR__ . '/class-od-tag-visitor-registry.php';
129130
require_once __DIR__ . '/class-od-visited-tag-state.php';

plugins/optimization-detective/optimization.php

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,16 @@ function od_optimize_template_output_buffer( string $buffer ): string {
245245
return $buffer;
246246
}
247247

248-
$slug = od_get_url_metrics_slug( od_get_normalized_query_vars() );
249-
$post = OD_URL_Metrics_Post_Type::get_post( $slug );
248+
$query_vars = od_get_normalized_query_vars();
249+
$slug = od_get_url_metrics_slug( $query_vars );
250+
$post = OD_URL_Metrics_Post_Type::get_post( $slug );
251+
252+
/**
253+
* Post ID.
254+
*
255+
* @var positive-int|null $post_id
256+
*/
257+
$post_id = $post instanceof WP_Post ? $post->ID : null;
250258

251259
$tag_visitor_registry = new OD_Tag_Visitor_Registry();
252260

@@ -259,22 +267,40 @@ function od_optimize_template_output_buffer( string $buffer ): string {
259267
*/
260268
do_action( 'od_register_tag_visitors', $tag_visitor_registry );
261269

262-
$current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, od_get_current_theme_template() );
263-
$group_collection = new OD_URL_Metric_Group_Collection(
270+
$current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, od_get_current_theme_template() );
271+
$group_collection = new OD_URL_Metric_Group_Collection(
264272
$post instanceof WP_Post ? OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ) : array(),
265273
$current_etag,
266274
od_get_breakpoint_max_widths(),
267275
od_get_url_metrics_breakpoint_sample_size(),
268276
od_get_url_metric_freshness_ttl()
269277
);
270-
$link_collection = new OD_Link_Collection();
278+
$link_collection = new OD_Link_Collection();
279+
280+
$template_optimization_context = new OD_Template_Optimization_Context(
281+
$group_collection,
282+
$link_collection,
283+
$query_vars,
284+
$slug,
285+
$post_id
286+
);
287+
288+
/**
289+
* Fires before Optimization Detective starts optimizing the template.
290+
*
291+
* @since n.e.x.t
292+
*
293+
* @param OD_Template_Optimization_Context $template_optimization_context Template optimization context.
294+
*/
295+
do_action( 'od_start_template_optimization', $template_optimization_context );
296+
271297
$visited_tag_state = new OD_Visited_Tag_State();
272298
$tag_visitor_context = new OD_Tag_Visitor_Context(
273299
$processor,
274300
$group_collection,
275301
$link_collection,
276302
$visited_tag_state,
277-
$post instanceof WP_Post && $post->ID > 0 ? $post->ID : null
303+
$post_id
278304
);
279305
$current_tag_bookmark = 'optimization_detective_current_tag';
280306
$visitors = iterator_to_array( $tag_visitor_registry );
@@ -322,7 +348,23 @@ function od_optimize_template_output_buffer( string $buffer ): string {
322348
$visited_tag_state->reset();
323349
} while ( $processor->next_tag( array( 'tag_closers' => 'skip' ) ) );
324350

351+
// Inject detection script.
352+
// TODO: When optimizing above, if we find that there is a stored LCP element but it fails to match, it should perhaps set $needs_detection to true and send the request with an override nonce. However, this would require backtracking and adding the data-od-xpath attributes.
353+
if ( $needs_detection ) {
354+
$processor->append_body_html( od_get_detection_script( $slug, $group_collection ) );
355+
}
356+
357+
/**
358+
* Fires after Optimization Detective finishes optimizing the template.
359+
*
360+
* @since n.e.x.t
361+
*
362+
* @param OD_Template_Optimization_Context $template_optimization_context Template optimization context.
363+
*/
364+
do_action( 'od_finish_template_optimization', $template_optimization_context );
365+
325366
// Send any preload links in a Link response header and in a LINK tag injected at the end of the HEAD.
367+
// Additional links may have been added at the od_finish_template_optimization action, so this must come after.
326368
if ( count( $link_collection ) > 0 ) {
327369
$response_header_links = $link_collection->get_response_header();
328370
if ( ! is_null( $response_header_links ) && ! headers_sent() ) {
@@ -331,11 +373,5 @@ function od_optimize_template_output_buffer( string $buffer ): string {
331373
$processor->append_head_html( $link_collection->get_html() );
332374
}
333375

334-
// Inject detection script.
335-
// TODO: When optimizing above, if we find that there is a stored LCP element but it fails to match, it should perhaps set $needs_detection to true and send the request with an override nonce. However, this would require backtracking and adding the data-od-xpath attributes.
336-
if ( $needs_detection ) {
337-
$processor->append_body_html( od_get_detection_script( $slug, $group_collection ) );
338-
}
339-
340376
return $processor->get_updated_html();
341377
}

plugins/optimization-detective/tests/test-cases/admin-bar/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/many-images/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/noscript/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/preload-link/expected.html

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/video/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)