Skip to content

Commit

Permalink
Merge pull request #1604 from WordPress/update/image-and-embed-lazy-l…
Browse files Browse the repository at this point in the history
…oad-hardening

Avoid lazy-loading images and embeds unless there are URL Metrics for both mobile and desktop
  • Loading branch information
westonruter authored Oct 18, 2024
2 parents 70cd02b + 4fc33a1 commit dd67b09
Show file tree
Hide file tree
Showing 15 changed files with 168 additions and 177 deletions.
147 changes: 77 additions & 70 deletions plugins/embed-optimizer/class-embed-optimizer-tag-visitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,78 +101,85 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool {

$this->reduce_layout_shifts( $context );

$max_intersection_ratio = $context->url_metric_group_collection->get_element_max_intersection_ratio( self::get_embed_wrapper_xpath( $processor->get_xpath() ) );
if ( $max_intersection_ratio > 0 ) {
/*
* The following embeds have been chosen for optimization due to their relative popularity among all embed types.
* See <https://colab.sandbox.google.com/drive/1nSpg3qoCLY-cBTV2zOUkgUCU7R7X2f_R?resourcekey=0-MgT7Ur0pT__vw-5_AHjgWQ#scrollTo=utZv59sXzXvS>.
* The list of hosts being preconnected to was obtained by inserting an embed into a post and then looking
* at the network log on the frontend as the embed renders. Each should include the host of the iframe src
* as well as URLs for assets used by the embed, _if_ the URL looks like it is not geotargeted (e.g. '-us')
* or load-balanced (e.g. 's0.example.com'). For the load balancing case, attempt to load the asset by
* incrementing the number appearing in the subdomain (e.g. s1.example.com). If the asset still loads, then
* it is a likely case of a load balancing domain name which cannot be safely preconnected since it could
* not end up being the load balanced domain used for the embed. Lastly, these domains are only for the URLs
* for GET requests, as POST requests are not likely to be part of the critical rendering path.
*/
$preconnect_hrefs = array();
$has_class = static function ( string $wanted_class ) use ( $processor ): bool {
return true === $processor->has_class( $wanted_class );
};
if ( $has_class( 'wp-block-embed-youtube' ) ) {
$preconnect_hrefs[] = 'https://www.youtube.com';
$preconnect_hrefs[] = 'https://i.ytimg.com';
} elseif ( $has_class( 'wp-block-embed-twitter' ) ) {
$preconnect_hrefs[] = 'https://syndication.twitter.com';
$preconnect_hrefs[] = 'https://pbs.twimg.com';
} elseif ( $has_class( 'wp-block-embed-vimeo' ) ) {
$preconnect_hrefs[] = 'https://player.vimeo.com';
$preconnect_hrefs[] = 'https://f.vimeocdn.com';
$preconnect_hrefs[] = 'https://i.vimeocdn.com';
} elseif ( $has_class( 'wp-block-embed-spotify' ) ) {
$preconnect_hrefs[] = 'https://apresolve.spotify.com';
$preconnect_hrefs[] = 'https://embed-cdn.spotifycdn.com';
$preconnect_hrefs[] = 'https://encore.scdn.co';
$preconnect_hrefs[] = 'https://i.scdn.co';
} elseif ( $has_class( 'wp-block-embed-videopress' ) || $has_class( 'wp-block-embed-wordpress-tv' ) ) {
$preconnect_hrefs[] = 'https://video.wordpress.com';
$preconnect_hrefs[] = 'https://public-api.wordpress.com';
$preconnect_hrefs[] = 'https://videos.files.wordpress.com';
$preconnect_hrefs[] = 'https://v0.wordpress.com'; // This does not appear to be a load-balanced domain since v1.wordpress.com is not valid.
} elseif ( $has_class( 'wp-block-embed-instagram' ) ) {
$preconnect_hrefs[] = 'https://www.instagram.com';
$preconnect_hrefs[] = 'https://static.cdninstagram.com';
$preconnect_hrefs[] = 'https://scontent.cdninstagram.com';
} elseif ( $has_class( 'wp-block-embed-tiktok' ) ) {
$preconnect_hrefs[] = 'https://www.tiktok.com';
// Note: The other domains used for TikTok embeds include https://lf16-tiktok-web.tiktokcdn-us.com,
// https://lf16-cdn-tos.tiktokcdn-us.com, and https://lf16-tiktok-common.tiktokcdn-us.com among others
// which either appear to be geo-targeted ('-us') _or_ load-balanced ('lf16'). So these are not added
// to the preconnected hosts.
} elseif ( $has_class( 'wp-block-embed-amazon' ) ) {
$preconnect_hrefs[] = 'https://read.amazon.com';
$preconnect_hrefs[] = 'https://m.media-amazon.com';
} elseif ( $has_class( 'wp-block-embed-soundcloud' ) ) {
$preconnect_hrefs[] = 'https://w.soundcloud.com';
$preconnect_hrefs[] = 'https://widget.sndcdn.com';
// Note: There is also https://i1.sndcdn.com which is for the album art, but the '1' indicates it may be geotargeted/load-balanced.
} elseif ( $has_class( 'wp-block-embed-pinterest' ) ) {
$preconnect_hrefs[] = 'https://assets.pinterest.com';
$preconnect_hrefs[] = 'https://widgets.pinterest.com';
$preconnect_hrefs[] = 'https://i.pinimg.com';
}
// Preconnect links and lazy-loading can only be done once there are URL metrics collected for both mobile and desktop.
if (
$context->url_metric_group_collection->get_first_group()->count() > 0
&&
$context->url_metric_group_collection->get_last_group()->count() > 0
) {
$max_intersection_ratio = $context->url_metric_group_collection->get_element_max_intersection_ratio( self::get_embed_wrapper_xpath( $processor->get_xpath() ) );
if ( $max_intersection_ratio > 0 ) {
/*
* The following embeds have been chosen for optimization due to their relative popularity among all embed types.
* See <https://colab.sandbox.google.com/drive/1nSpg3qoCLY-cBTV2zOUkgUCU7R7X2f_R?resourcekey=0-MgT7Ur0pT__vw-5_AHjgWQ#scrollTo=utZv59sXzXvS>.
* The list of hosts being preconnected to was obtained by inserting an embed into a post and then looking
* at the network log on the frontend as the embed renders. Each should include the host of the iframe src
* as well as URLs for assets used by the embed, _if_ the URL looks like it is not geotargeted (e.g. '-us')
* or load-balanced (e.g. 's0.example.com'). For the load balancing case, attempt to load the asset by
* incrementing the number appearing in the subdomain (e.g. s1.example.com). If the asset still loads, then
* it is a likely case of a load balancing domain name which cannot be safely preconnected since it could
* not end up being the load balanced domain used for the embed. Lastly, these domains are only for the URLs
* for GET requests, as POST requests are not likely to be part of the critical rendering path.
*/
$preconnect_hrefs = array();
$has_class = static function ( string $wanted_class ) use ( $processor ): bool {
return true === $processor->has_class( $wanted_class );
};
if ( $has_class( 'wp-block-embed-youtube' ) ) {
$preconnect_hrefs[] = 'https://www.youtube.com';
$preconnect_hrefs[] = 'https://i.ytimg.com';
} elseif ( $has_class( 'wp-block-embed-twitter' ) ) {
$preconnect_hrefs[] = 'https://syndication.twitter.com';
$preconnect_hrefs[] = 'https://pbs.twimg.com';
} elseif ( $has_class( 'wp-block-embed-vimeo' ) ) {
$preconnect_hrefs[] = 'https://player.vimeo.com';
$preconnect_hrefs[] = 'https://f.vimeocdn.com';
$preconnect_hrefs[] = 'https://i.vimeocdn.com';
} elseif ( $has_class( 'wp-block-embed-spotify' ) ) {
$preconnect_hrefs[] = 'https://apresolve.spotify.com';
$preconnect_hrefs[] = 'https://embed-cdn.spotifycdn.com';
$preconnect_hrefs[] = 'https://encore.scdn.co';
$preconnect_hrefs[] = 'https://i.scdn.co';
} elseif ( $has_class( 'wp-block-embed-videopress' ) || $has_class( 'wp-block-embed-wordpress-tv' ) ) {
$preconnect_hrefs[] = 'https://video.wordpress.com';
$preconnect_hrefs[] = 'https://public-api.wordpress.com';
$preconnect_hrefs[] = 'https://videos.files.wordpress.com';
$preconnect_hrefs[] = 'https://v0.wordpress.com'; // This does not appear to be a load-balanced domain since v1.wordpress.com is not valid.
} elseif ( $has_class( 'wp-block-embed-instagram' ) ) {
$preconnect_hrefs[] = 'https://www.instagram.com';
$preconnect_hrefs[] = 'https://static.cdninstagram.com';
$preconnect_hrefs[] = 'https://scontent.cdninstagram.com';
} elseif ( $has_class( 'wp-block-embed-tiktok' ) ) {
$preconnect_hrefs[] = 'https://www.tiktok.com';
// Note: The other domains used for TikTok embeds include https://lf16-tiktok-web.tiktokcdn-us.com,
// https://lf16-cdn-tos.tiktokcdn-us.com, and https://lf16-tiktok-common.tiktokcdn-us.com among others
// which either appear to be geo-targeted ('-us') _or_ load-balanced ('lf16'). So these are not added
// to the preconnected hosts.
} elseif ( $has_class( 'wp-block-embed-amazon' ) ) {
$preconnect_hrefs[] = 'https://read.amazon.com';
$preconnect_hrefs[] = 'https://m.media-amazon.com';
} elseif ( $has_class( 'wp-block-embed-soundcloud' ) ) {
$preconnect_hrefs[] = 'https://w.soundcloud.com';
$preconnect_hrefs[] = 'https://widget.sndcdn.com';
// Note: There is also https://i1.sndcdn.com which is for the album art, but the '1' indicates it may be geotargeted/load-balanced.
} elseif ( $has_class( 'wp-block-embed-pinterest' ) ) {
$preconnect_hrefs[] = 'https://assets.pinterest.com';
$preconnect_hrefs[] = 'https://widgets.pinterest.com';
$preconnect_hrefs[] = 'https://i.pinimg.com';
}

foreach ( $preconnect_hrefs as $preconnect_href ) {
$context->link_collection->add_link(
array(
'rel' => 'preconnect',
'href' => $preconnect_href,
)
);
foreach ( $preconnect_hrefs as $preconnect_href ) {
$context->link_collection->add_link(
array(
'rel' => 'preconnect',
'href' => $preconnect_href,
)
);
}
} elseif ( embed_optimizer_update_markup( $processor, false ) && ! $this->added_lazy_script ) {
$processor->append_body_html( wp_get_inline_script_tag( embed_optimizer_get_lazy_load_script(), array( 'type' => 'module' ) ) );
$this->added_lazy_script = true;
}
} elseif ( embed_optimizer_update_markup( $processor, false ) && ! $this->added_lazy_script ) {
$processor->append_body_html( wp_get_inline_script_tag( embed_optimizer_get_lazy_load_script(), array( 'type' => 'module' ) ) );
$this->added_lazy_script = true;
}

/*
Expand Down
15 changes: 2 additions & 13 deletions plugins/embed-optimizer/tests/test-cases/nested-figure-embed.php
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {
$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);

$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 1,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 500 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ),
),
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]/*[1][self::VIDEO]',
Expand All @@ -29,7 +18,7 @@
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[2][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 0,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 654 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 654 ) ),
),
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[2][self::FIGURE]/*[1][self::DIV]/*[1][self::FIGURE]/*[2][self::VIDEO]',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {

$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);

$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 0,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 500 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ),
),
),
false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {
$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);
$test_case->populate_url_metrics(
array(
array(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {
$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => true,
'intersectionRatio' => 1,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 500 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ),
),
)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {
$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 0,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 500 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ),
),
)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {
$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => true,
'intersectionRatio' => 1,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 500 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ),
),
),
false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {
$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => false,
'intersectionRatio' => 0,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 500 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ),
),
),
false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
<?php
return array(
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void {
$rect = array(
'width' => 500.1,
'height' => 500.2,
'x' => 100.3,
'y' => 100.4,
'top' => 0.1,
'right' => 0.2,
'bottom' => 0.3,
'left' => 0.4,
);
$test_case->populate_url_metrics(
array(
array(
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]',
'isLCP' => true,
'intersectionRatio' => 1,
'resizedBoundingClientRect' => array_merge( $rect, array( 'height' => 500 ) ),
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ),
),
)
);
Expand Down
Loading

0 comments on commit dd67b09

Please sign in to comment.