Make WordPress Core


Ignore:
Timestamp:
03/11/2026 06:19:53 AM (3 months ago)
Author:
westonruter
Message:

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 https://github.com/WordPress/wordpress-develop/pull/11196
Includes backport of Gutenberg#76302.

See related Gutenberg issues:

  • 76181: Image in navigation overlay can get fetchpriority=high and degrade LCP metric for page.
  • 76268: Image in collapsed Details block may erroneously get fetchpriority=high even though hidden.
  • 76301: Block Visibility: IMG in viewport-conditional block may get fetchpriority=high even when not displayed.
  • 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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/media.php

    r61884 r61934  
    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.
     
    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.
     
    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
     
    61416169             */
    61426170            && did_action( 'get_header' ) && ! did_action( 'get_footer' )
    6143             ) {
     6171        ) {
    61446172            $maybe_in_viewport    = true;
    61456173            $maybe_increase_count = true;
     
    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 ) ) {
     
    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.
    6168      */
    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'] ) {
     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.
     6200     */
     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    }
     
    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 */
    62556290function wp_maybe_add_fetchpriority_high_attr( $loading_attrs, $tag_name, $attr ) {
     
    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 );
     
    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    }
     
    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.
    6310  */
    6311 function wp_high_priority_element_flag( $value = null ) {
     6349 * @return bool Returns true if the high-priority element was not already marked.
     6350 */
     6351function wp_high_priority_element_flag( $value = null ): bool {
    63126352    static $high_priority_element = true;
    63136353
Note: See TracChangeset for help on using the changeset viewer.