From abdefc07b07b405674c6a1e17f6a9ce07baad573 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 11 Mar 2025 17:42:17 -0700 Subject: [PATCH 01/14] Move OD initialization to wp action instead of output buffer callback --- .../optimization-detective/optimization.php | 73 +++++++++++-------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index e9240c05df..686de5e5d1 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -78,6 +78,8 @@ static function ( string $output, ?int $phase ): string { * * @since 0.1.0 * @access private + * + * @global WP_Query $wp_the_query WP_Query object. */ function od_maybe_add_template_output_buffer_filter(): void { $conditions = array( @@ -112,7 +114,41 @@ static function () use ( $reasons ): void { return; } - $callback = 'od_optimize_template_output_buffer'; + $slug = od_get_url_metrics_slug( od_get_normalized_query_vars() ); + $post = OD_URL_Metrics_Post_Type::get_post( $slug ); + $post_id = $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null; + + $tag_visitor_registry = new OD_Tag_Visitor_Registry(); + + /** + * Fires to register tag visitors before walking over the document to perform optimizations. + * + * @since 0.3.0 + * + * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. + */ + do_action( 'od_register_tag_visitors', $tag_visitor_registry ); + + global $wp_the_query; + $current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, od_get_current_theme_template() ); // TODO: Make sure the template is set!! + $group_collection = new OD_URL_Metric_Group_Collection( + $post instanceof WP_Post ? OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ) : array(), + $current_etag, + od_get_breakpoint_max_widths(), + od_get_url_metrics_breakpoint_sample_size(), + od_get_url_metric_freshness_ttl() + ); + + $callback = static function ( string $buffer ) use ( $tag_visitor_registry, $group_collection, $slug, $post_id ): string { + return od_optimize_template_output_buffer( + $buffer, + $tag_visitor_registry, + $group_collection, + $slug, + $post_id + ); + }; + if ( function_exists( 'perflab_wrap_server_timing' ) && @@ -219,13 +255,14 @@ function od_is_response_html_content_type(): bool { * @since 0.1.0 * @access private * - * @global WP_Query $wp_the_query WP_Query object. - * - * @param string $buffer Template output buffer. + * @param string $buffer Template output buffer. + * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. + * @param OD_URL_Metric_Group_Collection $group_collection URL Metric group collection. + * @param non-empty-string $slug Slug. + * @param positive-int|null $post_id The ID for the od_url_metric post if it exists. * @return string Filtered template output buffer. */ -function od_optimize_template_output_buffer( string $buffer ): string { - global $wp_the_query; +function od_optimize_template_output_buffer( string $buffer, OD_Tag_Visitor_Registry $tag_visitor_registry, OD_URL_Metric_Group_Collection $group_collection, string $slug, ?int $post_id ): string { // If the content-type is not HTML or the output does not start with '<', then abort since the buffer is definitely not HTML. if ( @@ -245,28 +282,6 @@ function od_optimize_template_output_buffer( string $buffer ): string { return $buffer; } - $slug = od_get_url_metrics_slug( od_get_normalized_query_vars() ); - $post = OD_URL_Metrics_Post_Type::get_post( $slug ); - - $tag_visitor_registry = new OD_Tag_Visitor_Registry(); - - /** - * Fires to register tag visitors before walking over the document to perform optimizations. - * - * @since 0.3.0 - * - * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. - */ - do_action( 'od_register_tag_visitors', $tag_visitor_registry ); - - $current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, od_get_current_theme_template() ); - $group_collection = new OD_URL_Metric_Group_Collection( - $post instanceof WP_Post ? OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ) : array(), - $current_etag, - od_get_breakpoint_max_widths(), - od_get_url_metrics_breakpoint_sample_size(), - od_get_url_metric_freshness_ttl() - ); $link_collection = new OD_Link_Collection(); $visited_tag_state = new OD_Visited_Tag_State(); $tag_visitor_context = new OD_Tag_Visitor_Context( @@ -274,7 +289,7 @@ function od_optimize_template_output_buffer( string $buffer ): string { $group_collection, $link_collection, $visited_tag_state, - $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null + $post_id ); $current_tag_bookmark = 'optimization_detective_current_tag'; $visitors = iterator_to_array( $tag_visitor_registry ); From 64d63da822d6ad8b7ca6af03bc394e3e9cb7cb85 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 11 Mar 2025 17:43:06 -0700 Subject: [PATCH 02/14] Add od_start_template_optimization action --- plugins/optimization-detective/optimization.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index 686de5e5d1..f59d705c50 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -139,6 +139,18 @@ static function () use ( $reasons ): void { od_get_url_metric_freshness_ttl() ); + /** + * Fires when the current OD_URL_Metric_Group_Collection has been constructed for the response. + * + * @since n.e.x.t + * @todo The parameters should be put into a context object as is done with other such actions. + * + * @param OD_URL_Metric_Group_Collection $group_collection URL Metric group collection. + * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. + * @param WP_Post|null $post The od_url_metrics post if it exists. + */ + do_action( 'od_start_template_optimization', $group_collection, $tag_visitor_registry, $post ); + $callback = static function ( string $buffer ) use ( $tag_visitor_registry, $group_collection, $slug, $post_id ): string { return od_optimize_template_output_buffer( $buffer, From 3b0f696d035b4fe657d5be06ab4c263b06712903 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 12 Mar 2025 11:15:16 -0700 Subject: [PATCH 03/14] Initiaize OD objects at template_include filter --- .../optimization-detective/optimization.php | 36 ++++++++++++++++--- .../optimization-detective/storage/data.php | 8 ++--- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index f59d705c50..6935d9c93f 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -78,8 +78,6 @@ static function ( string $output, ?int $phase ): string { * * @since 0.1.0 * @access private - * - * @global WP_Query $wp_the_query WP_Query object. */ function od_maybe_add_template_output_buffer_filter(): void { $conditions = array( @@ -114,6 +112,31 @@ static function () use ( $reasons ): void { return; } + /* + * The template_include filter with a max priority is used in order to obtain the $template without having to + * rely on the $template global. Additionally, there is no hook which fires after the `template_include` filter + * before the template starts rendering. Therefore, this is the last opportunity we have to initialize key + * Optimization Detective objects while at the same time it is the first opportunity to do so since before here + * the $template will not be known. + * + * Note that output buffering also starts at this same point in another filter, although if output buffering is + * added to core, then it would be started either before the `template_redirect` action or after the + * `template_include` filters have completely applied. + */ + add_filter( 'template_include', 'od_add_template_output_buffer_filter', PHP_INT_MAX ); +} + +/** + * Adds filter to optimize the template output buffer. + * + * @since n.e.x.t + * + * @global WP_Query $wp_the_query WP_Query object. + * + * @param non-empty-string|mixed $template Template. + * @return non-empty-string|mixed Passed-through template. + */ +function od_add_template_output_buffer_filter( $template ) { $slug = od_get_url_metrics_slug( od_get_normalized_query_vars() ); $post = OD_URL_Metrics_Post_Type::get_post( $slug ); $post_id = $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null; @@ -130,8 +153,9 @@ static function () use ( $reasons ): void { do_action( 'od_register_tag_visitors', $tag_visitor_registry ); global $wp_the_query; - $current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, od_get_current_theme_template() ); // TODO: Make sure the template is set!! - $group_collection = new OD_URL_Metric_Group_Collection( + $current_theme_template = od_get_current_theme_template( is_string( $template ) ? $template : null ); + $current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, $current_theme_template ); + $group_collection = new OD_URL_Metric_Group_Collection( $post instanceof WP_Post ? OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ) : array(), $current_etag, od_get_breakpoint_max_widths(), @@ -140,7 +164,7 @@ static function () use ( $reasons ): void { ); /** - * Fires when the current OD_URL_Metric_Group_Collection has been constructed for the response. + * Fires when Optimization Detective is initialized to optimize the current response. * * @since n.e.x.t * @todo The parameters should be put into a context object as is done with other such actions. @@ -171,6 +195,8 @@ function_exists( 'perflab_server_timing_use_output_buffer' ) $callback = perflab_wrap_server_timing( $callback, 'optimization-detective', 'exist' ); } add_filter( 'od_template_output_buffer', $callback ); + + return $template; } /** diff --git a/plugins/optimization-detective/storage/data.php b/plugins/optimization-detective/storage/data.php index fb67b6ae91..6297bc2f0e 100644 --- a/plugins/optimization-detective/storage/data.php +++ b/plugins/optimization-detective/storage/data.php @@ -144,12 +144,12 @@ function od_get_url_metrics_slug( array $query_vars ): string { * @access private * * @global string|null $_wp_current_template_id Current template ID. - * @global string|null $template Template file path. * + * @param string|null $template Template. * @return string|WP_Block_Template|null Template. */ -function od_get_current_theme_template() { - global $template, $_wp_current_template_id; +function od_get_current_theme_template( ?string $template ) { + global $_wp_current_template_id; // TODO: Ideally we would not rely on a global here. if ( wp_is_block_theme() && isset( $_wp_current_template_id ) ) { $block_template = get_block_template( $_wp_current_template_id, 'wp_template' ); @@ -157,7 +157,7 @@ function od_get_current_theme_template() { return $block_template; } } - if ( isset( $template ) && is_string( $template ) ) { + if ( isset( $template ) ) { return basename( $template ); } return null; From f7da494939047503e0552626a0ed532e463eaa9d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 12 Mar 2025 16:39:24 -0700 Subject: [PATCH 04/14] Introduce OD_Template_Optimization_Context --- ...class-od-template-optimization-context.php | 136 ++++++++++++++++++ plugins/optimization-detective/load.php | 1 + .../optimization-detective/optimization.php | 24 ++-- .../optimization-detective/storage/data.php | 2 +- 4 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 plugins/optimization-detective/class-od-template-optimization-context.php diff --git a/plugins/optimization-detective/class-od-template-optimization-context.php b/plugins/optimization-detective/class-od-template-optimization-context.php new file mode 100644 index 0000000000..9d040d93a4 --- /dev/null +++ b/plugins/optimization-detective/class-od-template-optimization-context.php @@ -0,0 +1,136 @@ + $normalized_query_vars Normalized query vars. + * @property-read non-empty-string $url_metrics_slug Slug for the od_url_metrics post. + * @property-read non-empty-string $current_etag Current ETag. + */ +final class OD_Template_Optimization_Context { + + /** + * URL Metric group collection. + * + * @since n.e.x.t + * @var OD_URL_Metric_Group_Collection + */ + private $url_metric_group_collection; + + /** + * Tag visitor registry. + * + * @since n.e.x.t + * @var OD_Tag_Visitor_Registry + */ + private $tag_visitor_registry; + + /** + * 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. + * + * @since n.e.x.t + * @var positive-int|null + */ + private $url_metrics_id; + + /** + * Normalized query vars. + * + * @since n.e.x.t + * @var array + */ + private $normalized_query_vars; + + /** + * Slug for the od_url_metrics post. + * + * @since n.e.x.t + * @var non-empty-string + */ + private $url_metrics_slug; + + /** + * Current ETag. + * + * @since n.e.x.t + * @var non-empty-string + */ + private $current_etag; + + /** + * Constructor. + * + * @since n.e.x.t + * + * @param OD_URL_Metric_Group_Collection $url_metric_group_collection URL Metric group collection. + * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. + * @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. + * @param array $normalized_query_vars Normalized query vars. + * @param non-empty-string $url_metrics_slug Slug for the od_url_metrics post. + * @param non-empty-string $current_etag Current ETag. + */ + public function __construct( OD_URL_Metric_Group_Collection $url_metric_group_collection, OD_Tag_Visitor_Registry $tag_visitor_registry, ?int $url_metrics_id, array $normalized_query_vars, string $url_metrics_slug, string $current_etag ) { + $this->url_metric_group_collection = $url_metric_group_collection; + $this->tag_visitor_registry = $tag_visitor_registry; + $this->url_metrics_id = $url_metrics_id; + $this->normalized_query_vars = $normalized_query_vars; + $this->url_metrics_slug = $url_metrics_slug; + $this->current_etag = $current_etag; + } + + /** + * Gets a property. + * + * @since n.e.x.t + * + * @param string $name Property name. + * @return mixed Property value. + * + * @throws Error When property is unknown. + */ + public function __get( string $name ) { + switch ( $name ) { + case 'tag_visitor_registry': + return $this->tag_visitor_registry; + case 'url_metrics_id': + return $this->url_metrics_id; + case 'url_metric_group_collection': + return $this->url_metric_group_collection; + case 'normalized_query_vars': + return $this->normalized_query_vars; + case 'url_metrics_slug': + return $this->url_metrics_slug; + case 'current_etag': + return $this->current_etag; + default: + throw new Error( + esc_html( + sprintf( + /* translators: %s is class member variable name */ + __( 'Unknown property %s.', 'optimization-detective' ), + __CLASS__ . '::$' . $name + ) + ) + ); + } + } +} diff --git a/plugins/optimization-detective/load.php b/plugins/optimization-detective/load.php index 8c9faa1c17..191dfe99df 100644 --- a/plugins/optimization-detective/load.php +++ b/plugins/optimization-detective/load.php @@ -121,6 +121,7 @@ class_alias( OD_URL_Metric_Group_Collection::class, 'OD_URL_Metrics_Group_Collec require_once __DIR__ . '/detection.php'; // Optimization logic. + require_once __DIR__ . '/class-od-template-optimization-context.php'; require_once __DIR__ . '/class-od-link-collection.php'; require_once __DIR__ . '/class-od-tag-visitor-registry.php'; require_once __DIR__ . '/class-od-visited-tag-state.php'; diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index 6935d9c93f..de40152a38 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -137,9 +137,10 @@ static function () use ( $reasons ): void { * @return non-empty-string|mixed Passed-through template. */ function od_add_template_output_buffer_filter( $template ) { - $slug = od_get_url_metrics_slug( od_get_normalized_query_vars() ); - $post = OD_URL_Metrics_Post_Type::get_post( $slug ); - $post_id = $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null; + $query_vars = od_get_normalized_query_vars(); + $slug = od_get_url_metrics_slug( $query_vars ); + $post = OD_URL_Metrics_Post_Type::get_post( $slug ); + $post_id = $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null; $tag_visitor_registry = new OD_Tag_Visitor_Registry(); @@ -167,13 +168,20 @@ function od_add_template_output_buffer_filter( $template ) { * Fires when Optimization Detective is initialized to optimize the current response. * * @since n.e.x.t - * @todo The parameters should be put into a context object as is done with other such actions. * - * @param OD_URL_Metric_Group_Collection $group_collection URL Metric group collection. - * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. - * @param WP_Post|null $post The od_url_metrics post if it exists. + * @param OD_Template_Optimization_Context $context Template optimization context. */ - do_action( 'od_start_template_optimization', $group_collection, $tag_visitor_registry, $post ); + do_action( + 'od_start_template_optimization', + new OD_Template_Optimization_Context( + $group_collection, + $tag_visitor_registry, + $post_id, + $query_vars, + $slug, + $current_etag + ) + ); $callback = static function ( string $buffer ) use ( $tag_visitor_registry, $group_collection, $slug, $post_id ): string { return od_optimize_template_output_buffer( diff --git a/plugins/optimization-detective/storage/data.php b/plugins/optimization-detective/storage/data.php index 6297bc2f0e..58c6c1b10c 100644 --- a/plugins/optimization-detective/storage/data.php +++ b/plugins/optimization-detective/storage/data.php @@ -158,7 +158,7 @@ function od_get_current_theme_template( ?string $template ) { } } if ( isset( $template ) ) { - return basename( $template ); + return basename( $template ); // TODO: Why basename here? } return null; } From 51feaad38010ae0113adeb0a782c0b4ed4328c66 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 12 Mar 2025 16:46:10 -0700 Subject: [PATCH 05/14] Add link collection to context --- .../class-od-template-optimization-context.php | 15 ++++++++++++++- plugins/optimization-detective/optimization.php | 11 +++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/plugins/optimization-detective/class-od-template-optimization-context.php b/plugins/optimization-detective/class-od-template-optimization-context.php index 9d040d93a4..e08c83a556 100644 --- a/plugins/optimization-detective/class-od-template-optimization-context.php +++ b/plugins/optimization-detective/class-od-template-optimization-context.php @@ -23,6 +23,7 @@ * @property-read array $normalized_query_vars Normalized query vars. * @property-read non-empty-string $url_metrics_slug Slug for the od_url_metrics post. * @property-read non-empty-string $current_etag Current ETag. + * @property-read OD_Link_Collection $link_collection Link collection. */ final class OD_Template_Optimization_Context { @@ -76,6 +77,14 @@ final class OD_Template_Optimization_Context { */ private $current_etag; + /** + * Link collection. + * + * @since n.e.x.t + * @var OD_Link_Collection + */ + private $link_collection; + /** * Constructor. * @@ -87,14 +96,16 @@ final class OD_Template_Optimization_Context { * @param array $normalized_query_vars Normalized query vars. * @param non-empty-string $url_metrics_slug Slug for the od_url_metrics post. * @param non-empty-string $current_etag Current ETag. + * @param OD_Link_Collection $link_collection Link collection. */ - public function __construct( OD_URL_Metric_Group_Collection $url_metric_group_collection, OD_Tag_Visitor_Registry $tag_visitor_registry, ?int $url_metrics_id, array $normalized_query_vars, string $url_metrics_slug, string $current_etag ) { + public function __construct( OD_URL_Metric_Group_Collection $url_metric_group_collection, OD_Tag_Visitor_Registry $tag_visitor_registry, ?int $url_metrics_id, array $normalized_query_vars, string $url_metrics_slug, string $current_etag, OD_Link_Collection $link_collection ) { $this->url_metric_group_collection = $url_metric_group_collection; $this->tag_visitor_registry = $tag_visitor_registry; $this->url_metrics_id = $url_metrics_id; $this->normalized_query_vars = $normalized_query_vars; $this->url_metrics_slug = $url_metrics_slug; $this->current_etag = $current_etag; + $this->link_collection = $link_collection; } /** @@ -121,6 +132,8 @@ public function __get( string $name ) { return $this->url_metrics_slug; case 'current_etag': return $this->current_etag; + case 'link_collection': + return $this->link_collection; default: throw new Error( esc_html( diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index de40152a38..a6ad3558ed 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -163,6 +163,7 @@ function od_add_template_output_buffer_filter( $template ) { od_get_url_metrics_breakpoint_sample_size(), od_get_url_metric_freshness_ttl() ); + $link_collection = new OD_Link_Collection(); /** * Fires when Optimization Detective is initialized to optimize the current response. @@ -179,15 +180,17 @@ function od_add_template_output_buffer_filter( $template ) { $post_id, $query_vars, $slug, - $current_etag + $current_etag, + $link_collection ) ); - $callback = static function ( string $buffer ) use ( $tag_visitor_registry, $group_collection, $slug, $post_id ): string { + $callback = static function ( string $buffer ) use ( $tag_visitor_registry, $group_collection, $link_collection, $slug, $post_id ): string { return od_optimize_template_output_buffer( $buffer, $tag_visitor_registry, $group_collection, + $link_collection, $slug, $post_id ); @@ -304,11 +307,12 @@ function od_is_response_html_content_type(): bool { * @param string $buffer Template output buffer. * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. * @param OD_URL_Metric_Group_Collection $group_collection URL Metric group collection. + * @param OD_Link_Collection $link_collection Link collection. * @param non-empty-string $slug Slug. * @param positive-int|null $post_id The ID for the od_url_metric post if it exists. * @return string Filtered template output buffer. */ -function od_optimize_template_output_buffer( string $buffer, OD_Tag_Visitor_Registry $tag_visitor_registry, OD_URL_Metric_Group_Collection $group_collection, string $slug, ?int $post_id ): string { +function od_optimize_template_output_buffer( string $buffer, OD_Tag_Visitor_Registry $tag_visitor_registry, OD_URL_Metric_Group_Collection $group_collection, OD_Link_Collection $link_collection, string $slug, ?int $post_id ): string { // If the content-type is not HTML or the output does not start with '<', then abort since the buffer is definitely not HTML. if ( @@ -328,7 +332,6 @@ function od_optimize_template_output_buffer( string $buffer, OD_Tag_Visitor_Regi return $buffer; } - $link_collection = new OD_Link_Collection(); $visited_tag_state = new OD_Visited_Tag_State(); $tag_visitor_context = new OD_Tag_Visitor_Context( $processor, From 0ad7f79121849e0c8e0c9afa898ddd8c0e9625f9 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 12 Mar 2025 16:50:56 -0700 Subject: [PATCH 06/14] Reuse template optimization context in od_optimize_template_output_buffer() --- .../optimization-detective/optimization.php | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index a6ad3558ed..36f15c59dc 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -165,6 +165,16 @@ function od_add_template_output_buffer_filter( $template ) { ); $link_collection = new OD_Link_Collection(); + $context = new OD_Template_Optimization_Context( + $group_collection, + $tag_visitor_registry, + $post_id, + $query_vars, + $slug, + $current_etag, + $link_collection + ); + /** * Fires when Optimization Detective is initialized to optimize the current response. * @@ -172,28 +182,10 @@ function od_add_template_output_buffer_filter( $template ) { * * @param OD_Template_Optimization_Context $context Template optimization context. */ - do_action( - 'od_start_template_optimization', - new OD_Template_Optimization_Context( - $group_collection, - $tag_visitor_registry, - $post_id, - $query_vars, - $slug, - $current_etag, - $link_collection - ) - ); + do_action( 'od_start_template_optimization', $context ); - $callback = static function ( string $buffer ) use ( $tag_visitor_registry, $group_collection, $link_collection, $slug, $post_id ): string { - return od_optimize_template_output_buffer( - $buffer, - $tag_visitor_registry, - $group_collection, - $link_collection, - $slug, - $post_id - ); + $callback = static function ( string $buffer ) use ( $context ): string { + return od_optimize_template_output_buffer( $buffer, $context ); }; if ( @@ -304,15 +296,11 @@ function od_is_response_html_content_type(): bool { * @since 0.1.0 * @access private * - * @param string $buffer Template output buffer. - * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. - * @param OD_URL_Metric_Group_Collection $group_collection URL Metric group collection. - * @param OD_Link_Collection $link_collection Link collection. - * @param non-empty-string $slug Slug. - * @param positive-int|null $post_id The ID for the od_url_metric post if it exists. + * @param string $buffer Template output buffer. + * @param OD_Template_Optimization_Context $context Template optimization context. * @return string Filtered template output buffer. */ -function od_optimize_template_output_buffer( string $buffer, OD_Tag_Visitor_Registry $tag_visitor_registry, OD_URL_Metric_Group_Collection $group_collection, OD_Link_Collection $link_collection, string $slug, ?int $post_id ): string { +function od_optimize_template_output_buffer( string $buffer, OD_Template_Optimization_Context $context ): string { // If the content-type is not HTML or the output does not start with '<', then abort since the buffer is definitely not HTML. if ( @@ -322,6 +310,12 @@ function od_optimize_template_output_buffer( string $buffer, OD_Tag_Visitor_Regi return $buffer; } + $link_collection = $context->link_collection; + $post_id = $context->url_metrics_id; + $group_collection = $context->url_metric_group_collection; + $slug = $context->url_metrics_slug; + $tag_visitor_registry = $context->tag_visitor_registry; + // If the initial tag is not an open HTML tag, then abort since the buffer is not a complete HTML document. $processor = new OD_HTML_Tag_Processor( $buffer ); if ( ! ( From 8bcfc13c88131515de70e6618f9daf074f93e698 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 12 Mar 2025 17:24:46 -0700 Subject: [PATCH 07/14] Finalize the tag registry after the od_register_tag_visitors action has fired --- .../class-od-tag-visitor-registry.php | 47 ++++++++++++++++++- .../optimization-detective/optimization.php | 8 +++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/plugins/optimization-detective/class-od-tag-visitor-registry.php b/plugins/optimization-detective/class-od-tag-visitor-registry.php index 01b10712ae..02814672f9 100644 --- a/plugins/optimization-detective/class-od-tag-visitor-registry.php +++ b/plugins/optimization-detective/class-od-tag-visitor-registry.php @@ -32,18 +32,43 @@ final class OD_Tag_Visitor_Registry implements Countable, IteratorAggregate { */ private $visitors = array(); + /** + * Whether finalized. + * + * @since n.e.x.t + * @var bool + */ + private $is_finalized = false; + + /** + * Finalizes the registry to prevent further modifications. + * + * @since n.e.x.t + * @access private + */ + public function finalize(): void { + $this->is_finalized = true; + } + /** * Registers a tag visitor. * * @since 0.3.0 + * @since n.e.x.t Returns boolean for whether registration is successful. Returns false if registry is finalized. * * @phpstan-param TagVisitorCallback $tag_visitor_callback * * @param non-empty-string $id Identifier for the tag visitor. * @param callable $tag_visitor_callback Tag visitor callback. + * @return bool Whether a tag visitor was registered. */ - public function register( string $id, callable $tag_visitor_callback ): void { + public function register( string $id, callable $tag_visitor_callback ): bool { + if ( $this->is_finalized ) { + _doing_it_wrong( __METHOD__, esc_html( $this->get_finalized_message() ), 'optimization-detective 1.0.0' ); + return false; + } $this->visitors[ $id ] = $tag_visitor_callback; + return true; } /** @@ -77,11 +102,16 @@ public function get_registered( string $id ): ?callable { * Unregisters a tag visitor. * * @since 0.3.0 + * @since n.e.x.t Returns false if the registry is finalized. * * @param non-empty-string $id Identifier for the tag visitor. * @return bool Whether a tag visitor was unregistered. */ public function unregister( string $id ): bool { + if ( $this->is_finalized ) { + _doing_it_wrong( __METHOD__, esc_html( $this->get_finalized_message() ), 'optimization-detective 1.0.0' ); + return false; + } if ( ! $this->is_registered( $id ) ) { return false; } @@ -110,4 +140,19 @@ public function getIterator(): ArrayIterator { public function count(): int { return count( $this->visitors ); } + + /** + * Gets the finalized message when attempting to mutate the registry after the od_register_tag_visitors action. + * + * @since n.e.x.t + * + * @return string Message. + */ + private function get_finalized_message(): string { + return sprintf( + /* translators: %s is the od_register_tag_visitors action */ + __( 'The tag visitor registry has already been finalized. This method must be called during the %s action.', 'optimization-detective' ), + 'od_register_tag_visitors' + ); + } } diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index 36f15c59dc..abefdac6aa 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -153,17 +153,21 @@ function od_add_template_output_buffer_filter( $template ) { */ do_action( 'od_register_tag_visitors', $tag_visitor_registry ); + // Prevent modification of the tag visitor registry since doing so would invalidate the etag. + $tag_visitor_registry->finalize(); + global $wp_the_query; $current_theme_template = od_get_current_theme_template( is_string( $template ) ? $template : null ); $current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, $current_theme_template ); $group_collection = new OD_URL_Metric_Group_Collection( $post instanceof WP_Post ? OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ) : array(), $current_etag, + // TODO: Add the following values to the context as well. od_get_breakpoint_max_widths(), od_get_url_metrics_breakpoint_sample_size(), od_get_url_metric_freshness_ttl() - ); - $link_collection = new OD_Link_Collection(); + ); // TODO: Also finalize the collection? + $link_collection = new OD_Link_Collection(); $context = new OD_Template_Optimization_Context( $group_collection, From a57391d7138bf29505f7ad75a0bc41210d79d219 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 12 Mar 2025 17:26:57 -0700 Subject: [PATCH 08/14] Add TODO in Image_Prioritizer_Background_Image_Styled_Tag_Visitor --- ...ass-image-prioritizer-background-image-styled-tag-visitor.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php b/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php index bd455f1974..12dfb8f9f9 100644 --- a/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php +++ b/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php @@ -143,6 +143,7 @@ private function get_common_lcp_element_external_background_image( OD_URL_Metric private function maybe_preload_external_lcp_background_image( OD_Tag_Visitor_Context $context ): void { // Gather the tuples of URL Metric group and the common LCP element external background image. // Note the groups of URL Metrics do not change across invocations, we just need to compute this once for all. + // 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. if ( ! is_array( $this->group_common_lcp_element_external_background_images ) ) { $this->group_common_lcp_element_external_background_images = array(); foreach ( $context->url_metric_group_collection as $group ) { From 6abee9cb3372ad223c9c2951ee11f2b207683a0d Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 13 Mar 2025 12:31:51 -0700 Subject: [PATCH 09/14] Go back to initializing in footer but add action before/after optimization loop --- .../class-od-tag-visitor-registry.php | 47 +----- ...class-od-template-optimization-context.php | 68 +++++--- .../optimization-detective/optimization.php | 150 +++++++----------- .../optimization-detective/storage/data.php | 10 +- 4 files changed, 107 insertions(+), 168 deletions(-) diff --git a/plugins/optimization-detective/class-od-tag-visitor-registry.php b/plugins/optimization-detective/class-od-tag-visitor-registry.php index 02814672f9..01b10712ae 100644 --- a/plugins/optimization-detective/class-od-tag-visitor-registry.php +++ b/plugins/optimization-detective/class-od-tag-visitor-registry.php @@ -32,43 +32,18 @@ final class OD_Tag_Visitor_Registry implements Countable, IteratorAggregate { */ private $visitors = array(); - /** - * Whether finalized. - * - * @since n.e.x.t - * @var bool - */ - private $is_finalized = false; - - /** - * Finalizes the registry to prevent further modifications. - * - * @since n.e.x.t - * @access private - */ - public function finalize(): void { - $this->is_finalized = true; - } - /** * Registers a tag visitor. * * @since 0.3.0 - * @since n.e.x.t Returns boolean for whether registration is successful. Returns false if registry is finalized. * * @phpstan-param TagVisitorCallback $tag_visitor_callback * * @param non-empty-string $id Identifier for the tag visitor. * @param callable $tag_visitor_callback Tag visitor callback. - * @return bool Whether a tag visitor was registered. */ - public function register( string $id, callable $tag_visitor_callback ): bool { - if ( $this->is_finalized ) { - _doing_it_wrong( __METHOD__, esc_html( $this->get_finalized_message() ), 'optimization-detective 1.0.0' ); - return false; - } + public function register( string $id, callable $tag_visitor_callback ): void { $this->visitors[ $id ] = $tag_visitor_callback; - return true; } /** @@ -102,16 +77,11 @@ public function get_registered( string $id ): ?callable { * Unregisters a tag visitor. * * @since 0.3.0 - * @since n.e.x.t Returns false if the registry is finalized. * * @param non-empty-string $id Identifier for the tag visitor. * @return bool Whether a tag visitor was unregistered. */ public function unregister( string $id ): bool { - if ( $this->is_finalized ) { - _doing_it_wrong( __METHOD__, esc_html( $this->get_finalized_message() ), 'optimization-detective 1.0.0' ); - return false; - } if ( ! $this->is_registered( $id ) ) { return false; } @@ -140,19 +110,4 @@ public function getIterator(): ArrayIterator { public function count(): int { return count( $this->visitors ); } - - /** - * Gets the finalized message when attempting to mutate the registry after the od_register_tag_visitors action. - * - * @since n.e.x.t - * - * @return string Message. - */ - private function get_finalized_message(): string { - return sprintf( - /* translators: %s is the od_register_tag_visitors action */ - __( 'The tag visitor registry has already been finalized. This method must be called during the %s action.', 'optimization-detective' ), - 'od_register_tag_visitors' - ); - } } diff --git a/plugins/optimization-detective/class-od-template-optimization-context.php b/plugins/optimization-detective/class-od-template-optimization-context.php index e08c83a556..ec8d698576 100644 --- a/plugins/optimization-detective/class-od-template-optimization-context.php +++ b/plugins/optimization-detective/class-od-template-optimization-context.php @@ -13,7 +13,7 @@ // @codeCoverageIgnoreEnd /** - * Context for optimizing a template prior to rendering. + * Context for optimizing a template. * * @since n.e.x.t * @@ -22,7 +22,6 @@ * @property-read positive-int|null $url_metrics_id ID for the od_url_metrics post which provided the URL Metrics in the collection. * @property-read array $normalized_query_vars Normalized query vars. * @property-read non-empty-string $url_metrics_slug Slug for the od_url_metrics post. - * @property-read non-empty-string $current_etag Current ETag. * @property-read OD_Link_Collection $link_collection Link collection. */ final class OD_Template_Optimization_Context { @@ -36,12 +35,16 @@ final class OD_Template_Optimization_Context { private $url_metric_group_collection; /** - * Tag visitor registry. + * HTML Tag Processor. + * + * This object is not directly exposed with an accessor property. This class exposes {@see self::append_head_html()} + * and {@see self::append_body_html()} methods which wrap calls to the underlying + * {@see OD_HTML_Tag_Processor::append_head_html()} and {@see OD_HTML_Tag_Processor::append_body_html()}.s * * @since n.e.x.t - * @var OD_Tag_Visitor_Registry + * @var OD_HTML_Tag_Processor */ - private $tag_visitor_registry; + private $processor; /** * ID for the od_url_metrics post which provided the URL Metrics in the collection. @@ -69,14 +72,6 @@ final class OD_Template_Optimization_Context { */ private $url_metrics_slug; - /** - * Current ETag. - * - * @since n.e.x.t - * @var non-empty-string - */ - private $current_etag; - /** * Link collection. * @@ -90,22 +85,46 @@ final class OD_Template_Optimization_Context { * * @since n.e.x.t * + * @param OD_HTML_Tag_Processor $processor HTML Tag Processor. * @param OD_URL_Metric_Group_Collection $url_metric_group_collection URL Metric group collection. - * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. - * @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. + * @param OD_Link_Collection $link_collection Link collection. * @param array $normalized_query_vars Normalized query vars. * @param non-empty-string $url_metrics_slug Slug for the od_url_metrics post. - * @param non-empty-string $current_etag Current ETag. - * @param OD_Link_Collection $link_collection Link collection. + * @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. */ - public function __construct( OD_URL_Metric_Group_Collection $url_metric_group_collection, OD_Tag_Visitor_Registry $tag_visitor_registry, ?int $url_metrics_id, array $normalized_query_vars, string $url_metrics_slug, string $current_etag, OD_Link_Collection $link_collection ) { + public function __construct( OD_HTML_Tag_Processor $processor, 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 ) { + $this->processor = $processor; $this->url_metric_group_collection = $url_metric_group_collection; - $this->tag_visitor_registry = $tag_visitor_registry; - $this->url_metrics_id = $url_metrics_id; + $this->link_collection = $link_collection; $this->normalized_query_vars = $normalized_query_vars; $this->url_metrics_slug = $url_metrics_slug; - $this->current_etag = $current_etag; - $this->link_collection = $link_collection; + $this->url_metrics_id = $url_metrics_id; + } + + /** + * Append HTML to the HEAD. + * + * The provided HTML must be valid! No validation is performed. + * + * @since n.e.x.t + * + * @param non-empty-string $html HTML to inject. + */ + public function append_head_html( string $html ): void { + $this->processor->append_head_html( $html ); + } + + /** + * Append HTML to the BODY. + * + * The provided HTML must be valid! No validation is performed. + * + * @since n.e.x.t + * + * @param non-empty-string $html HTML to inject. + */ + public function append_body_html( string $html ): void { + $this->processor->append_body_html( $html ); } /** @@ -119,9 +138,8 @@ public function __construct( OD_URL_Metric_Group_Collection $url_metric_group_co * @throws Error When property is unknown. */ public function __get( string $name ) { + // Note: The $processor is intentionally not exposed. switch ( $name ) { - case 'tag_visitor_registry': - return $this->tag_visitor_registry; case 'url_metrics_id': return $this->url_metrics_id; case 'url_metric_group_collection': @@ -130,8 +148,6 @@ public function __get( string $name ) { return $this->normalized_query_vars; case 'url_metrics_slug': return $this->url_metrics_slug; - case 'current_etag': - return $this->current_etag; case 'link_collection': return $this->link_collection; default: diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index abefdac6aa..57f19c57f9 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -112,86 +112,7 @@ static function () use ( $reasons ): void { return; } - /* - * The template_include filter with a max priority is used in order to obtain the $template without having to - * rely on the $template global. Additionally, there is no hook which fires after the `template_include` filter - * before the template starts rendering. Therefore, this is the last opportunity we have to initialize key - * Optimization Detective objects while at the same time it is the first opportunity to do so since before here - * the $template will not be known. - * - * Note that output buffering also starts at this same point in another filter, although if output buffering is - * added to core, then it would be started either before the `template_redirect` action or after the - * `template_include` filters have completely applied. - */ - add_filter( 'template_include', 'od_add_template_output_buffer_filter', PHP_INT_MAX ); -} - -/** - * Adds filter to optimize the template output buffer. - * - * @since n.e.x.t - * - * @global WP_Query $wp_the_query WP_Query object. - * - * @param non-empty-string|mixed $template Template. - * @return non-empty-string|mixed Passed-through template. - */ -function od_add_template_output_buffer_filter( $template ) { - $query_vars = od_get_normalized_query_vars(); - $slug = od_get_url_metrics_slug( $query_vars ); - $post = OD_URL_Metrics_Post_Type::get_post( $slug ); - $post_id = $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null; - - $tag_visitor_registry = new OD_Tag_Visitor_Registry(); - - /** - * Fires to register tag visitors before walking over the document to perform optimizations. - * - * @since 0.3.0 - * - * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. - */ - do_action( 'od_register_tag_visitors', $tag_visitor_registry ); - - // Prevent modification of the tag visitor registry since doing so would invalidate the etag. - $tag_visitor_registry->finalize(); - - global $wp_the_query; - $current_theme_template = od_get_current_theme_template( is_string( $template ) ? $template : null ); - $current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, $current_theme_template ); - $group_collection = new OD_URL_Metric_Group_Collection( - $post instanceof WP_Post ? OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ) : array(), - $current_etag, - // TODO: Add the following values to the context as well. - od_get_breakpoint_max_widths(), - od_get_url_metrics_breakpoint_sample_size(), - od_get_url_metric_freshness_ttl() - ); // TODO: Also finalize the collection? - $link_collection = new OD_Link_Collection(); - - $context = new OD_Template_Optimization_Context( - $group_collection, - $tag_visitor_registry, - $post_id, - $query_vars, - $slug, - $current_etag, - $link_collection - ); - - /** - * Fires when Optimization Detective is initialized to optimize the current response. - * - * @since n.e.x.t - * - * @param OD_Template_Optimization_Context $context Template optimization context. - */ - do_action( 'od_start_template_optimization', $context ); - - $callback = static function ( string $buffer ) use ( $context ): string { - return od_optimize_template_output_buffer( $buffer, $context ); - }; - + $callback = 'od_optimize_template_output_buffer'; if ( function_exists( 'perflab_wrap_server_timing' ) && @@ -202,8 +123,6 @@ function_exists( 'perflab_server_timing_use_output_buffer' ) $callback = perflab_wrap_server_timing( $callback, 'optimization-detective', 'exist' ); } add_filter( 'od_template_output_buffer', $callback ); - - return $template; } /** @@ -300,11 +219,13 @@ function od_is_response_html_content_type(): bool { * @since 0.1.0 * @access private * - * @param string $buffer Template output buffer. - * @param OD_Template_Optimization_Context $context Template optimization context. + * @global WP_Query $wp_the_query WP_Query object. + * + * @param string $buffer Template output buffer. * @return string Filtered template output buffer. */ -function od_optimize_template_output_buffer( string $buffer, OD_Template_Optimization_Context $context ): string { +function od_optimize_template_output_buffer( string $buffer ): string { + global $wp_the_query; // If the content-type is not HTML or the output does not start with '<', then abort since the buffer is definitely not HTML. if ( @@ -314,12 +235,6 @@ function od_optimize_template_output_buffer( string $buffer, OD_Template_Optimiz return $buffer; } - $link_collection = $context->link_collection; - $post_id = $context->url_metrics_id; - $group_collection = $context->url_metric_group_collection; - $slug = $context->url_metrics_slug; - $tag_visitor_registry = $context->tag_visitor_registry; - // If the initial tag is not an open HTML tag, then abort since the buffer is not a complete HTML document. $processor = new OD_HTML_Tag_Processor( $buffer ); if ( ! ( @@ -330,6 +245,50 @@ function od_optimize_template_output_buffer( string $buffer, OD_Template_Optimiz return $buffer; } + $query_vars = od_get_normalized_query_vars(); + $slug = od_get_url_metrics_slug( $query_vars ); + $post = OD_URL_Metrics_Post_Type::get_post( $slug ); + $post_id = $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null; + + $tag_visitor_registry = new OD_Tag_Visitor_Registry(); + + /** + * Fires to register tag visitors before walking over the document to perform optimizations. + * + * @since 0.3.0 + * + * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. + */ + do_action( 'od_register_tag_visitors', $tag_visitor_registry ); + + $current_etag = od_get_current_url_metrics_etag( $tag_visitor_registry, $wp_the_query, od_get_current_theme_template() ); + $group_collection = new OD_URL_Metric_Group_Collection( + $post instanceof WP_Post ? OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ) : array(), + $current_etag, + od_get_breakpoint_max_widths(), + od_get_url_metrics_breakpoint_sample_size(), + od_get_url_metric_freshness_ttl() + ); + $link_collection = new OD_Link_Collection(); + + $context = new OD_Template_Optimization_Context( + $processor, + $group_collection, + $link_collection, + $query_vars, + $slug, + $post_id + ); + + /** + * Fires before Optimization Detective starts optimizing the template. + * + * @since n.e.x.t + * + * @param OD_Template_Optimization_Context $context Template optimization context. + */ + do_action( 'od_start_template_optimization', $context ); + $visited_tag_state = new OD_Visited_Tag_State(); $tag_visitor_context = new OD_Tag_Visitor_Context( $processor, @@ -399,5 +358,14 @@ function od_optimize_template_output_buffer( string $buffer, OD_Template_Optimiz $processor->append_body_html( od_get_detection_script( $slug, $group_collection ) ); } + /** + * Fires after Optimization Detective finishes optimizing the template. + * + * @since n.e.x.t + * + * @param OD_Template_Optimization_Context $context Template optimization context. + */ + do_action( 'od_finish_template_optimization', $context ); + return $processor->get_updated_html(); } diff --git a/plugins/optimization-detective/storage/data.php b/plugins/optimization-detective/storage/data.php index 58c6c1b10c..fb67b6ae91 100644 --- a/plugins/optimization-detective/storage/data.php +++ b/plugins/optimization-detective/storage/data.php @@ -144,12 +144,12 @@ function od_get_url_metrics_slug( array $query_vars ): string { * @access private * * @global string|null $_wp_current_template_id Current template ID. + * @global string|null $template Template file path. * - * @param string|null $template Template. * @return string|WP_Block_Template|null Template. */ -function od_get_current_theme_template( ?string $template ) { - global $_wp_current_template_id; // TODO: Ideally we would not rely on a global here. +function od_get_current_theme_template() { + global $template, $_wp_current_template_id; if ( wp_is_block_theme() && isset( $_wp_current_template_id ) ) { $block_template = get_block_template( $_wp_current_template_id, 'wp_template' ); @@ -157,8 +157,8 @@ function od_get_current_theme_template( ?string $template ) { return $block_template; } } - if ( isset( $template ) ) { - return basename( $template ); // TODO: Why basename here? + if ( isset( $template ) && is_string( $template ) ) { + return basename( $template ); } return null; } From 09d7af77f20687e9c282d27146d8be891bd966c0 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 13 Mar 2025 14:49:31 -0700 Subject: [PATCH 10/14] Rename variable make it distinct from other context Co-authored-by: Felix Arntz --- plugins/optimization-detective/optimization.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index 57f19c57f9..4520aaa232 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -271,7 +271,7 @@ function od_optimize_template_output_buffer( string $buffer ): string { ); $link_collection = new OD_Link_Collection(); - $context = new OD_Template_Optimization_Context( + $template_optimization_context = new OD_Template_Optimization_Context( $processor, $group_collection, $link_collection, @@ -285,9 +285,9 @@ function od_optimize_template_output_buffer( string $buffer ): string { * * @since n.e.x.t * - * @param OD_Template_Optimization_Context $context Template optimization context. + * @param OD_Template_Optimization_Context $template_optimization_context Template optimization context. */ - do_action( 'od_start_template_optimization', $context ); + do_action( 'od_start_template_optimization', $template_optimization_context ); $visited_tag_state = new OD_Visited_Tag_State(); $tag_visitor_context = new OD_Tag_Visitor_Context( @@ -363,9 +363,9 @@ function od_optimize_template_output_buffer( string $buffer ): string { * * @since n.e.x.t * - * @param OD_Template_Optimization_Context $context Template optimization context. + * @param OD_Template_Optimization_Context $template_optimization_context Template optimization context. */ - do_action( 'od_finish_template_optimization', $context ); + do_action( 'od_finish_template_optimization', $template_optimization_context ); return $processor->get_updated_html(); } From 0d8cb6540aeafa1c3a60a0937c19f72e4bdd0dad Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 13 Mar 2025 16:09:23 -0700 Subject: [PATCH 11/14] Use phpdoc to declare that the post ID is a positive-int|null --- plugins/optimization-detective/optimization.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index 4520aaa232..49a548401b 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -248,7 +248,13 @@ function od_optimize_template_output_buffer( string $buffer ): string { $query_vars = od_get_normalized_query_vars(); $slug = od_get_url_metrics_slug( $query_vars ); $post = OD_URL_Metrics_Post_Type::get_post( $slug ); - $post_id = $post instanceof WP_Post && $post->ID > 0 ? $post->ID : null; + + /** + * Post ID. + * + * @var positive-int|null $post_id + */ + $post_id = $post instanceof WP_Post ? $post->ID : null; $tag_visitor_registry = new OD_Tag_Visitor_Registry(); From 38a4c6b61aef92a0a0f450df4486a9eed7cd92d7 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 13 Mar 2025 17:09:48 -0700 Subject: [PATCH 12/14] Add tests and fix bug with adding links at finish action --- ...class-od-template-optimization-context.php | 1 - .../optimization-detective/optimization.php | 19 +++--- .../tests/test-cases/admin-bar/expected.html | 5 +- .../complete-url-metrics/expected.html | 7 +- .../test-cases/many-images/expected.html | 5 +- .../test-cases/no-url-metrics/expected.html | 5 +- .../tests/test-cases/noscript/expected.html | 5 +- .../test-cases/preload-link/expected.html | 5 +- .../test-cases/tag-track-opt-in/expected.html | 5 +- .../tests/test-cases/video/expected.html | 5 +- .../test-cases/xhtml-response/expected.html | 5 +- .../tests/test-optimization.php | 66 +++++++++++++++++++ 12 files changed, 113 insertions(+), 20 deletions(-) diff --git a/plugins/optimization-detective/class-od-template-optimization-context.php b/plugins/optimization-detective/class-od-template-optimization-context.php index ec8d698576..0492540abe 100644 --- a/plugins/optimization-detective/class-od-template-optimization-context.php +++ b/plugins/optimization-detective/class-od-template-optimization-context.php @@ -18,7 +18,6 @@ * @since n.e.x.t * * @property-read OD_URL_Metric_Group_Collection $url_metric_group_collection URL Metric group collection. - * @property-read OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry. * @property-read positive-int|null $url_metrics_id ID for the od_url_metrics post which provided the URL Metrics in the collection. * @property-read array $normalized_query_vars Normalized query vars. * @property-read non-empty-string $url_metrics_slug Slug for the od_url_metrics post. diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index 49a548401b..2b4fd44488 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -349,15 +349,6 @@ function od_optimize_template_output_buffer( string $buffer ): string { $visited_tag_state->reset(); } while ( $processor->next_tag( array( 'tag_closers' => 'skip' ) ) ); - // Send any preload links in a Link response header and in a LINK tag injected at the end of the HEAD. - if ( count( $link_collection ) > 0 ) { - $response_header_links = $link_collection->get_response_header(); - if ( ! is_null( $response_header_links ) && ! headers_sent() ) { - header( $response_header_links, false ); - } - $processor->append_head_html( $link_collection->get_html() ); - } - // Inject detection script. // 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. if ( $needs_detection ) { @@ -373,5 +364,15 @@ function od_optimize_template_output_buffer( string $buffer ): string { */ do_action( 'od_finish_template_optimization', $template_optimization_context ); + // Send any preload links in a Link response header and in a LINK tag injected at the end of the HEAD. + // Additional links may have been added at the od_finish_template_optimization action, so this must come after. + if ( count( $link_collection ) > 0 ) { + $response_header_links = $link_collection->get_response_header(); + if ( ! is_null( $response_header_links ) && ! headers_sent() ) { + header( $response_header_links, false ); + } + $processor->append_head_html( $link_collection->get_html() ); + } + return $processor->get_updated_html(); } diff --git a/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html b/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html index 532d16658f..afd28d0a10 100644 --- a/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html +++ b/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html @@ -2,7 +2,9 @@ ... - + + +
+ diff --git a/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html b/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html index 9d17b1daaa..0ea589c24e 100644 --- a/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html +++ b/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html @@ -2,10 +2,13 @@ ... - + + +
Foo
- + + diff --git a/plugins/optimization-detective/tests/test-cases/many-images/expected.html b/plugins/optimization-detective/tests/test-cases/many-images/expected.html index 9e3201dfff..24b323405b 100644 --- a/plugins/optimization-detective/tests/test-cases/many-images/expected.html +++ b/plugins/optimization-detective/tests/test-cases/many-images/expected.html @@ -2,7 +2,9 @@ ... - + + +
Foo @@ -1007,5 +1009,6 @@ Foo
+ diff --git a/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html b/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html index 1a7bdccd47..e9a1f964fb 100644 --- a/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html +++ b/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html @@ -2,11 +2,14 @@ ... - + + +
Foo
+ diff --git a/plugins/optimization-detective/tests/test-cases/noscript/expected.html b/plugins/optimization-detective/tests/test-cases/noscript/expected.html index b2d736475d..c8f3fa7b7e 100644 --- a/plugins/optimization-detective/tests/test-cases/noscript/expected.html +++ b/plugins/optimization-detective/tests/test-cases/noscript/expected.html @@ -2,7 +2,9 @@ ... - + + +
+ diff --git a/plugins/optimization-detective/tests/test-cases/preload-link/expected.html b/plugins/optimization-detective/tests/test-cases/preload-link/expected.html index ba358c6ce6..60cf5800fd 100644 --- a/plugins/optimization-detective/tests/test-cases/preload-link/expected.html +++ b/plugins/optimization-detective/tests/test-cases/preload-link/expected.html @@ -2,12 +2,15 @@ ... - + + +
+ diff --git a/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html b/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html index 38e8f34613..3a163cb489 100644 --- a/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html +++ b/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html @@ -2,7 +2,9 @@ ... - + + +
@@ -11,5 +13,6 @@
+ diff --git a/plugins/optimization-detective/tests/test-cases/video/expected.html b/plugins/optimization-detective/tests/test-cases/video/expected.html index a6c2ac4a39..2cb39c8150 100644 --- a/plugins/optimization-detective/tests/test-cases/video/expected.html +++ b/plugins/optimization-detective/tests/test-cases/video/expected.html @@ -2,7 +2,9 @@ ... - + + +
+ diff --git a/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html b/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html index 19591e005f..ab8c6a4c24 100644 --- a/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html +++ b/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html @@ -4,11 +4,14 @@ XHTML 1.0 Strict Example - + + +

Foo

+ diff --git a/plugins/optimization-detective/tests/test-optimization.php b/plugins/optimization-detective/tests/test-optimization.php index 3347317866..26bf4cfca0 100644 --- a/plugins/optimization-detective/tests/test-optimization.php +++ b/plugins/optimization-detective/tests/test-optimization.php @@ -377,6 +377,10 @@ public function data_provider_test_od_optimize_template_output_buffer(): array { * @covers OD_Visited_Tag_State::is_tag_tracked * @covers OD_Visited_Tag_State::reset * @covers OD_HTML_Tag_Processor::is_admin_bar + * @covers OD_Template_Optimization_Context::__construct + * @covers OD_Template_Optimization_Context::__get + * @covers OD_Template_Optimization_Context::append_head_html + * @covers OD_Template_Optimization_Context::append_body_html * * @dataProvider data_provider_test_od_optimize_template_output_buffer * @@ -385,6 +389,18 @@ public function data_provider_test_od_optimize_template_output_buffer(): array { * @noinspection PhpDocMissingThrowsInspection */ public function test_od_optimize_template_output_buffer( string $directory ): void { + $this->assertSame( 0, did_action( 'od_register_tag_visitors' ) ); + $this->assertSame( 0, did_action( 'od_start_template_optimization' ) ); + $this->assertSame( 0, did_action( 'od_finish_template_optimization' ) ); + + $did_initialize = false; + add_action( + 'od_register_tag_visitors', + static function () use ( &$did_initialize ): void { + $did_initialize = true; + } + ); + add_action( 'od_register_tag_visitors', function ( OD_Tag_Visitor_Registry $tag_visitor_registry ): void { @@ -431,6 +447,56 @@ function ( OD_Tag_Visitor_Context $context ): void { } ); + $template_optimization_context = null; + add_action( + 'od_start_template_optimization', + function ( OD_Template_Optimization_Context $context ) use ( &$template_optimization_context ): void { + $this->assertInstanceOf( OD_URL_Metric_Group_Collection::class, $context->url_metric_group_collection ); + $this->assertTrue( is_int( $context->url_metrics_id ) || is_null( $context->url_metrics_id ) ); + $this->assertIsArray( $context->normalized_query_vars ); + $this->assertIsString( $context->url_metrics_slug ); + $this->assertSame( od_get_url_metrics_slug( $context->normalized_query_vars ), $context->url_metrics_slug ); + if ( is_int( $context->url_metrics_id ) ) { + $post = get_post( $context->url_metrics_id ); + $this->assertInstanceOf( WP_Post::class, $post ); + $this->assertSame( $post->post_name, $context->url_metrics_slug ); + } + $this->assertInstanceOf( OD_Link_Collection::class, $context->link_collection ); + + $error = null; + $value = ''; + try { + $value = $context->__get( 'invalid_param' ); + } catch ( Error $e ) { + $error = $e; + } + $this->assertInstanceOf( Error::class, $error ); + $this->assertSame( '', $value ); + + $context->append_head_html( "\n" ); + + $template_optimization_context = $context; + } + ); + + add_action( + 'od_finish_template_optimization', + function ( OD_Template_Optimization_Context $context ) use ( &$template_optimization_context ): void { + $this->assertSame( $template_optimization_context, $context ); + $context->link_collection->add_link( + array( + 'rel' => 'preconnect', + 'href' => 'https://inserted-at-finish-template-optimization-action.example.net/', + ) + ); + $context->append_body_html( "\n" ); + } + ); + $this->assert_snapshot_equals( $directory ); + + $this->assertSame( $did_initialize ? 1 : 0, did_action( 'od_register_tag_visitors' ) ); + $this->assertSame( $did_initialize ? 1 : 0, did_action( 'od_start_template_optimization' ) ); + $this->assertSame( $did_initialize ? 1 : 0, did_action( 'od_finish_template_optimization' ) ); } } From 5d12ef7dd06b2c486b97d409f80d7adb74913ae1 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 13 Mar 2025 17:30:44 -0700 Subject: [PATCH 13/14] Add docs for requirement for valid HTML passed into methods --- .../class-od-html-tag-processor.php | 24 +++++++++------- .../class-od-tag-visitor-context.php | 2 +- ...class-od-template-optimization-context.php | 28 +++++++++++-------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/plugins/optimization-detective/class-od-html-tag-processor.php b/plugins/optimization-detective/class-od-html-tag-processor.php index d96e4eea8a..bb775441f4 100644 --- a/plugins/optimization-detective/class-od-html-tag-processor.php +++ b/plugins/optimization-detective/class-od-html-tag-processor.php @@ -702,29 +702,33 @@ public function is_admin_bar(): bool { } /** - * Append HTML to the HEAD. + * Appends raw HTML to the HEAD. * - * The provided HTML must be valid! No validation is performed. + * The provided HTML must be valid for insertion in the HEAD. No validation is currently performed. However, in the + * future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid + * HTML is provided, this method may emit a `_doing_it_wrong()` warning. * * @since 0.4.0 * - * @param string $html HTML to inject. + * @param string $raw_html Raw HTML to inject. */ - public function append_head_html( string $html ): void { - $this->buffered_text_replacements[ self::END_OF_HEAD_BOOKMARK ][] = $html; + public function append_head_html( string $raw_html ): void { + $this->buffered_text_replacements[ self::END_OF_HEAD_BOOKMARK ][] = $raw_html; } /** - * Append HTML to the BODY. + * Appends raw HTML to the BODY. * - * The provided HTML must be valid! No validation is performed. + * The provided HTML must be valid for insertion in the BODY. No validation is currently performed. However, in the + * future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid + * HTML is provided, this method may emit a `_doing_it_wrong()` warning. * * @since 0.4.0 * - * @param string $html HTML to inject. + * @param string $raw_html Raw HTML to inject. */ - public function append_body_html( string $html ): void { - $this->buffered_text_replacements[ self::END_OF_BODY_BOOKMARK ][] = $html; + public function append_body_html( string $raw_html ): void { + $this->buffered_text_replacements[ self::END_OF_BODY_BOOKMARK ][] = $raw_html; } /** diff --git a/plugins/optimization-detective/class-od-tag-visitor-context.php b/plugins/optimization-detective/class-od-tag-visitor-context.php index fae07d74c2..920ed35442 100644 --- a/plugins/optimization-detective/class-od-tag-visitor-context.php +++ b/plugins/optimization-detective/class-od-tag-visitor-context.php @@ -110,7 +110,7 @@ public function track_tag(): void { * @throws Error When property is unknown. */ public function __get( string $name ) { - // Note that there is intentionally not a case for 'visited_tag_state'. + // Note: There is intentionally not a 'visited_tag_state' case to expose $this->visited_tag_state. switch ( $name ) { case 'processor': return $this->processor; diff --git a/plugins/optimization-detective/class-od-template-optimization-context.php b/plugins/optimization-detective/class-od-template-optimization-context.php index 0492540abe..0df18fa1ac 100644 --- a/plugins/optimization-detective/class-od-template-optimization-context.php +++ b/plugins/optimization-detective/class-od-template-optimization-context.php @@ -101,29 +101,35 @@ public function __construct( OD_HTML_Tag_Processor $processor, OD_URL_Metric_Gro } /** - * Append HTML to the HEAD. + * Appends raw HTML to the HEAD. * - * The provided HTML must be valid! No validation is performed. + * The provided HTML must be valid for insertion in the HEAD. No validation is currently performed. However, in the + * future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid + * HTML is provided, this method may emit a `_doing_it_wrong()` warning. * * @since n.e.x.t + * @see OD_HTML_Tag_Processor::append_head_html() * - * @param non-empty-string $html HTML to inject. + * @param string $raw_html Raw HTML to inject. */ - public function append_head_html( string $html ): void { - $this->processor->append_head_html( $html ); + public function append_head_html( string $raw_html ): void { + $this->processor->append_head_html( $raw_html ); } /** - * Append HTML to the BODY. + * Appends raw HTML to the BODY. * - * The provided HTML must be valid! No validation is performed. + * The provided HTML must be valid for insertion in the BODY. No validation is currently performed. However, in the + * future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid + * HTML is provided, this method may emit a `_doing_it_wrong()` warning. * * @since n.e.x.t + * @see OD_HTML_Tag_Processor::append_body_html() * - * @param non-empty-string $html HTML to inject. + * @param string $raw_html HTML to inject. */ - public function append_body_html( string $html ): void { - $this->processor->append_body_html( $html ); + public function append_body_html( string $raw_html ): void { + $this->processor->append_body_html( $raw_html ); } /** @@ -137,7 +143,7 @@ public function append_body_html( string $html ): void { * @throws Error When property is unknown. */ public function __get( string $name ) { - // Note: The $processor is intentionally not exposed. + // Note: There is intentionally not a 'processor' case to expose $this->processor. switch ( $name ) { case 'url_metrics_id': return $this->url_metrics_id; From 53a91a22fc5dbba0f704725db90942b4b7e32cdf Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 14 Mar 2025 13:20:15 -0700 Subject: [PATCH 14/14] Remove append_head_html() and append_body_html() methods from OD_Template_Optimization_Context for now Co-authored-by: Felix Arntz --- ...class-od-template-optimization-context.php | 49 +------------------ .../optimization-detective/optimization.php | 1 - .../tests/test-cases/admin-bar/expected.html | 4 +- .../complete-url-metrics/expected.html | 6 +-- .../test-cases/many-images/expected.html | 4 +- .../test-cases/no-url-metrics/expected.html | 4 +- .../tests/test-cases/noscript/expected.html | 4 +- .../test-cases/preload-link/expected.html | 4 +- .../test-cases/tag-track-opt-in/expected.html | 4 +- .../tests/test-cases/video/expected.html | 4 +- .../test-cases/xhtml-response/expected.html | 4 +- .../tests/test-optimization.php | 5 -- 12 files changed, 12 insertions(+), 81 deletions(-) diff --git a/plugins/optimization-detective/class-od-template-optimization-context.php b/plugins/optimization-detective/class-od-template-optimization-context.php index 0df18fa1ac..66f6fe2ce6 100644 --- a/plugins/optimization-detective/class-od-template-optimization-context.php +++ b/plugins/optimization-detective/class-od-template-optimization-context.php @@ -33,18 +33,6 @@ final class OD_Template_Optimization_Context { */ private $url_metric_group_collection; - /** - * HTML Tag Processor. - * - * This object is not directly exposed with an accessor property. This class exposes {@see self::append_head_html()} - * and {@see self::append_body_html()} methods which wrap calls to the underlying - * {@see OD_HTML_Tag_Processor::append_head_html()} and {@see OD_HTML_Tag_Processor::append_body_html()}.s - * - * @since n.e.x.t - * @var OD_HTML_Tag_Processor - */ - private $processor; - /** * ID for the od_url_metrics post which provided the URL Metrics in the collection. * @@ -83,16 +71,15 @@ final class OD_Template_Optimization_Context { * Constructor. * * @since n.e.x.t + * @access private * - * @param OD_HTML_Tag_Processor $processor HTML Tag Processor. * @param OD_URL_Metric_Group_Collection $url_metric_group_collection URL Metric group collection. * @param OD_Link_Collection $link_collection Link collection. * @param array $normalized_query_vars Normalized query vars. * @param non-empty-string $url_metrics_slug Slug for the od_url_metrics post. * @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. */ - public function __construct( OD_HTML_Tag_Processor $processor, 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 ) { - $this->processor = $processor; + 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 ) { $this->url_metric_group_collection = $url_metric_group_collection; $this->link_collection = $link_collection; $this->normalized_query_vars = $normalized_query_vars; @@ -100,38 +87,6 @@ public function __construct( OD_HTML_Tag_Processor $processor, OD_URL_Metric_Gro $this->url_metrics_id = $url_metrics_id; } - /** - * Appends raw HTML to the HEAD. - * - * The provided HTML must be valid for insertion in the HEAD. No validation is currently performed. However, in the - * future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid - * HTML is provided, this method may emit a `_doing_it_wrong()` warning. - * - * @since n.e.x.t - * @see OD_HTML_Tag_Processor::append_head_html() - * - * @param string $raw_html Raw HTML to inject. - */ - public function append_head_html( string $raw_html ): void { - $this->processor->append_head_html( $raw_html ); - } - - /** - * Appends raw HTML to the BODY. - * - * The provided HTML must be valid for insertion in the BODY. No validation is currently performed. However, in the - * future the HTML Processor may be used to ensure the validity of the provided HTML. At that time, when invalid - * HTML is provided, this method may emit a `_doing_it_wrong()` warning. - * - * @since n.e.x.t - * @see OD_HTML_Tag_Processor::append_body_html() - * - * @param string $raw_html HTML to inject. - */ - public function append_body_html( string $raw_html ): void { - $this->processor->append_body_html( $raw_html ); - } - /** * Gets a property. * diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index 2b4fd44488..508f1cafc8 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -278,7 +278,6 @@ function od_optimize_template_output_buffer( string $buffer ): string { $link_collection = new OD_Link_Collection(); $template_optimization_context = new OD_Template_Optimization_Context( - $processor, $group_collection, $link_collection, $query_vars, diff --git a/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html b/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html index afd28d0a10..cef1b2bb25 100644 --- a/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html +++ b/plugins/optimization-detective/tests/test-cases/admin-bar/expected.html @@ -2,8 +2,7 @@ ... - - +
@@ -17,6 +16,5 @@

- diff --git a/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html b/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html index 0ea589c24e..1b3f152d57 100644 --- a/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html +++ b/plugins/optimization-detective/tests/test-cases/complete-url-metrics/expected.html @@ -2,13 +2,11 @@ ... - - +
Foo
- - + diff --git a/plugins/optimization-detective/tests/test-cases/many-images/expected.html b/plugins/optimization-detective/tests/test-cases/many-images/expected.html index 24b323405b..cd8f9d4259 100644 --- a/plugins/optimization-detective/tests/test-cases/many-images/expected.html +++ b/plugins/optimization-detective/tests/test-cases/many-images/expected.html @@ -2,8 +2,7 @@ ... - - +
@@ -1009,6 +1008,5 @@ Foo
- diff --git a/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html b/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html index e9a1f964fb..6d21c8825d 100644 --- a/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html +++ b/plugins/optimization-detective/tests/test-cases/no-url-metrics/expected.html @@ -2,14 +2,12 @@ ... - - +
Foo
- diff --git a/plugins/optimization-detective/tests/test-cases/noscript/expected.html b/plugins/optimization-detective/tests/test-cases/noscript/expected.html index c8f3fa7b7e..e0c2fa8bca 100644 --- a/plugins/optimization-detective/tests/test-cases/noscript/expected.html +++ b/plugins/optimization-detective/tests/test-cases/noscript/expected.html @@ -2,8 +2,7 @@ ... - - +
@@ -12,6 +11,5 @@
- diff --git a/plugins/optimization-detective/tests/test-cases/preload-link/expected.html b/plugins/optimization-detective/tests/test-cases/preload-link/expected.html index 60cf5800fd..e6fdf03462 100644 --- a/plugins/optimization-detective/tests/test-cases/preload-link/expected.html +++ b/plugins/optimization-detective/tests/test-cases/preload-link/expected.html @@ -2,8 +2,7 @@ ... - - + @@ -11,6 +10,5 @@
- diff --git a/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html b/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html index 3a163cb489..146cd940a5 100644 --- a/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html +++ b/plugins/optimization-detective/tests/test-cases/tag-track-opt-in/expected.html @@ -2,8 +2,7 @@ ... - - +
@@ -13,6 +12,5 @@
- diff --git a/plugins/optimization-detective/tests/test-cases/video/expected.html b/plugins/optimization-detective/tests/test-cases/video/expected.html index 2cb39c8150..599ae9ded4 100644 --- a/plugins/optimization-detective/tests/test-cases/video/expected.html +++ b/plugins/optimization-detective/tests/test-cases/video/expected.html @@ -2,8 +2,7 @@ ... - - +
@@ -13,6 +12,5 @@
- diff --git a/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html b/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html index ab8c6a4c24..975f527017 100644 --- a/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html +++ b/plugins/optimization-detective/tests/test-cases/xhtml-response/expected.html @@ -4,14 +4,12 @@ XHTML 1.0 Strict Example - - +

Foo

- diff --git a/plugins/optimization-detective/tests/test-optimization.php b/plugins/optimization-detective/tests/test-optimization.php index 26bf4cfca0..121cbe2f3b 100644 --- a/plugins/optimization-detective/tests/test-optimization.php +++ b/plugins/optimization-detective/tests/test-optimization.php @@ -379,8 +379,6 @@ public function data_provider_test_od_optimize_template_output_buffer(): array { * @covers OD_HTML_Tag_Processor::is_admin_bar * @covers OD_Template_Optimization_Context::__construct * @covers OD_Template_Optimization_Context::__get - * @covers OD_Template_Optimization_Context::append_head_html - * @covers OD_Template_Optimization_Context::append_body_html * * @dataProvider data_provider_test_od_optimize_template_output_buffer * @@ -473,8 +471,6 @@ function ( OD_Template_Optimization_Context $context ) use ( &$template_optimiza $this->assertInstanceOf( Error::class, $error ); $this->assertSame( '', $value ); - $context->append_head_html( "\n" ); - $template_optimization_context = $context; } ); @@ -489,7 +485,6 @@ function ( OD_Template_Optimization_Context $context ) use ( &$template_optimiza 'href' => 'https://inserted-at-finish-template-optimization-action.example.net/', ) ); - $context->append_body_html( "\n" ); } );