diff --git a/plugins/embed-optimizer/class-embed-optimizer-tag-visitor.php b/plugins/embed-optimizer/class-embed-optimizer-tag-visitor.php index 072ab03257..3b2636ee81 100644 --- a/plugins/embed-optimizer/class-embed-optimizer-tag-visitor.php +++ b/plugins/embed-optimizer/class-embed-optimizer-tag-visitor.php @@ -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 ( @@ -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; @@ -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 && diff --git a/plugins/embed-optimizer/detect.js b/plugins/embed-optimizer/detect.js index 596177fd3e..1aab3d0838 100644 --- a/plugins/embed-optimizer/detect.js +++ b/plugins/embed-optimizer/detect.js @@ -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. */ diff --git a/plugins/embed-optimizer/readme.txt b/plugins/embed-optimizer/readme.txt index 5fb24d2b7c..4f1dc14145 100644 --- a/plugins/embed-optimizer/readme.txt +++ b/plugins/embed-optimizer/readme.txt @@ -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. @@ -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 = diff --git a/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php b/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php index 1b2379df36..798d42f1f6 100644 --- a/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php +++ b/plugins/image-prioritizer/class-image-prioritizer-background-image-styled-tag-visitor.php @@ -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; diff --git a/plugins/image-prioritizer/class-image-prioritizer-img-tag-visitor.php b/plugins/image-prioritizer/class-image-prioritizer-img-tag-visitor.php index c6c6af5b46..3480c6d72f 100644 --- a/plugins/image-prioritizer/class-image-prioritizer-img-tag-visitor.php +++ b/plugins/image-prioritizer/class-image-prioritizer-img-tag-visitor.php @@ -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; @@ -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 @@ -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 ); diff --git a/plugins/image-prioritizer/class-image-prioritizer-tag-visitor.php b/plugins/image-prioritizer/class-image-prioritizer-tag-visitor.php index 832db34f21..240b359f65 100644 --- a/plugins/image-prioritizer/class-image-prioritizer-tag-visitor.php +++ b/plugins/image-prioritizer/class-image-prioritizer-tag-visitor.php @@ -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; diff --git a/plugins/image-prioritizer/class-image-prioritizer-video-tag-visitor.php b/plugins/image-prioritizer/class-image-prioritizer-video-tag-visitor.php index 060f0b8994..120b9a8af8 100644 --- a/plugins/image-prioritizer/class-image-prioritizer-video-tag-visitor.php +++ b/plugins/image-prioritizer/class-image-prioritizer-video-tag-visitor.php @@ -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; @@ -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; @@ -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 ( diff --git a/plugins/image-prioritizer/readme.txt b/plugins/image-prioritizer/readme.txt index f7297a80fc..8097fb3d80 100644 --- a/plugins/image-prioritizer/readme.txt +++ b/plugins/image-prioritizer/readme.txt @@ -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 = diff --git a/plugins/optimization-detective/class-od-data-validation-exception.php b/plugins/optimization-detective/class-od-data-validation-exception.php index 8ecde91ad3..2efab6fc9c 100644 --- a/plugins/optimization-detective/class-od-data-validation-exception.php +++ b/plugins/optimization-detective/class-od-data-validation-exception.php @@ -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 diff --git a/plugins/optimization-detective/class-od-element.php b/plugins/optimization-detective/class-od-element.php index 2f9f776607..16a981ac1b 100644 --- a/plugins/optimization-detective/class-od-element.php +++ b/plugins/optimization-detective/class-od-element.php @@ -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 @@ -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 @@ -48,7 +48,7 @@ class OD_Element implements ArrayAccess, JsonSerializable { * @phpstan-param ElementData $data * * @param array $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; @@ -56,7 +56,7 @@ public function __construct( array $data, OD_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 * diff --git a/plugins/optimization-detective/class-od-strict-url-metric.php b/plugins/optimization-detective/class-od-strict-url-metric.php index f3ecfede21..490315461b 100644 --- a/plugins/optimization-detective/class-od-strict-url-metric.php +++ b/plugins/optimization-detective/class-od-strict-url-metric.php @@ -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 diff --git a/plugins/optimization-detective/class-od-tag-visitor-context.php b/plugins/optimization-detective/class-od-tag-visitor-context.php index 6111a64a8f..4dd1279f53 100644 --- a/plugins/optimization-detective/class-od-tag-visitor-context.php +++ b/plugins/optimization-detective/class-od-tag-visitor-context.php @@ -30,7 +30,7 @@ final class OD_Tag_Visitor_Context { public $processor; /** - * URL metric group collection. + * URL Metric group collection. * * @var OD_URL_Metric_Group_Collection * @readonly @@ -49,7 +49,7 @@ final class OD_Tag_Visitor_Context { * Constructor. * * @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_URL_Metric_Group_Collection $url_metric_group_collection URL Metric group collection. * @param OD_Link_Collection $link_collection Link collection. */ public function __construct( OD_HTML_Tag_Processor $processor, OD_URL_Metric_Group_Collection $url_metric_group_collection, OD_Link_Collection $link_collection ) { @@ -65,7 +65,7 @@ public function __construct( OD_HTML_Tag_Processor $processor, OD_URL_Metric_Gro * @todo Remove this when no plugins are possibly referring to the url_metrics_group_collection property anymore. * * @param string $name Property name. - * @return OD_URL_Metric_Group_Collection URL metric group collection. + * @return OD_URL_Metric_Group_Collection URL Metric group collection. * * @throws Error When property is unknown. */ diff --git a/plugins/optimization-detective/class-od-tag-visitor-registry.php b/plugins/optimization-detective/class-od-tag-visitor-registry.php index d57f6f051f..e6b57527cd 100644 --- a/plugins/optimization-detective/class-od-tag-visitor-registry.php +++ b/plugins/optimization-detective/class-od-tag-visitor-registry.php @@ -80,7 +80,7 @@ public function unregister( string $id ): bool { } /** - * Returns an iterator for the URL metrics in the group. + * Returns an iterator for the URL Metrics in the group. * * @return ArrayIterator ArrayIterator for tag visitors. */ @@ -89,9 +89,9 @@ public function getIterator(): ArrayIterator { } /** - * Counts the URL metrics in the group. + * Counts the URL Metrics in the group. * - * @return int<0, max> URL metric count. + * @return int<0, max> URL Metric count. */ public function count(): int { return count( $this->visitors ); diff --git a/plugins/optimization-detective/class-od-url-metric-group-collection.php b/plugins/optimization-detective/class-od-url-metric-group-collection.php index a86cd3efb6..e1b70d0c27 100644 --- a/plugins/optimization-detective/class-od-url-metric-group-collection.php +++ b/plugins/optimization-detective/class-od-url-metric-group-collection.php @@ -22,7 +22,7 @@ final class OD_URL_Metric_Group_Collection implements Countable, IteratorAggregate, JsonSerializable { /** - * URL metric groups. + * URL Metric groups. * * The number of groups corresponds to one greater than the number of * breakpoints. This is because breakpoints are the dividing line between diff --git a/plugins/optimization-detective/class-od-url-metric-group.php b/plugins/optimization-detective/class-od-url-metric-group.php index 2346e272d8..21aa0eda03 100644 --- a/plugins/optimization-detective/class-od-url-metric-group.php +++ b/plugins/optimization-detective/class-od-url-metric-group.php @@ -12,7 +12,7 @@ } /** - * URL metrics grouped by viewport according to breakpoints. + * URL Metrics grouped by viewport according to breakpoints. * * @implements IteratorAggregate * diff --git a/plugins/optimization-detective/class-od-url-metric.php b/plugins/optimization-detective/class-od-url-metric.php index a08eff8d81..5df0991056 100644 --- a/plugins/optimization-detective/class-od-url-metric.php +++ b/plugins/optimization-detective/class-od-url-metric.php @@ -78,7 +78,7 @@ class OD_URL_Metric implements JsonSerializable { * * @throws OD_Data_Validation_Exception When the input is invalid. * - * @param array $data URL metric data. + * @param array $data URL Metric data. */ public function __construct( array $data ) { if ( ! isset( $data['uuid'] ) ) { @@ -125,7 +125,7 @@ private function prepare_data( array $data ): array { } /** - * Gets the group that this URL metric is a part of (which may not be any). + * Gets the group that this URL Metric is a part of (which may not be any). * * @since 0.7.0 * @@ -136,7 +136,7 @@ public function get_group(): ?OD_URL_Metric_Group { } /** - * Sets the group that this URL metric is a part of. + * Sets the group that this URL Metric is a part of. * * @since 0.7.0 * @@ -200,7 +200,7 @@ public static function get_json_schema(): array { 'required' => true, 'properties' => array( 'uuid' => array( - 'description' => __( 'The UUID for the URL metric.', 'optimization-detective' ), + 'description' => __( 'The UUID for the URL Metric.', 'optimization-detective' ), 'type' => 'string', 'format' => 'uuid', 'required' => true, @@ -296,7 +296,7 @@ public static function get_json_schema(): array { } /** - * Filters additional schema properties which should be allowed for an elements item in a URL metric. + * Filters additional schema properties which should be allowed for an element's item in a URL metric. * * @since 0.6.0 * diff --git a/plugins/optimization-detective/detect.js b/plugins/optimization-detective/detect.js index 9445ffbe13..7903ea93f8 100644 --- a/plugins/optimization-detective/detect.js +++ b/plugins/optimization-detective/detect.js @@ -85,11 +85,11 @@ function error( ...message ) { } /** - * Checks whether the URL metric(s) for the provided viewport width is needed. + * Checks whether the URL Metric(s) for the provided viewport width is needed. * * @param {number} viewportWidth - Current viewport width. * @param {URLMetricGroupStatus[]} urlMetricGroupStatuses - Viewport group statuses. - * @return {boolean} Whether URL metrics are needed. + * @return {boolean} Whether URL Metrics are needed. */ function isViewportNeeded( viewportWidth, urlMetricGroupStatuses ) { let lastWasLacking = false; @@ -128,7 +128,7 @@ function recursiveFreeze( obj ) { } /** - * URL metric being assembled for submission. + * URL Metric being assembled for submission. * * @type {URLMetric} */ @@ -155,7 +155,7 @@ function getRootData() { } /** - * Extends root URL metric data. + * Extends root URL Metric data. * * @param {ExtendedRootData} properties */ @@ -241,12 +241,12 @@ function extendElementData( xpath, properties ) { * @param {string} args.restApiEndpoint URL for where to send the detection data. * @param {string} args.restApiNonce Nonce for writing to the REST API. * @param {string} args.currentUrl Current URL. - * @param {string} args.urlMetricSlug Slug for URL metric. - * @param {string} args.urlMetricNonce Nonce for URL metric storage. - * @param {URLMetricGroupStatus[]} args.urlMetricGroupStatuses URL metric group statuses. - * @param {number} args.storageLockTTL The TTL (in seconds) for the URL metric storage lock. + * @param {string} args.urlMetricSlug Slug for URL Metric. + * @param {string} args.urlMetricNonce Nonce for URL Metric storage. + * @param {URLMetricGroupStatus[]} args.urlMetricGroupStatuses URL Metric group statuses. + * @param {number} args.storageLockTTL The TTL (in seconds) for the URL Metric storage lock. * @param {string} args.webVitalsLibrarySrc The URL for the web-vitals library. - * @param {Object} [args.urlMetricGroupCollection] URL metric group collection, when in debug mode. + * @param {Object} [args.urlMetricGroupCollection] URL Metric group collection, when in debug mode. */ export default async function detect( { serveTime, @@ -268,7 +268,7 @@ export default async function detect( { const currentTime = getCurrentTime(); if ( isDebug ) { - log( 'Stored URL metric group collection:', urlMetricGroupCollection ); + log( 'Stored URL Metric group collection:', urlMetricGroupCollection ); } // Abort running detection logic if it was served in a cached page. @@ -281,10 +281,10 @@ export default async function detect( { return; } - // Abort if the current viewport is not among those which need URL metrics. + // Abort if the current viewport is not among those which need URL Metrics. if ( ! isViewportNeeded( win.innerWidth, urlMetricGroupStatuses ) ) { if ( isDebug ) { - log( 'No need for URL metrics from the current viewport.' ); + log( 'No need for URL Metrics from the current viewport.' ); } return; } diff --git a/plugins/optimization-detective/detection.php b/plugins/optimization-detective/detection.php index 1a6133b58f..7d18ae8374 100644 --- a/plugins/optimization-detective/detection.php +++ b/plugins/optimization-detective/detection.php @@ -16,8 +16,8 @@ * @since 0.1.0 * @access private * - * @param string $slug URL metrics slug. - * @param OD_URL_Metric_Group_Collection $group_collection URL metric group collection. + * @param string $slug URL Metrics slug. + * @param OD_URL_Metric_Group_Collection $group_collection URL Metric group collection. */ function od_get_detection_script( string $slug, OD_URL_Metric_Group_Collection $group_collection ): string { /** diff --git a/plugins/optimization-detective/readme.txt b/plugins/optimization-detective/readme.txt index 3c257e47a4..6b13dcef0b 100644 --- a/plugins/optimization-detective/readme.txt +++ b/plugins/optimization-detective/readme.txt @@ -11,7 +11,9 @@ Provides an API for leveraging real user metrics to detect optimizations to appl == Description == -This plugin captures real user metrics about what elements are displayed on the page across a variety of device form factors (e.g. desktop, tablet, and phone) in order to apply loading optimizations which are not possible with WordPress’s current server-side heuristics. This plugin is a dependency which does not provide end-user functionality on its own. For that, please install the dependent plugin [Image Prioritizer](https://wordpress.org/plugins/image-prioritizer/) (among [others](https://github.com/WordPress/performance/labels/%5BPlugin%5D%20Optimization%20Detective) to come from the WordPress Core Performance team). +This plugin captures real user metrics about what elements are displayed on the page across a variety of device form factors (e.g. desktop, tablet, and phone) in order to apply loading optimizations which are not possible with WordPress’s current server-side heuristics. + +This plugin is a dependency which does not provide end-user functionality on its own. For that, please install the dependent plugin [Image Prioritizer](https://wordpress.org/plugins/image-prioritizer/) or [Embed Optimizer](https://wordpress.org/plugins/embed-optimizer/) (among [others](https://github.com/WordPress/performance/labels/%5BPlugin%5D%20Optimization%20Detective) to come from the WordPress Core Performance team). = Background = @@ -21,11 +23,18 @@ In order to increase the accuracy of identifying the LCP element, including acro = Technical Foundation = -At the core of Optimization Detective is the “URL Metric”, information about a page according to how it was loaded by a client with a specific viewport width. This includes which elements were visible in the initial viewport and which one was the LCP element. Each URL on a site can have an associated set of these URL Metrics (stored in a custom post type) which are gathered from real users. It gathers a sample of URL Metrics according to common responsive breakpoints (e.g. mobile, tablet, and desktop). When no more URL Metrics are needed for a URL due to the sample size being obtained for the breakpoints, it discontinues serving the JavaScript to gather the metrics (leveraging the [web-vitals.js](https://github.com/GoogleChrome/web-vitals) library). With the URL Metrics in hand, the output-buffered page is sent through the HTML Tag Processor and--when the [Image Prioritizer](https://wordpress.org/plugins/image-prioritizer/) dependent plugin is installed--the images which were the LCP element for various breakpoints will get prioritized with high-priority preload links (along with `fetchpriority=high` on the actual `img` tag when it is the common LCP element across all breakpoints). LCP elements with background images added via inline `background-image` styles are also prioritized with preload links. +At the core of Optimization Detective is the “URL Metric”, information about a page according to how it was loaded by a client with a specific viewport width. This includes which elements were visible in the initial viewport and which one was the LCP element. The URL Metric data is also extensible. Each URL on a site can have an associated set of these URL Metrics (stored in a custom post type) which are gathered from the visits of real users. It gathers samples of URL Metrics which are grouped according to WordPress's default responsive breakpoints: + +1. Mobile: 0-480px +2. Phablet: 481-600px +3. Tablet: 601-782px +4. Desktop: \>782px + +When no more URL Metrics are needed for a URL due to the sample size being obtained for the viewport group, it discontinues serving the JavaScript to gather the metrics (leveraging the [web-vitals.js](https://github.com/GoogleChrome/web-vitals) library). With the URL Metrics in hand, the output-buffered page is sent through the HTML Tag Processor and--when the [Image Prioritizer](https://wordpress.org/plugins/image-prioritizer/) dependent plugin is installed--the images which were the LCP element for various breakpoints will get prioritized with high-priority preload links (along with `fetchpriority=high` on the actual `img` tag when it is the common LCP element across all breakpoints). LCP elements with background images added via inline `background-image` styles are also prioritized with preload links. URL Metrics have a “freshness TTL” after which they will be stale and the JavaScript will be served again to start gathering metrics again to ensure that the right elements continue to get their loading prioritized. When a URL Metrics custom post type hasn't been touched in a while, it is automatically garbage-collected. -👉 **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 dependent plugin(s)). And since administrator users are not normal visitors typically, optimizations are not applied for admins by default (but this can be overridden with the `od_can_optimize_response` filter below). URL metrics are not collected for administrators because it is likely that additional elements will be present on the page which are not also shown to non-administrators, meaning the URL metrics could not reliably be reused between them. +👉 **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 dependent plugin(s)). And since administrator users are not normal visitors typically, optimizations are not applied for admins by default (but this can be overridden with the `od_can_optimize_response` filter below). URL Metrics are not collected for administrators because it is likely that additional elements will be present on the page which are not also shown to non-administrators, meaning the URL Metrics could not reliably be reused between them. There are currently **no settings** and no user interface for this plugin since it is designed to work without any configuration. @@ -37,16 +46,43 @@ When the `WP_DEBUG` constant is enabled, additional logging for Optimization Det Fires when the Optimization Detective is initializing. This action is useful for loading extension code that depends on Optimization Detective to be running. The version of the plugin is passed as the sole argument so that if the required version is not present, the callback can short circuit. -**Filter:** `od_breakpoint_max_widths` (default: [480, 600, 782]) +**Action:** `od_register_tag_visitors` (argument: `OD_Tag_Visitor_Registry`) + +Fires to register tag visitors before walking over the document to perform optimizations. -Filters the breakpoint max widths to group URL metrics for various viewports. Each number represents the maximum width (inclusive) for a given breakpoint. So if there is one number, 480, then this means there will be two viewport groupings, one for 0<=480, and another >480. If instead there were three provided breakpoints (320, 480, 576) then this means there will be four groups: +For example, to register a new tag visitor that targets `H1` elements: + +` +register( + 'my-plugin/h1', + static function ( OD_Tag_Visitor_Context $context ): bool { + if ( $context->processor->get_tag() !== 'H1' ) { + return false; + } + // Now optimize based on stored URL Metrics in $context->url_metric_group_collection. + // ... + + // Returning true causes the tag to be tracked in URL Metrics. If there is no need + // for this, as in there is no reference to $context->url_metric_group_collection + // in a tag visitor, then this can instead return false. + return true; + } + ); + } +); +` - 1. 0-320 (small smartphone) - 2. 321-480 (normal smartphone) - 3. 481-576 (phablets) - 4. >576 (desktop) +Refer to [Image Prioritizer](https://github.com/WordPress/performance/tree/trunk/plugins/image-prioritizer) and [Embed Optimizer](https://github.com/WordPress/performance/tree/trunk/plugins/embed-optimizer) for real world examples of how tag visitors are used. Registered tag visitors need only be callables, so in addition to providing a closure you may provide a `callable-string` or even a class which has an `__invoke()` method. -The default breakpoints are reused from Gutenberg which appear to be used the most in media queries that affect frontend styles. +**Filter:** `od_breakpoint_max_widths` (default: `array(480, 600, 782)`) + +Filters the breakpoint max widths to group URL Metrics for various viewports. Each number represents the maximum width (inclusive) for a given breakpoint. So if there is one number, 480, then this means there will be two viewport groupings, one for 0\<=480, and another \>480. If instead there are the two breakpoints defined, 480 and 782, then this means there will be three viewport groups of URL metrics, one for 0\<=480 (i.e. mobile), another 481\<=782 (i.e. phablet/tablet), and another \>782 (i.e. desktop). + +These default breakpoints are reused from Gutenberg which appear to be used the most in media queries that affect frontend styles. **Filter:** `od_can_optimize_response` (default: boolean condition, see below) @@ -67,7 +103,7 @@ add_filter( 'od_can_optimize_response', '__return_true' ); **Filter:** `od_url_metrics_breakpoint_sample_size` (default: 3) -Filters the sample size for a breakpoint's URL metrics on a given URL. The sample size must be greater than zero. During development, it may be helpful to reduce the sample size to 1: +Filters the sample size for a breakpoint's URL Metrics on a given URL. The sample size must be greater than zero. During development, it may be helpful to reduce the sample size to 1: ` 'object', + 'properties' => array_fill_keys( + array( + 'width', + 'height', + 'x', + 'y', + 'top', + 'right', + 'bottom', + 'left', + ), + array( + 'type' => 'number', + 'required' => true, + ) + ), + ); + return $additional_properties; + } +); +` + +See also [example usage](https://github.com/WordPress/performance/blob/6bb8405c5c446e3b66c2bfa3ae03ba61b188bca2/plugins/embed-optimizer/hooks.php#L81-L110) in Embed Optimizer. + +**Filter:** `od_url_metric_schema_root_additional_properties` (default: empty array) + +Filters additional schema properties which should be allowed at the root of a URL Metric. + +The usage here is the same as the previous filter, except it allows new properties to be added to the root of the URL Metric and not just to one of the object items in the `elements` property. + +**Filter:** `od_extension_module_urls` (default: empty array of strings) + +Filters the list of extension script module URLs to import when performing detection. + +For example: + +` +getMessage() . $suffix ), // This is not a warning because schema changes will happen, and so it is expected - // that this will result in existing URL metrics being invalidated. + // that this will result in existing URL Metrics being invalidated. E_USER_NOTICE ); @@ -189,13 +189,13 @@ static function ( $url_metric_data ) use ( $trigger_error ) { } /** - * Stores URL metric by merging it with the other URL metrics which share the same normalized query vars. + * Stores URL Metric by merging it with the other URL Metrics which share the same normalized query vars. * * @since 0.1.0 * @todo There is duplicate logic here with od_handle_rest_request(). * * @param string $slug Slug (hash of normalized query vars). - * @param OD_URL_Metric $new_url_metric New URL metric. + * @param OD_URL_Metric $new_url_metric New URL Metric. * @return int|WP_Error Post ID or WP_Error otherwise. */ public static function store_url_metric( string $slug, OD_URL_Metric $new_url_metric ) { diff --git a/plugins/optimization-detective/storage/data.php b/plugins/optimization-detective/storage/data.php index 4ac7698d16..0902faa5ab 100644 --- a/plugins/optimization-detective/storage/data.php +++ b/plugins/optimization-detective/storage/data.php @@ -11,9 +11,9 @@ } /** - * Gets the freshness age (TTL) for a given URL metric. + * Gets the freshness age (TTL) for a given URL Metric. * - * When a URL metric expires it is eligible to be replaced by a newer one if its viewport lies within the same breakpoint. + * When a URL Metric expires it is eligible to be replaced by a newer one if its viewport lies within the same breakpoint. * * @since 0.1.0 * @access private @@ -22,9 +22,9 @@ */ function od_get_url_metric_freshness_ttl(): int { /** - * Filters the freshness age (TTL) for a given URL metric. + * Filters the freshness age (TTL) for a given URL Metric. * - * The freshness TTL must be at least zero, in which it considers URL metrics to always be stale. + * The freshness TTL must be at least zero, in which it considers URL Metrics to always be stale. * In practice, the value should be at least an hour. * * @since 0.1.0 @@ -54,7 +54,7 @@ function od_get_url_metric_freshness_ttl(): int { /** * Gets the normalized query vars for the current request. * - * This is used as a cache key for stored URL metrics. + * This is used as a cache key for stored URL Metrics. * * TODO: For non-singular requests, consider adding the post IDs from The Loop to ensure publishing a new post will invalidate the cache. * @@ -77,7 +77,7 @@ function od_get_normalized_query_vars(): array { ); } - // Vary URL metrics by whether the user is logged in since additional elements may be present. + // Vary URL Metrics by whether the user is logged in since additional elements may be present. if ( is_user_logged_in() ) { $normalized_query_vars['user_logged_in'] = true; } @@ -124,7 +124,7 @@ function od_get_current_url(): string { } /** - * Gets slug for URL metrics. + * Gets slug for URL Metrics. * * A slug is the hash of the normalized query vars. * @@ -141,7 +141,7 @@ function od_get_url_metrics_slug( array $query_vars ): string { } /** - * Computes nonce for storing URL metrics for a specific slug. + * Computes nonce for storing URL Metrics for a specific slug. * * This is used in the REST API to authenticate the storage of new URL metrics from a given URL. * diff --git a/plugins/optimization-detective/storage/rest-api.php b/plugins/optimization-detective/storage/rest-api.php index 849e5d86ca..2a5f5019b5 100644 --- a/plugins/optimization-detective/storage/rest-api.php +++ b/plugins/optimization-detective/storage/rest-api.php @@ -18,7 +18,7 @@ const OD_REST_API_NAMESPACE = 'optimization-detective/v1'; /** - * Route for storing a URL metric. + * Route for storing a URL Metric. * * Note the `:store` art of the endpoint follows Google's guidance in AIP-136 for the use of the POST method in a way * that does not strictly follow the standard usage. Namely, submitting a POST request to this endpoint will either @@ -30,7 +30,7 @@ const OD_URL_METRICS_ROUTE = '/url-metrics:store'; /** - * Registers endpoint for storage of URL metric. + * Registers endpoint for storage of URL Metric. * * @since 0.1.0 * @access private @@ -53,7 +53,7 @@ function od_register_endpoint(): void { 'pattern' => '^[0-9a-f]+$', 'validate_callback' => static function ( string $nonce, WP_REST_Request $request ) { if ( ! od_verify_url_metrics_storage_nonce( $nonce, $request->get_param( 'slug' ), $request->get_param( 'url' ) ) ) { - return new WP_Error( 'invalid_nonce', __( 'URL metrics nonce verification failure.', 'optimization-detective' ) ); + return new WP_Error( 'invalid_nonce', __( 'URL Metrics nonce verification failure.', 'optimization-detective' ) ); } return true; }, @@ -77,7 +77,7 @@ function od_register_endpoint(): void { if ( OD_Storage_Lock::is_locked() ) { return new WP_Error( 'url_metric_storage_locked', - __( 'URL metric storage is presently locked for the current IP.', 'optimization-detective' ), + __( 'URL Metric storage is presently locked for the current IP.', 'optimization-detective' ), array( 'status' => 403 ) ); } @@ -109,7 +109,7 @@ function od_handle_rest_request( WP_REST_Request $request ) { od_get_url_metric_freshness_ttl() ); - // Block the request if URL metrics aren't needed for the provided viewport width. + // Block the request if URL Metrics aren't needed for the provided viewport width. try { $url_metric_group = $url_metric_group_collection->get_group_for_viewport_width( $request->get_param( 'viewport' )['width'] @@ -120,7 +120,7 @@ function od_handle_rest_request( WP_REST_Request $request ) { if ( $url_metric_group->is_complete() ) { return new WP_Error( 'url_metric_group_complete', - __( 'The URL metric group for the provided viewport is already complete.', 'optimization-detective' ), + __( 'The URL Metric group for the provided viewport is already complete.', 'optimization-detective' ), array( 'status' => 403 ) ); } @@ -153,7 +153,7 @@ function od_handle_rest_request( WP_REST_Request $request ) { 'rest_invalid_param', sprintf( /* translators: %s is exception name */ - __( 'Failed to validate URL metric: %s', 'optimization-detective' ), + __( 'Failed to validate URL Metric: %s', 'optimization-detective' ), $e->getMessage() ), array( 'status' => 400 ) diff --git a/plugins/optimization-detective/tests/storage/test-rest-api.php b/plugins/optimization-detective/tests/storage/test-rest-api.php index 157bc23d76..426617f500 100644 --- a/plugins/optimization-detective/tests/storage/test-rest-api.php +++ b/plugins/optimization-detective/tests/storage/test-rest-api.php @@ -88,7 +88,7 @@ function ( OD_URL_Metric_Store_Request_Context $context ): void { $this->assertInstanceOf( WP_Post::class, $post ); $url_metrics = OD_URL_Metrics_Post_Type::get_url_metrics_from_post( $post ); - $this->assertCount( 1, $url_metrics, 'Expected number of URL metrics stored.' ); + $this->assertCount( 1, $url_metrics, 'Expected number of URL Metrics stored.' ); $this->assertSame( $valid_params['elements'], $this->get_array_json_data( $url_metrics[0]->get( 'elements' ) ) ); $this->assertSame( $valid_params['viewport']['width'], $url_metrics[0]->get_viewport_width() ); @@ -417,7 +417,7 @@ public function test_rest_request_breakpoint_not_needed_for_specific_breakpoint( public function test_rest_request_over_populate_wider_viewport_group(): void { add_filter( 'od_url_metric_storage_lock_ttl', '__return_zero' ); - // First establish a single breakpoint, so there are two groups of URL metrics + // First establish a single breakpoint, so there are two groups of URL Metrics // with viewport widths 0-480 and >481. $breakpoint_width = 480; add_filter( @@ -456,7 +456,7 @@ static function ( OD_URL_Metric_Group $group ) { $this->assertCount( 0, $url_metric_groups[0], 'Expected first group to be empty.' ); $this->assertCount( $sample_size, end( $url_metric_groups ), 'Expected last group to be fully populated.' ); - // Now attempt to store one more URL metric for the wider viewport group. + // Now attempt to store one more URL Metric for the wider viewport group. // This should fail because the group is already fully populated to the sample size. $request = $this->create_request( $wider_viewport_params ); $response = rest_get_server()->dispatch( $request ); @@ -472,7 +472,7 @@ static function ( OD_URL_Metric_Group $group ) { public function test_rest_request_over_populate_narrower_viewport_group(): void { add_filter( 'od_url_metric_storage_lock_ttl', '__return_zero' ); - // First establish a single breakpoint, so there are two groups of URL metrics + // First establish a single breakpoint, so there are two groups of URL Metrics // with viewport widths 0-480 and >481. $breakpoint_width = 480; add_filter( @@ -490,7 +490,7 @@ static function () use ( $breakpoint_width ): array { $narrower_viewport_params ); - // Now attempt to store one more URL metric for the narrower viewport group. + // Now attempt to store one more URL Metric for the narrower viewport group. // This should fail because the group is already fully populated to the sample size. $request = $this->create_request( $narrower_viewport_params ); $response = rest_get_server()->dispatch( $request ); @@ -498,10 +498,10 @@ static function () use ( $breakpoint_width ): array { } /** - * Populate URL metrics. + * Populate URL Metrics. * - * @param int $count Count of URL metrics to populate. - * @param array $params Params for URL metric. + * @param int $count Count of URL Metrics to populate. + * @param array $params Params for URL Metric. */ private function populate_url_metrics( int $count, array $params ): void { for ( $i = 0; $i < $count; $i++ ) { @@ -566,7 +566,7 @@ private function recursive_merge( array $base_array, array $sparse_array ): arra } /** - * Creates a request to store a URL metric. + * Creates a request to store a URL Metric. * * @param array $params Params. * @return WP_REST_Request> Request. diff --git a/plugins/optimization-detective/tests/test-class-od-url-metrics-group-collection.php b/plugins/optimization-detective/tests/test-class-od-url-metrics-group-collection.php index 0900651783..8553841aba 100644 --- a/plugins/optimization-detective/tests/test-class-od-url-metrics-group-collection.php +++ b/plugins/optimization-detective/tests/test-class-od-url-metrics-group-collection.php @@ -176,7 +176,7 @@ public function data_provider_sample_size_and_breakpoints(): array { * * @param int $sample_size Sample size. * @param int[] $breakpoints Breakpoints. - * @param array $viewport_widths Viewport widths mapped to the number of URL metrics to instantiate. + * @param array $viewport_widths Viewport widths mapped to the number of URL Metrics to instantiate. * @param array $expected_counts Minimum viewport widths mapped to the expected counts in each group. * * @dataProvider data_provider_sample_size_and_breakpoints @@ -214,7 +214,7 @@ public function test_adding_pushes_out_old_metrics(): void { $breakpoints = array( 400, 600 ); $group_collection = new OD_URL_Metric_Group_Collection( array(), $breakpoints, $sample_size, HOUR_IN_SECONDS ); - // Populate the groups with stale URL metrics. + // Populate the groups with stale URL Metrics. $viewport_widths = array( 300, 500, 700 ); $old_timestamp = microtime( true ) - ( HOUR_IN_SECONDS + 1 ); @@ -233,7 +233,7 @@ public function test_adding_pushes_out_old_metrics(): void { } } - // Try adding one URL metric for each breakpoint group. + // Try adding one URL Metric for each breakpoint group. foreach ( $viewport_widths as $viewport_width ) { $group_collection->add_url_metric( $this->get_sample_url_metric( array( 'viewport_width' => $viewport_width ) ) ); } @@ -242,7 +242,7 @@ public function test_adding_pushes_out_old_metrics(): void { $this->assertCount( $max_possible_url_metrics_count, $group_collection->get_flattened_url_metrics(), - 'Expected the total count of URL metrics to not exceed the multiple of the sample size.' + 'Expected the total count of URL Metrics to not exceed the multiple of the sample size.' ); $new_count = 0; foreach ( $group_collection->get_flattened_url_metrics() as $url_metric ) { @@ -250,8 +250,8 @@ public function test_adding_pushes_out_old_metrics(): void { ++$new_count; } } - $this->assertGreaterThan( 0, $new_count, 'Expected there to be at least one new URL metric.' ); - $this->assertSame( count( $viewport_widths ), $new_count, 'Expected the new URL metrics to all have been added.' ); + $this->assertGreaterThan( 0, $new_count, 'Expected there to be at least one new URL Metric.' ); + $this->assertSame( count( $viewport_widths ), $new_count, 'Expected the new URL Metrics to all have been added.' ); } /** @@ -731,7 +731,7 @@ public function data_provider_element_max_intersection_ratios(): array { * * @dataProvider data_provider_element_max_intersection_ratios * - * @param array $url_metrics URL metrics. + * @param array $url_metrics URL Metrics. * @param array $expected Expected. */ public function test_get_all_element_max_intersection_ratios( array $url_metrics, array $expected ): void { @@ -908,7 +908,7 @@ public function data_provider_get_all_elements_positioned_in_any_initial_viewpor * * @dataProvider data_provider_get_all_elements_positioned_in_any_initial_viewport * - * @param array $url_metrics URL metrics. + * @param array $url_metrics URL Metrics. * @param array $expected Expected. */ public function test_get_all_elements_positioned_in_any_initial_viewport( array $url_metrics, array $expected ): void {