Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #1921

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 ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?php
/**
* Optimization Detective: OD_Template_Optimization_Context class
*
* @package optimization-detective
* @since n.e.x.t
*/

// @codeCoverageIgnoreStart
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
// @codeCoverageIgnoreEnd

/**
* Context for optimizing a template.
*
* @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<string, mixed> $normalized_query_vars Normalized query vars.
* @property-read non-empty-string $url_metrics_slug Slug for the od_url_metrics post.
* @property-read OD_Link_Collection $link_collection Link collection.
*/
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;

/**
* 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.
*
* 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<string, mixed>
*/
private $normalized_query_vars;

/**
* Slug for the od_url_metrics post.
*
* @since n.e.x.t
* @var non-empty-string
*/
private $url_metrics_slug;

/**
* Link collection.
*
* @since n.e.x.t
* @var OD_Link_Collection
*/
private $link_collection;

/**
* Constructor.
*
* @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_Link_Collection $link_collection Link collection.
* @param array<string, mixed> $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;
$this->url_metric_group_collection = $url_metric_group_collection;
$this->link_collection = $link_collection;
$this->normalized_query_vars = $normalized_query_vars;
$this->url_metrics_slug = $url_metrics_slug;
$this->url_metrics_id = $url_metrics_id;

Check warning on line 101 in plugins/optimization-detective/class-od-template-optimization-context.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/class-od-template-optimization-context.php#L95-L101

Added lines #L95 - L101 were not covered by tests
}

/**
* 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 );

Check warning on line 114 in plugins/optimization-detective/class-od-template-optimization-context.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/class-od-template-optimization-context.php#L113-L114

Added lines #L113 - L114 were not covered by tests
}

/**
* 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 );

Check warning on line 127 in plugins/optimization-detective/class-od-template-optimization-context.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/class-od-template-optimization-context.php#L126-L127

Added lines #L126 - L127 were not covered by tests
}

/**
* 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 ) {

Check warning on line 140 in plugins/optimization-detective/class-od-template-optimization-context.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/class-od-template-optimization-context.php#L140

Added line #L140 was not covered by tests
// Note: The $processor is intentionally not exposed.
switch ( $name ) {
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 'link_collection':
return $this->link_collection;

Check warning on line 152 in plugins/optimization-detective/class-od-template-optimization-context.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/class-od-template-optimization-context.php#L143-L152

Added lines #L143 - L152 were not covered by tests
default:
throw new Error(
esc_html(
sprintf(

Check warning on line 156 in plugins/optimization-detective/class-od-template-optimization-context.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/class-od-template-optimization-context.php#L154-L156

Added lines #L154 - L156 were not covered by tests
/* translators: %s is class member variable name */
__( 'Unknown property %s.', 'optimization-detective' ),
__CLASS__ . '::$' . $name
)
)
);

Check warning on line 162 in plugins/optimization-detective/class-od-template-optimization-context.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/class-od-template-optimization-context.php#L158-L162

Added lines #L158 - L162 were not covered by tests
}
}
}
1 change: 1 addition & 0 deletions plugins/optimization-detective/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
require_once __DIR__ . '/detection.php';

// Optimization logic.
require_once __DIR__ . '/class-od-template-optimization-context.php';

Check warning on line 124 in plugins/optimization-detective/load.php

View check run for this annotation

Codecov / codecov/patch

plugins/optimization-detective/load.php#L124

Added line #L124 was not covered by tests
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';
Expand Down
42 changes: 36 additions & 6 deletions plugins/optimization-detective/optimization.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,10 @@ 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 );
$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;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this a bit strange - I assume without it PHPStan complains. But in reality a WP_Post should never have a non-positive ID. Obviously an additional check for it is not a real problem, but if we then set the $post_id to null if not, we should also set the $post to null in that same situation.

In other words: If somehow the WP_Post is invalid, we shouldn't allow the post object to get passed through either, if we don't accept its ID value.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's for the sake of PHPStan. The condition was present before when constructing OD_Tag_Visitor_Context but just moved up here.

Technically WP_Post can have a negative integer sometimes. It was a hack I used in the Customizer to denote nav_menu_item posts which were in a changeset but not yet published to the database 😅

Otherwise, the $post is only used in OD_URL_Metrics_Post_Type::get_url_metrics_from_post() below, which only looks at the post_content of the object, so in that case it doesn't matter if the ID is not valid.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But if a post doesn't have an ID, wouldn't it be considered irrelevant for Optimization Detective too? I think it would make more sense to then nullify it too for a consistent experience to avoid a weird edge-case.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since in practice it will never not be a positive-int, I've opted for phpdoc to declare it as such: 0d8cb65.


$tag_visitor_registry = new OD_Tag_Visitor_Registry();

Expand All @@ -259,22 +261,41 @@ function od_optimize_template_output_buffer( string $buffer ): string {
*/
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(
$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();
$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,
$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 );
Expand Down Expand Up @@ -337,5 +358,14 @@ function od_optimize_template_output_buffer( string $buffer ): string {
$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();
}