-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove requirement for both mobile and desktop URL metrics for preconnect links in Embed Optimizer #1764
Remove requirement for both mobile and desktop URL metrics for preconnect links in Embed Optimizer #1764
Changes from 5 commits
f19d670
6778acc
7f08b4e
d9fc859
9f94551
0b4150c
2c9bb4a
7d979ee
399d3b2
ca0ca13
6aa98e2
b789da7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -26,7 +26,7 @@ final class Embed_Optimizer_Tag_Visitor { | |||||
* | ||||||
* @var bool | ||||||
*/ | ||||||
protected $added_lazy_script = false; | ||||||
private $added_lazy_script = false; | ||||||
|
||||||
/** | ||||||
* Determines whether the processor is currently at a figure.wp-block-embed tag. | ||||||
|
@@ -103,96 +103,8 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool { | |||||
} | ||||||
|
||||||
$this->reduce_layout_shifts( $context ); | ||||||
|
||||||
// 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 | ||||||
) { | ||||||
$embed_wrapper_xpath = self::get_embed_wrapper_xpath( $processor->get_xpath() ); | ||||||
$max_intersection_ratio = $context->url_metric_group_collection->get_element_max_intersection_ratio( $embed_wrapper_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 ) { | ||||||
foreach ( $context->url_metric_group_collection as $group ) { | ||||||
if ( ! ( $group->get_element_max_intersection_ratio( $embed_wrapper_xpath ) > 0.0 ) ) { | ||||||
continue; | ||||||
} | ||||||
|
||||||
$context->link_collection->add_link( | ||||||
array( | ||||||
'rel' => 'preconnect', | ||||||
'href' => $preconnect_href, | ||||||
), | ||||||
$group->get_minimum_viewport_width(), | ||||||
$group->get_maximum_viewport_width() | ||||||
); | ||||||
} | ||||||
} | ||||||
} 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; | ||||||
} | ||||||
} | ||||||
$this->add_preconnect_links( $context ); | ||||||
$this->lazy_load_embeds( $context ); | ||||||
|
||||||
/* | ||||||
* At this point the tag is a figure.wp-block-embed, and we can return false because this does not need to be | ||||||
|
@@ -283,4 +195,134 @@ private function reduce_layout_shifts( OD_Tag_Visitor_Context $context ): void { | |||||
$processor->append_head_html( sprintf( "<style>\n%s\n</style>\n", join( "\n", $style_rules ) ) ); | ||||||
} | ||||||
} | ||||||
|
||||||
/** | ||||||
* Gets preconnect URLs based on embed type | ||||||
* | ||||||
* @since n.e.x.t | ||||||
* | ||||||
* @param OD_HTML_Tag_Processor $processor Processor. | ||||||
* @return array<non-empty-string> Array of URLs to preconnect to. | ||||||
*/ | ||||||
private function get_preconnect_urls( OD_HTML_Tag_Processor $processor ): array { | ||||||
/* | ||||||
* 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>. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI, this link doesn't seem to be publicly accessible. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, thanks for that. @adamsilverstein Can this be exported to a Gist? |
||||||
* 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'; | ||||||
} | ||||||
|
||||||
return $preconnect_hrefs; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Adds preconnect links for embed resources. | ||||||
* | ||||||
* @since n.e.x.t | ||||||
* | ||||||
* @param OD_Tag_Visitor_Context $context Tag visitor context, with the cursor currently at an embed block. | ||||||
*/ | ||||||
private function add_preconnect_links( OD_Tag_Visitor_Context $context ): void { | ||||||
$processor = $context->processor; | ||||||
$embed_wrapper_xpath = self::get_embed_wrapper_xpath( $processor->get_xpath() ); | ||||||
|
||||||
$preconnect_hrefs = $this->get_preconnect_urls( $processor ); | ||||||
foreach ( $preconnect_hrefs as $preconnect_href ) { | ||||||
foreach ( $context->url_metric_group_collection as $group ) { | ||||||
if ( ! ( $group->get_element_max_intersection_ratio( $embed_wrapper_xpath ) > 0.0 ) ) { | ||||||
continue; | ||||||
} | ||||||
|
||||||
$context->link_collection->add_link( | ||||||
array( | ||||||
'rel' => 'preconnect', | ||||||
'href' => $preconnect_href, | ||||||
), | ||||||
$group->get_minimum_viewport_width(), | ||||||
$group->get_maximum_viewport_width() | ||||||
); | ||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
/** | ||||||
* Optimizes an embed based on whether it is displayed in any initial viewport. | ||||||
* | ||||||
* @since n.e.x.t | ||||||
* | ||||||
* @param OD_Tag_Visitor_Context $context Tag visitor context, with the cursor currently at an embed block. | ||||||
*/ | ||||||
private function lazy_load_embeds( OD_Tag_Visitor_Context $context ): void { | ||||||
$processor = $context->processor; | ||||||
|
||||||
// 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 | ||||||
) { | ||||||
return; | ||||||
} | ||||||
|
||||||
$embed_wrapper_xpath = self::get_embed_wrapper_xpath( $processor->get_xpath() ); | ||||||
|
||||||
$max_intersection_ratio = $context->url_metric_group_collection->get_element_max_intersection_ratio( $embed_wrapper_xpath ); | ||||||
if ( ! ( $max_intersection_ratio > 0.0 ) && embed_optimizer_update_markup( $processor, false ) && ! $this->added_lazy_script ) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @westonruter Do we need to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense, thanks for clarifying. Done in 0b4150c. |
||||||
$processor->append_body_html( wp_get_inline_script_tag( embed_optimizer_get_lazy_load_script(), array( 'type' => 'module' ) ) ); | ||||||
$this->added_lazy_script = true; | ||||||
} | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
<?php | ||
return array( | ||
'set_up' => static function ( Test_Embed_Optimizer_Optimization_Detective $test_case ): void { | ||
OD_URL_Metrics_Post_Type::store_url_metric( | ||
od_get_url_metrics_slug( od_get_normalized_query_vars() ), | ||
$test_case->get_sample_url_metric( | ||
array( | ||
'viewport_width' => 100, | ||
'elements' => array( | ||
array( | ||
'xpath' => '/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]', | ||
'isLCP' => false, | ||
'intersectionRatio' => 1, | ||
'resizedBoundingClientRect' => array_merge( $test_case->get_sample_dom_rect(), array( 'height' => 500 ) ), | ||
), | ||
), | ||
) | ||
) | ||
); | ||
}, | ||
'buffer' => ' | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>...</title> | ||
</head> | ||
<body> | ||
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"> | ||
<div class="wp-block-embed__wrapper"> | ||
<iframe title="Matt Mullenweg: State of the Word 2023" width="750" height="422" src="https://www.youtube.com/embed/c7M4mBVgP3Y?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> | ||
</div> | ||
</figure> | ||
</body> | ||
</html> | ||
', | ||
'expected' => ' | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>...</title> | ||
<style> | ||
@media (max-width: 480px) { #embed-optimizer-a7659db28ecaa36ddee6ae66857dabd8 { min-height: 500px; } } | ||
</style> | ||
<link data-od-added-tag rel="preconnect" href="https://i.ytimg.com" media="(max-width: 480px)"> | ||
<link data-od-added-tag rel="preconnect" href="https://www.youtube.com" media="(max-width: 480px)"> | ||
</head> | ||
<body> | ||
<figure data-od-added-id id="embed-optimizer-a7659db28ecaa36ddee6ae66857dabd8" class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"> | ||
<div data-od-xpath="/*[1][self::HTML]/*[2][self::BODY]/*[1][self::FIGURE]/*[1][self::DIV]" class="wp-block-embed__wrapper"> | ||
<iframe title="Matt Mullenweg: State of the Word 2023" width="750" height="422" src="https://www.youtube.com/embed/c7M4mBVgP3Y?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> | ||
</div> | ||
</figure> | ||
<script type="module">/* import detect ... */</script> | ||
</body> | ||
</html> | ||
', | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems the comment lines here are missing an
space before the
*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. Fixed it in 0b4150c.