Skip to content

Commit 68c0f19

Browse files
committed
Media: Add optimization support for IMG tags with fetchpriority=low or fetchpriority=auto.
This updates `wp_get_loading_optimization_attributes()` and `wp_maybe_add_fetchpriority_high_attr()` to account for cases where an `IMG` has `fetchpriority=low` or `fetchpriority=auto`: * `IMG` tags with `fetchpriority=low` are not lazy-loaded since they may be in a Navigation overlay, Details block, or Accordion Item block and need to be loaded the instant the user toggles the block. * `IMG` tags with `fetchpriority=auto` do not increase the media count since they may be hidden in a viewport by block visibility settings. * Blocks with conditional visibility (such as hidden on mobile or desktop) now automatically add `fetchpriority="auto"` to their contained `IMG` tags to prevent them from erroneously receiving `fetchpriority=high` or affecting the lazy-loading of subsequent images. * An `IMG` with `fetchpriority=auto` which also surpasses the `wp_min_priority_img_pixels` threshold will prevent a subsequent image from getting `fetchpriority=high`. Developed in WordPress#11196 Includes backport of [WordPress/gutenberg#76302 Gutenberg#76302]. See related Gutenberg issues: - [WordPress/gutenberg#76181 76181]: Image in navigation overlay can get `fetchpriority=high` and degrade LCP metric for page. - [WordPress/gutenberg#76268 76268]: Image in collapsed Details block may erroneously get `fetchpriority=high` even though hidden. - [WordPress/gutenberg#76301 76301]: Block Visibility: `IMG` in viewport-conditional block may get `fetchpriority=high` even when not displayed. - [WordPress/gutenberg#76335 76335]: Image in collapsed Accordion block may erroneously get `fetchpriority=high` even though hidden. Follow-up to r56347, r56037. Props westonruter, mukesh27, ramonopoly, wildworks. See #58235. Fixes #64823. git-svn-id: https://develop.svn.wordpress.org/trunk@61934 602fd350-edb4-49c9-b593-d223f7449a82
1 parent b8b74d5 commit 68c0f19

5 files changed

Lines changed: 418 additions & 101 deletions

File tree

src/wp-includes/block-supports/block-visibility.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@ function wp_render_block_visibility_support( $block_content, $block ) {
139139
$processor = new WP_HTML_Tag_Processor( $block_content );
140140
if ( $processor->next_tag() ) {
141141
$processor->add_class( implode( ' ', $class_names ) );
142+
143+
/*
144+
* Set all IMG tags to be `fetchpriority=auto` so that wp_get_loading_optimization_attributes() won't add
145+
* `fetchpriority=high` or increment the media count to affect whether subsequent IMG tags get `loading=lazy`.
146+
*/
147+
do {
148+
if ( 'IMG' === $processor->get_tag() ) {
149+
$processor->set_attribute( 'fetchpriority', 'auto' );
150+
}
151+
} while ( $processor->next_tag() );
142152
$block_content = $processor->get_updated_html();
143153
}
144154
}

src/wp-includes/html-api/class-wp-html-tag-processor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,8 @@ public function change_parsing_namespace( string $new_namespace ): bool {
881881
* @type string|null $tag_closers "visit" or "skip": whether to stop on tag closers, e.g. </div>.
882882
* }
883883
* @return bool Whether a tag was matched.
884+
*
885+
* @phpstan-impure
884886
*/
885887
public function next_tag( $query = null ): bool {
886888
$this->parse_query( $query );

src/wp-includes/media.php

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5967,6 +5967,7 @@ function wp_get_webp_info( $filename ) {
59675967
* both attributes are present with those values.
59685968
*
59695969
* @since 6.3.0
5970+
* @since 7.0.0 Support `fetchpriority=low` and `fetchpriority=auto` so that `loading=lazy` is not added and the media count is not increased.
59705971
*
59715972
* @global WP_Query $wp_query WordPress Query object.
59725973
*
@@ -6067,7 +6068,9 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
60676068
}
60686069

60696070
// Logic to handle a `fetchpriority` attribute that is already provided.
6070-
if ( isset( $attr['fetchpriority'] ) && 'high' === $attr['fetchpriority'] ) {
6071+
$existing_fetchpriority = ( $attr['fetchpriority'] ?? null );
6072+
$is_low_fetchpriority = ( 'low' === $existing_fetchpriority );
6073+
if ( 'high' === $existing_fetchpriority ) {
60716074
/*
60726075
* If the image was already determined to not be in the viewport (e.g.
60736076
* from an already provided `loading` attribute), trigger a warning.
@@ -6090,6 +6093,31 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
60906093
} else {
60916094
$maybe_in_viewport = true;
60926095
}
6096+
} elseif ( $is_low_fetchpriority ) {
6097+
/*
6098+
* An IMG with fetchpriority=low is not initially displayed; it may be hidden in the Navigation Overlay,
6099+
* or it may be occluded in a non-initial carousel slide. Such images must not be lazy-loaded because the browser
6100+
* has no heuristic to know when to start loading them before the user needs to see them.
6101+
*/
6102+
$maybe_in_viewport = false;
6103+
6104+
// Preserve fetchpriority=low.
6105+
$loading_attrs['fetchpriority'] = 'low';
6106+
} elseif ( 'auto' === $existing_fetchpriority ) {
6107+
/*
6108+
* When a block's visibility support identifies that the block is conditionally displayed based on the viewport
6109+
* size, then it adds `fetchpriority=auto` to the block's IMG tags. These images must not be fetched with high
6110+
* priority because they could be erroneously loaded in viewports which do not even display them. Contrarily,
6111+
* they must not get `fetchpriority=low` because they may in fact be displayed in the current viewport. So as
6112+
* a signal to indicate that an IMG may be in the viewport, `fetchpriority=auto` is added. This has the effect
6113+
* here of preventing the media count from being increased, so that images hidden with block visibility do not
6114+
* affect whether a following IMG gets `loading=lazy`. In particular, `loading=lazy` should still be omitted
6115+
* on an IMG following any number of initial IMGs with `fetchpriority=auto` since those initial images may not
6116+
* be displayed.
6117+
*/
6118+
6119+
// Preserve fetchpriority=auto.
6120+
$loading_attrs['fetchpriority'] = 'auto';
60936121
}
60946122

60956123
if ( null === $maybe_in_viewport ) {
@@ -6140,7 +6168,7 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
61406168
* does not include any loop.
61416169
*/
61426170
&& did_action( 'get_header' ) && ! did_action( 'get_footer' )
6143-
) {
6171+
) {
61446172
$maybe_in_viewport = true;
61456173
$maybe_increase_count = true;
61466174
}
@@ -6149,12 +6177,14 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
61496177
/*
61506178
* If the element is in the viewport (`true`), potentially add
61516179
* `fetchpriority` with a value of "high". Otherwise, i.e. if the element
6152-
* is not not in the viewport (`false`) or it is unknown (`null`), add
6153-
* `loading` with a value of "lazy".
6180+
* is not in the viewport (`false`) or it is unknown (`null`), add
6181+
* `loading` with a value of "lazy" if the element is not already being
6182+
* de-prioritized with `fetchpriority=low` due to occlusion in
6183+
* Navigation Overlay, non-initial carousel slides, or a collapsed Details block.
61546184
*/
61556185
if ( $maybe_in_viewport ) {
61566186
$loading_attrs = wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr );
6157-
} else {
6187+
} elseif ( ! $is_low_fetchpriority ) {
61586188
// Only add `loading="lazy"` if the feature is enabled.
61596189
if ( wp_lazy_loading_enabled( $tag_name, $context ) ) {
61606190
$loading_attrs['loading'] = 'lazy';
@@ -6164,16 +6194,20 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
61646194
/*
61656195
* If flag was set based on contextual logic above, increase the content
61666196
* media count, either unconditionally, or based on whether the image size
6167-
* is larger than the threshold.
6197+
* is larger than the threshold. This does not apply when the IMG has
6198+
* fetchpriority=auto because it may be conditionally displayed by viewport
6199+
* size.
61686200
*/
6169-
if ( $increase_count ) {
6170-
wp_increase_content_media_count();
6171-
} elseif ( $maybe_increase_count ) {
6172-
/** This filter is documented in wp-includes/media.php */
6173-
$wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 );
6174-
6175-
if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) {
6201+
if ( 'auto' !== $existing_fetchpriority ) {
6202+
if ( $increase_count ) {
61766203
wp_increase_content_media_count();
6204+
} elseif ( $maybe_increase_count ) {
6205+
/** This filter is documented in wp-includes/media.php */
6206+
$wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 );
6207+
6208+
if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) {
6209+
wp_increase_content_media_count();
6210+
}
61776211
}
61786212
}
61796213

@@ -6245,27 +6279,31 @@ function wp_increase_content_media_count( $amount = 1 ) {
62456279
* Determines whether to add `fetchpriority='high'` to loading attributes.
62466280
*
62476281
* @since 6.3.0
6282+
* @since 7.0.0 Support is added for IMG tags with `fetchpriority='low'` and `fetchpriority='auto'`.
62486283
* @access private
62496284
*
6250-
* @param array $loading_attrs Array of the loading optimization attributes for the element.
6251-
* @param string $tag_name The tag name.
6252-
* @param array $attr Array of the attributes for the element.
6253-
* @return array Updated loading optimization attributes for the element.
6285+
* @param array<string, string> $loading_attrs Array of the loading optimization attributes for the element.
6286+
* @param string $tag_name The tag name.
6287+
* @param array<string, mixed> $attr Array of the attributes for the element.
6288+
* @return array<string, string> Updated loading optimization attributes for the element.
62546289
*/
62556290
function wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr ) {
62566291
// For now, adding `fetchpriority="high"` is only supported for images.
62576292
if ( 'img' !== $tag_name ) {
62586293
return $loading_attrs;
62596294
}
62606295

6261-
if ( isset( $attr['fetchpriority'] ) ) {
6296+
$existing_fetchpriority = $attr['fetchpriority'] ?? null;
6297+
if ( null !== $existing_fetchpriority && 'auto' !== $existing_fetchpriority ) {
62626298
/*
6263-
* While any `fetchpriority` value could be set in `$loading_attrs`,
6264-
* for consistency we only do it for `fetchpriority="high"` since that
6265-
* is the only possible value that WordPress core would apply on its
6266-
* own.
6299+
* When an IMG has been explicitly marked with `fetchpriority=high`, then honor that this is the element that
6300+
* should have the priority. In contrast, the Navigation block may add `fetchpriority=low` to an IMG which
6301+
* appears in the Navigation Overlay; such images should never be considered candidates for
6302+
* `fetchpriority=high`. Lastly, block visibility may add `fetchpriority=auto` to an IMG when the block is
6303+
* conditionally displayed based on viewport size. Such an image is considered an LCP element candidate if it
6304+
* exceeds the threshold for the minimum number of square pixels.
62676305
*/
6268-
if ( 'high' === $attr['fetchpriority'] ) {
6306+
if ( 'high' === $existing_fetchpriority ) {
62696307
$loading_attrs['fetchpriority'] = 'high';
62706308
wp_high_priority_element_flag( false );
62716309
}
@@ -6292,7 +6330,9 @@ function wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr
62926330
$wp_min_priority_img_pixels = apply_filters( 'wp_min_priority_img_pixels', 50000 );
62936331

62946332
if ( $wp_min_priority_img_pixels <= $attr['width'] * $attr['height'] ) {
6295-
$loading_attrs['fetchpriority'] = 'high';
6333+
if ( 'auto' !== $existing_fetchpriority ) {
6334+
$loading_attrs['fetchpriority'] = 'high';
6335+
}
62966336
wp_high_priority_element_flag( false );
62976337
}
62986338

@@ -6306,9 +6346,9 @@ function wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr
63066346
* @access private
63076347
*
63086348
* @param bool $value Optional. Used to change the static variable. Default null.
6309-
* @return bool Returns true if high-priority element was marked already, otherwise false.
6349+
* @return bool Returns true if the high-priority element was not already marked.
63106350
*/
6311-
function wp_high_priority_element_flag( $value = null ) {
6351+
function wp_high_priority_element_flag( $value = null ): bool {
63126352
static $high_priority_element = true;
63136353

63146354
if ( is_bool( $value ) ) {

0 commit comments

Comments
 (0)