Skip to content

Commit a7e0893

Browse files
authored
Merge branch 'trunk' into add/performance-features-management-guidance
2 parents 7b83127 + b1bf1ae commit a7e0893

17 files changed

+1090
-34
lines changed

plugins/embed-optimizer/detect.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const loadedElementContentRects = new Map();
5151
* @type {InitializeCallback}
5252
* @param {InitializeArgs} args Args.
5353
*/
54-
export function initialize( { isDebug } ) {
54+
export async function initialize( { isDebug } ) {
5555
/** @type NodeListOf<HTMLDivElement> */
5656
const embedWrappers = document.querySelectorAll(
5757
'.wp-block-embed > .wp-block-embed__wrapper[data-od-xpath]'

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

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
/**
1515
* Tag visitor that optimizes elements with background-image styles.
1616
*
17+
* @phpstan-type LcpElementExternalBackgroundImage array{
18+
* url: non-empty-string,
19+
* tag: non-empty-string,
20+
* id: string|null,
21+
* class: string|null,
22+
* }
23+
*
1724
* @since 0.1.0
1825
* @access private
1926
*/
@@ -35,6 +42,14 @@ final class Image_Prioritizer_Background_Image_Styled_Tag_Visitor extends Image_
3542
*/
3643
private $added_lazy_assets = false;
3744

45+
/**
46+
* Tuples of URL Metric group and the common LCP element external background image.
47+
*
48+
* @since n.e.x.t
49+
* @var array<array{OD_URL_Metric_Group, LcpElementExternalBackgroundImage}>
50+
*/
51+
private $group_common_lcp_element_external_background_images;
52+
3853
/**
3954
* Visits a tag.
4055
*
@@ -65,33 +80,128 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool {
6580
}
6681

6782
if ( is_null( $background_image_url ) ) {
83+
$this->maybe_preload_external_lcp_background_image( $context );
6884
return false;
6985
}
7086

7187
$xpath = $processor->get_xpath();
7288

7389
// If this element is the LCP (for a breakpoint group), add a preload link for it.
7490
foreach ( $context->url_metric_group_collection->get_groups_by_lcp_element( $xpath ) as $group ) {
75-
$link_attributes = array(
76-
'rel' => 'preload',
77-
'fetchpriority' => 'high',
78-
'as' => 'image',
79-
'href' => $background_image_url,
80-
'media' => 'screen',
81-
);
82-
83-
$context->link_collection->add_link(
84-
$link_attributes,
85-
$group->get_minimum_viewport_width(),
86-
$group->get_maximum_viewport_width()
87-
);
91+
$this->add_image_preload_link( $context->link_collection, $group, $background_image_url );
8892
}
8993

9094
$this->lazy_load_bg_images( $context );
9195

9296
return true;
9397
}
9498

99+
/**
100+
* Gets the common LCP element external background image for a URL Metric group.
101+
*
102+
* @since n.e.x.t
103+
*
104+
* @param OD_URL_Metric_Group $group Group.
105+
* @return LcpElementExternalBackgroundImage|null
106+
*/
107+
private function get_common_lcp_element_external_background_image( OD_URL_Metric_Group $group ): ?array {
108+
109+
// If the group is not fully populated, we don't have enough URL Metrics to reliably know whether the background image is consistent across page loads.
110+
// This is intentionally not using $group->is_complete() because we still will use stale URL Metrics in the calculation.
111+
if ( $group->count() !== $group->get_sample_size() ) {
112+
return null;
113+
}
114+
115+
$previous_lcp_element_external_background_image = null;
116+
foreach ( $group as $url_metric ) {
117+
/**
118+
* Stored data.
119+
*
120+
* @var LcpElementExternalBackgroundImage|null $lcp_element_external_background_image
121+
*/
122+
$lcp_element_external_background_image = $url_metric->get( 'lcpElementExternalBackgroundImage' );
123+
if ( ! is_array( $lcp_element_external_background_image ) ) {
124+
return null;
125+
}
126+
if ( null !== $previous_lcp_element_external_background_image && $previous_lcp_element_external_background_image !== $lcp_element_external_background_image ) {
127+
return null;
128+
}
129+
$previous_lcp_element_external_background_image = $lcp_element_external_background_image;
130+
}
131+
132+
return $previous_lcp_element_external_background_image;
133+
}
134+
135+
/**
136+
* Maybe preloads external background image.
137+
*
138+
* @since n.e.x.t
139+
*
140+
* @param OD_Tag_Visitor_Context $context Context.
141+
*/
142+
private function maybe_preload_external_lcp_background_image( OD_Tag_Visitor_Context $context ): void {
143+
// Gather the tuples of URL Metric group and the common LCP element external background image.
144+
// Note the groups of URL Metrics do not change across invocations, we just need to compute this once for all.
145+
if ( ! is_array( $this->group_common_lcp_element_external_background_images ) ) {
146+
$this->group_common_lcp_element_external_background_images = array();
147+
foreach ( $context->url_metric_group_collection as $group ) {
148+
$common = $this->get_common_lcp_element_external_background_image( $group );
149+
if ( is_array( $common ) ) {
150+
$this->group_common_lcp_element_external_background_images[] = array( $group, $common );
151+
}
152+
}
153+
}
154+
155+
// There are no common LCP background images, so abort.
156+
if ( count( $this->group_common_lcp_element_external_background_images ) === 0 ) {
157+
return;
158+
}
159+
160+
$processor = $context->processor;
161+
$tag_name = strtoupper( (string) $processor->get_tag() );
162+
foreach ( array_keys( $this->group_common_lcp_element_external_background_images ) as $i ) {
163+
list( $group, $common ) = $this->group_common_lcp_element_external_background_images[ $i ];
164+
if (
165+
// Note that the browser may send a lower-case tag name in the case of XHTML or embedded SVG/MathML, but
166+
// the HTML Tag Processor is currently normalizing to all upper-case. The HTML Processor on the other
167+
// hand may return the expected case.
168+
strtoupper( $common['tag'] ) === $tag_name
169+
&&
170+
$processor->get_attribute( 'id' ) === $common['id'] // May be checking equality with null.
171+
&&
172+
$processor->get_attribute( 'class' ) === $common['class'] // May be checking equality with null.
173+
) {
174+
$this->add_image_preload_link( $context->link_collection, $group, $common['url'] );
175+
176+
// Now that the preload link has been added, eliminate the entry to stop looking for it while iterating over the rest of the document.
177+
unset( $this->group_common_lcp_element_external_background_images[ $i ] );
178+
}
179+
}
180+
}
181+
182+
/**
183+
* Adds an image preload link for the group.
184+
*
185+
* @since n.e.x.t
186+
*
187+
* @param OD_Link_Collection $link_collection Link collection.
188+
* @param OD_URL_Metric_Group $group URL Metric group.
189+
* @param non-empty-string $url Image URL.
190+
*/
191+
private function add_image_preload_link( OD_Link_Collection $link_collection, OD_URL_Metric_Group $group, string $url ): void {
192+
$link_collection->add_link(
193+
array(
194+
'rel' => 'preload',
195+
'fetchpriority' => 'high',
196+
'as' => 'image',
197+
'href' => $url,
198+
'media' => 'screen',
199+
),
200+
$group->get_minimum_viewport_width(),
201+
$group->get_maximum_viewport_width()
202+
);
203+
}
204+
95205
/**
96206
* Optimizes an element with a background image based on whether it is displayed in any initial viewport.
97207
*

0 commit comments

Comments
 (0)