Skip to content

Commit

Permalink
Merge branch 'trunk' into update/use-ajax-for-activate-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
b1ink0 authored Nov 11, 2024
2 parents a59909d + bbbbf2b commit f9faaea
Show file tree
Hide file tree
Showing 30 changed files with 400 additions and 261 deletions.
6 changes: 3 additions & 3 deletions plugins/embed-optimizer/class-embed-optimizer-tag-visitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private function is_embed_figure( OD_HTML_Tag_Processor $processor ): bool {
* @since 0.3.0
*
* @param OD_HTML_Tag_Processor $processor Processor.
* @return bool Whether the tag should be measured and stored in URL metrics.
* @return bool Whether the tag should be measured and stored in URL Metrics.
*/
private function is_embed_wrapper( OD_HTML_Tag_Processor $processor ): bool {
return (
Expand Down Expand Up @@ -83,7 +83,7 @@ private function is_embed_wrapper( OD_HTML_Tag_Processor $processor ): bool {
* @since 0.2.0
*
* @param OD_Tag_Visitor_Context $context Tag visitor context.
* @return bool Whether the tag should be tracked in URL metrics.
* @return bool Whether the tag should be tracked in URL Metrics.
*/
public function __invoke( OD_Tag_Visitor_Context $context ): bool {
$processor = $context->processor;
Expand All @@ -103,7 +103,7 @@ 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.
// 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
&&
Expand Down
4 changes: 2 additions & 2 deletions plugins/embed-optimizer/detect.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* Embed Optimizer module for Optimization Detective
*
* When a URL metric is being collected by Optimization Detective, this module adds a ResizeObserver to keep track of
* the changed heights for embed blocks. This data is extended/amended onto the element data of the pending URL metric
* When a URL Metric is being collected by Optimization Detective, this module adds a ResizeObserver to keep track of
* the changed heights for embed blocks. This data is extended/amended onto the element data of the pending URL Metric
* when it is submitted for storage.
*/

Expand Down
22 changes: 19 additions & 3 deletions plugins/embed-optimizer/readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,25 @@ Optimizes the performance of embeds by lazy-loading iframes and scripts.

== Description ==

This plugin's purpose is to optimize the performance of [embeds in WordPress](https://wordpress.org/documentation/article/embeds/), such as YouTube videos, TikToks, and so on. Initially this is achieved by lazy-loading them only when they come into view. This improves performance because embeds are generally very resource-intensive and so lazy-loading them ensures that they don't compete with resources when the page is loading. [Other optimizations](https://github.com/WordPress/performance/issues?q=is%3Aissue+is%3Aopen+label%3A%22%5BPlugin%5D+Embed+Optimizer%22) are planned for the future.
This plugin's purpose is to optimize the performance of [embeds in WordPress](https://wordpress.org/documentation/article/embeds/), such as Tweets, YouTube videos, TikToks, and others.

This plugin also recommends that you install and activate the [Optimization Detective](https://wordpress.org/plugins/optimization-detective/) plugin. When it is active, it will start recording which embeds appear in the initial viewport based on actual visitors to your site. With this information in hand, Embed Optimizer will then avoid lazy-loading embeds which appear in the initial viewport (above the fold). This is important because lazy-loading adds a delay which can hurt the user experience and even degrade the Largest Contentful Paint (LCP) score for the page. In addition to not lazy-loading such above-the-fold embeds, Embed Optimizer will add preconnect links for the hosts of network resources known to be required for the most popular embeds (e.g. YouTube, Twitter, Vimeo, Spotify, VideoPress); this can further speed up the loading of critical embeds. Again, these performance enhancements are only enabled when Optimization Detective is active.
The current optimizations include:

1. Lazy loading embeds just before they come into view
2. Adding preconnect links for embeds in the initial viewport
3. Reserving space for embeds that resize to reduce layout shifting

**Lazy loading embeds** improves performance because embeds are generally very resource-intensive, so lazy loading them ensures that they don't compete with resources when the page is loading. Lazy loading of `IFRAME`\-based embeds is handled simply by adding the `loading=lazy` attribute. Lazy loading embeds that include `SCRIPT` tags is handled by using an Intersection Observer to watch for when the embed’s `FIGURE` container is going to enter the viewport and then it dynamically inserts the `SCRIPT` tag.

**This plugin also recommends that you install and activate the [Optimization Detective](https://wordpress.org/plugins/optimization-detective/) plugin**, which unlocks several optimizations beyond just lazy loading. Without Optimization Detective, lazy loading can actually degrade performance *when an embed is positioned in the initial viewport*. This is because lazy loading such viewport-initial elements can degrade LCP since rendering is delayed by the logic to determine whether the element is visible. This is why WordPress Core tries its best to [avoid](https://make.wordpress.org/core/2021/07/15/refining-wordpress-cores-lazy-loading-implementation/) [lazy loading](https://make.wordpress.org/core/2021/07/15/refining-wordpress-cores-lazy-loading-implementation/) `IMG` tags which appear in the initial viewport, although the server-side heuristics aren’t perfect. This is where Optimization Detective comes in since it detects whether an embed appears in any breakpoint-specific viewports, like mobile, tablet, and desktop. (See also the [Image Prioritizer](https://wordpress.org/plugins/image-prioritizer/) plugin which extends Optimization Detective to ensure lazy loading is correctly applied based on whether an IMG is in the initial viewport.)

When Optimization Detective is active, it will start keeping track of which embeds appear in the initial viewport based on actual visits to your site. With this information in hand, Embed Optimizer will then avoid lazy loading embeds which appear in the initial viewport. Furthermore, for such above-the-fold embeds Embed Optimizer will also **add preconnect links** for resources known to be used by those embeds. For example, if a YouTube embed appears in the initial viewport, Embed Optimizer with Optimization Detective will omit `loading=lazy` while also adding a preconnect link for `https://i.ytimg.com` which is the domain from which YouTube video poster images are served. Such preconnect links cause the initial-viewport embeds to load even faster.

The other major feature in Embed Optimizer enabled by Optimization Detective is the **reduction of layout shifts** caused by embeds that resize when they load. This is seen commonly in WordPress post embeds or Tweet embeds. Embed Optimizer keeps track of the resized heights of these embeds. With these resized heights stored, Embed Optimizer sets the appropriate height on the container FIGURE element as the viewport-specific `min-height` so that when the embed loads it does not cause a layout shift.

Since Optimization Detective relies on page visits to learn how the page is laid out, you’ll need to wait until you have visits from a mobile and desktop device to start seeing optimizations applied. Also, note that Optimization Detective does not apply optimizations by default for logged-in admin users.

Please note that the optimizations are intended to apply to Embed blocks. So if you do not see optimizations applied, make sure that your embeds are not inside of a Classic Block.

There are currently **no settings** and no user interface for this plugin since it is designed to work without any configuration.

Expand Down Expand Up @@ -55,7 +71,7 @@ The [plugin source code](https://github.com/WordPress/performance/tree/trunk/plu

**Enhancements**

* Leverage URL metrics to reserve space for embeds to reduce CLS. ([1373](https://github.com/WordPress/performance/pull/1373))
* Leverage URL Metrics to reserve space for embeds to reduce CLS. ([1373](https://github.com/WordPress/performance/pull/1373))
* Avoid lazy-loading images and embeds unless there are URL Metrics for both mobile and desktop. ([1604](https://github.com/WordPress/performance/pull/1604))

= 0.2.0 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final class Image_Prioritizer_Background_Image_Styled_Tag_Visitor extends Image_
* Visits a tag.
*
* @param OD_Tag_Visitor_Context $context Tag visitor context.
* @return bool Whether the tag should be tracked in URL metrics.
* @return bool Whether the tag should be tracked in URL Metrics.
*/
public function __invoke( OD_Tag_Visitor_Context $context ): bool {
$processor = $context->processor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ final class Image_Prioritizer_Img_Tag_Visitor extends Image_Prioritizer_Tag_Visi
*
* @param OD_Tag_Visitor_Context $context Tag visitor context.
*
* @return bool Whether the tag should be tracked in URL metrics.
* @return bool Whether the tag should be tracked in URL Metrics.
*/
public function __invoke( OD_Tag_Visitor_Context $context ): bool {
$processor = $context->processor;
Expand Down Expand Up @@ -61,7 +61,7 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool {
* At this point, the element is not the shared LCP across all viewport groups. Nevertheless, server-side
* heuristics have added fetchpriority=high to the element, but this is not warranted either due to a lack
* of data or because the LCP element is not common across all viewport groups. Since we have collected at
* least some URL metrics (per is_any_group_populated), further below a fetchpriority=high preload link will
* least some URL Metrics (per is_any_group_populated), further below a fetchpriority=high preload link will
* be added for the viewport(s) for which this is actually the LCP element. Some viewport groups may never
* get populated due to a lack of traffic (e.g. from tablets or phablets), so it is important to remove
* fetchpriority=high in such case to prevent server-side heuristics from prioritizing loading the image
Expand All @@ -71,10 +71,10 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool {
}

/*
* Do not do any lazy-loading if the mobile and desktop viewport groups lack URL metrics. This is important
* Do not do any lazy-loading if the mobile and desktop viewport groups lack URL Metrics. This is important
* because if there is an IMG in the initial viewport on desktop but not mobile, if then there are only URL
* metrics collected for mobile then the IMG will get lazy-loaded which is good for mobile but for desktop
* it will hurt performance. So this is why it is important to have URL metrics collected for both desktop and
* it will hurt performance. So this is why it is important to have URL Metrics collected for both desktop and
* mobile to verify whether maximum intersectionRatio is accounting for both screen sizes.
*/
$element_max_intersection_ratio = $context->url_metric_group_collection->get_element_max_intersection_ratio( $xpath );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ abstract class Image_Prioritizer_Tag_Visitor {
* Visits a tag.
*
* @param OD_Tag_Visitor_Context $context Tag visitor context.
* @return bool Whether the tag should be tracked in URL metrics.
* @return bool Whether the tag should be tracked in URL Metrics.
*/
abstract public function __invoke( OD_Tag_Visitor_Context $context ): bool;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ final class Image_Prioritizer_Video_Tag_Visitor extends Image_Prioritizer_Tag_Vi
* @since 0.2.0
*
* @param OD_Tag_Visitor_Context $context Tag visitor context.
* @return bool Whether the tag should be tracked in URL metrics.
* @return bool Whether the tag should be tracked in URL Metrics.
*/
public function __invoke( OD_Tag_Visitor_Context $context ): bool {
$processor = $context->processor;
Expand Down Expand Up @@ -96,8 +96,8 @@ private function reduce_poster_image_size( string $poster, OD_Tag_Visitor_Contex
$xpath = $processor->get_xpath();

/*
* Obtain maximum width of the element exclusively from the URL metrics group with the widest viewport width,
* which would be desktop. This prevents the situation where if URL metrics have only so far been gathered for
* Obtain maximum width of the element exclusively from the URL Metrics group with the widest viewport width,
* which would be desktop. This prevents the situation where if URL Metrics have only so far been gathered for
* mobile viewports that an excessively-small poster would end up getting served to the first desktop visitor.
*/
$max_element_width = 0;
Expand Down Expand Up @@ -173,10 +173,10 @@ private function lazy_load_videos( ?string $poster, OD_Tag_Visitor_Context $cont
$processor = $context->processor;

/*
* Do not do any lazy-loading if the mobile and desktop viewport groups lack URL metrics. This is important
* Do not do any lazy-loading if the mobile and desktop viewport groups lack URL Metrics. This is important
* because if there is a VIDEO in the initial viewport on desktop but not mobile, if then there are only URL
* metrics collected for mobile then the VIDEO will get lazy-loaded which is good for mobile but for desktop
* it will hurt performance. So this is why it is important to have URL metrics collected for both desktop and
* it will hurt performance. So this is why it is important to have URL Metrics collected for both desktop and
* mobile to verify whether maximum intersectionRatio is accounting for both screen sizes.
*/
if (
Expand Down
20 changes: 10 additions & 10 deletions plugins/image-prioritizer/readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ Optimizes LCP image loading with `fetchpriority=high` and applies image lazy-loa

== Description ==

This plugin optimizes the loading of images which are the LCP (Largest Contentful Paint) element, including both `img` elements and elements with CSS background images (where there is a `style` attribute with an `background-image` property). Different breakpoints in a theme's responsive design may result in differing elements being the LCP element. Therefore, the LCP element for each breakpoint is captured so that high-fetchpriority preload links with media queries are added which prioritize loading the LCP image specific to the viewport of the visitor.
This plugin optimizes the loading of images (and videos) with prioritization, lazy loading, and more accurate image size selection.

In addition to prioritizing the loading of the LCP image, this plugin also optimizes image loading by ensuring that `loading=lazy` is omitted from any image that appears in the initial viewport for any of the breakpoints, which by default include:
The current optimizations include:

1. 0-320 (small smartphone)
2. 321-480 (normal smartphone)
3. 481-576 (phablets)
4. >576 (desktop)
1. Ensuring `fetchpriority=high` is only added to an `IMG` when it is the Largest Contentful Paint (LCP) element across all responsive breakpoints.
2. Adding breakpoint-specific `fetchpriority=high` preload links for the LCP elements which are `IMG` elements or elements with a CSS `background-image` inline style.
3. Applying lazy-loading to `IMG` tags based on whether they appear in any breakpoint’s initial viewport. (Additionally, [`sizes=auto`](https://make.wordpress.org/core/2024/10/18/auto-sizes-for-lazy-loaded-images-in-wordpress-6-7/) is then also correctly applied.)
4. Adding `fetchpriority=low` to `IMG` tags which appear in the initial viewport but are not visible, such as when they are subsequent carousel slides.
5. Reducing the size of the `poster` image of a `VIDEO` from full size to the size appropriate for the maximum width of the video (on desktop).
6. Lazy-loading `VIDEO` tags by setting the appropriate attributes based on whether they appear in the initial viewport. If a `VIDEO` is the LCP element, it gets `preload=auto`; if it is in an initial viewport, the `preload=metadata` default is left; if it is not in an initial viewport, it gets `preload=none`. Lazy-loaded videos also get initial `preload`, `autoplay`, and `poster` attributes restored when the `VIDEO` is going to enter the viewport.

If an image does not appear in the initial viewport for any of these viewport groups, then `loading=lazy` is added to the `img` element.
**This plugin requires the [Optimization Detective](https://wordpress.org/plugins/optimization-detective/) plugin as a dependency.** Please refer to that plugin for additional background on how this plugin works as well as additional developer options.

👉 **Note:** This plugin optimizes pages for actual visitors, and it depends on visitors to optimize pages (since URL metrics need to be collected). As such, you won't see optimizations applied immediately after activating the plugin. And since administrator users are not normal visitors typically, optimizations are not applied for admins by default.
👉 **Note:** This plugin optimizes pages for actual visitors, and it depends on visitors to optimize pages. As such, you won't see optimizations applied immediately after activating the plugin. Please wait for URL Metrics to be gathered for both mobile and desktop visits. And since administrator users are not normal visitors typically, optimizations are not applied for admins by default.

There are currently **no settings** and no user interface for this plugin since it is designed to work without any configuration.

This plugin requires the [Optimization Detective](https://wordpress.org/plugins/optimization-detective/) plugin as a dependency. Please refer to that plugin for additional background on how this plugin works as well as additional developer options.

== Installation ==

= Installation from within WordPress =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}

/**
* Exception thrown when failing to validate URL metrics data.
* Exception thrown when failing to validate URL Metrics data.
*
* @since 0.1.0
* @access private
Expand Down
10 changes: 5 additions & 5 deletions plugins/optimization-detective/class-od-element.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
}

/**
* Data for a single element in a URL metric.
* Data for a single element in a URL Metric.
*
* @phpstan-import-type ElementData from OD_URL_Metric
* @phpstan-import-type DOMRect from OD_URL_Metric
Expand All @@ -33,7 +33,7 @@ class OD_Element implements ArrayAccess, JsonSerializable {
protected $data;

/**
* URL metric that this element belongs to.
* URL Metric that this element belongs to.
*
* @since 0.7.0
* @var OD_URL_Metric
Expand All @@ -48,15 +48,15 @@ class OD_Element implements ArrayAccess, JsonSerializable {
* @phpstan-param ElementData $data
*
* @param array<string, mixed> $data Element data.
* @param OD_URL_Metric $url_metric URL metric.
* @param OD_URL_Metric $url_metric URL Metric.
*/
public function __construct( array $data, OD_URL_Metric $url_metric ) {
$this->data = $data;
$this->url_metric = $url_metric;
}

/**
* Gets the URL metric that this element belongs to.
* Gets the URL Metric that this element belongs to.
*
* @since 0.7.0
*
Expand All @@ -67,7 +67,7 @@ public function get_url_metric(): OD_URL_Metric {
}

/**
* Gets the group that this element's URL metric is a part of (which may not be any).
* Gets the group that this element's URL Metric is a part of (which may not be any).
*
* @since 0.7.0
*
Expand Down
4 changes: 2 additions & 2 deletions plugins/optimization-detective/class-od-strict-url-metric.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
/**
* Representation of the measurements taken from a single client's visit to a specific URL without additionalProperties allowed.
*
* This is used exclusively in the REST API endpoint for capturing new URL metrics to prevent invalid additional data from being
* submitted in the request. For URL metrics which have been stored the looser OD_URL_Metric class is used instead.
* This is used exclusively in the REST API endpoint for capturing new URL Metrics to prevent invalid additional data from being
* submitted in the request. For URL Metrics which have been stored the looser OD_URL_Metric class is used instead.
*
* @since 0.6.0
* @access private
Expand Down
Loading

0 comments on commit f9faaea

Please sign in to comment.