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 c98023e8bf..d39cc2dac2 100644 --- a/plugins/image-prioritizer/class-image-prioritizer-img-tag-visitor.php +++ b/plugins/image-prioritizer/class-image-prioritizer-img-tag-visitor.php @@ -46,16 +46,9 @@ public function __invoke( OD_HTML_Tag_Walker $walker ): bool { $common_lcp_element = $this->url_metrics_group_collection->get_common_lcp_element(); if ( ! is_null( $common_lcp_element ) && $xpath === $common_lcp_element['xpath'] ) { if ( 'high' === $walker->get_attribute( 'fetchpriority' ) ) { - $walker->set_attribute( 'data-od-fetchpriority-already-added', true ); + $walker->set_meta_attribute( 'fetchpriority-already-added', true ); } else { $walker->set_attribute( 'fetchpriority', 'high' ); - $walker->set_attribute( 'data-od-added-fetchpriority', true ); - } - - // Never include loading=lazy on the LCP image common across all breakpoints. - if ( 'lazy' === $walker->get_attribute( 'loading' ) ) { - $walker->set_attribute( 'data-od-removed-loading', $walker->get_attribute( 'loading' ) ); - $walker->remove_attribute( 'loading' ); } } elseif ( is_string( $walker->get_attribute( 'fetchpriority' ) ) && $this->url_metrics_group_collection->is_every_group_populated() ) { /* @@ -68,12 +61,25 @@ public function __invoke( OD_HTML_Tag_Walker $walker ): bool { * Note also that if this is the LCP element for _some_ of the viewport groups, it will still get * fetchpriority=high by means of the preload link (with a media query) that is added further below. */ - $walker->set_attribute( 'data-od-removed-fetchpriority', $walker->get_attribute( 'fetchpriority' ) ); $walker->remove_attribute( 'fetchpriority' ); } - // TODO: If the image is visible (intersectionRatio!=0) in any of the URL metrics, remove loading=lazy. - // TODO: Conversely, if an image is the LCP element for one breakpoint but not another, add loading=lazy. This won't hurt performance since the image is being preloaded. + $element_max_intersection_ratio = $this->url_metrics_group_collection->get_element_max_intersection_ratio( $xpath ); + + // If the element was not found, we don't know if it was visible for not, so don't do anything. + if ( is_null( $element_max_intersection_ratio ) ) { + $walker->set_meta_attribute( 'unknown-tag', true ); // Mostly useful for debugging why an IMG isn't optimized. + } else { + // Otherwise, make sure visible elements omit the loading attribute, and hidden elements include loading=lazy. + $is_visible = $element_max_intersection_ratio > 0.0; + $loading = (string) $walker->get_attribute( 'loading' ); + if ( $is_visible && 'lazy' === $loading ) { + $walker->remove_attribute( 'loading' ); + } elseif ( ! $is_visible && 'lazy' !== $loading ) { + $walker->set_attribute( 'loading', 'lazy' ); + } + } + // TODO: If an image is visible in one breakpoint but not another, add loading=lazy AND add a regular-priority preload link with media queries (unless LCP in which case it should already have a fetchpriority=high link) so that the image won't be eagerly-loaded for viewports on which it is not shown. // If this element is the LCP (for a breakpoint group), add a preload link for it. foreach ( $this->url_metrics_group_collection->get_groups_by_lcp_element( $xpath ) as $group ) { diff --git a/plugins/image-prioritizer/load.php b/plugins/image-prioritizer/load.php index 5aa30810c6..aa5606fdf6 100644 --- a/plugins/image-prioritizer/load.php +++ b/plugins/image-prioritizer/load.php @@ -1,8 +1,8 @@ fetchpriority=high and applies image lazy-loading by leveraging client-side detection with real user metrics. * Requires at least: 6.4 * Requires PHP: 7.2 * Requires Plugins: optimization-detective diff --git a/plugins/image-prioritizer/readme.txt b/plugins/image-prioritizer/readme.txt index f4902fec46..cd0083ca4c 100644 --- a/plugins/image-prioritizer/readme.txt +++ b/plugins/image-prioritizer/readme.txt @@ -9,15 +9,24 @@ License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Tags: performance, images -Optimizes the loading of the LCP image by leveraging client-side detection with real user metrics. +Optimizes LCP image loading with `fetchpriority=high` and applies image lazy-loading by leveraging client-side detection with real user metrics. == Description == -Optimizes the loading of the LCP image by leveraging client-side detection with real user metrics. Currently, this involves adding `fetchpriority=high` to the LCP image and adding preload links for the LCP `img` as well as any LCP `background-image`. +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 requires the [Optimization Detective](https://wordpress.org/plugins/optimization-detective/) plugin as a dependency. +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: -TODO: Flesh out description. +1. 0-320 (small smartphone) +2. 321-480 (normal smartphone) +3. 481-576 (phablets) +4. >576 (desktop) + +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. + +Note that by default, URL Metrics are not gathered for administrator users, since they are not normal site visitors, and it is likely that additional elements will be present on the page which are not also shown to non-administrators. + +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 == diff --git a/plugins/image-prioritizer/tests/test-helper.php b/plugins/image-prioritizer/tests/test-helper.php index 52764863a5..8e9e345d5c 100644 --- a/plugins/image-prioritizer/tests/test-helper.php +++ b/plugins/image-prioritizer/tests/test-helper.php @@ -48,7 +48,7 @@ public function data_provider_test_filter_tag_walker_visitors(): array {