Skip to content

Commit

Permalink
Media: Rely on wp_get_loading_optimization_attributes() to add `dec…
Browse files Browse the repository at this point in the history
…oding="async"` to images.

The `wp_get_loading_optimization_attributes()` function was introduced in 6.3, as a single centralized place to control loading optimization attributes for various tags, most importantly images.

This changeset consolidates the `decoding="async"` optimization, which was added in 6.1, to occur solely as part of `wp_get_loading_optimization_attributes()`, removing duplicate code and allowing centralized filtering based on [56651].

As part of the change, the `wp_img_tag_add_decoding_attr()` function has been deprecated. The filter of the same name continues to be maintained for backward compatibility, as before covering only images that are part of a content blob such as post content (`the_content`).

Props pereirinha, mukesh27, joemcgill, flixos90.
Fixes #58892.
See #53232.


git-svn-id: https://develop.svn.wordpress.org/trunk@56690 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
felixarntz committed Sep 25, 2023
1 parent 6558db1 commit d33027c
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 163 deletions.
40 changes: 40 additions & 0 deletions src/wp-includes/deprecated.php
Original file line number Diff line number Diff line change
Expand Up @@ -5994,3 +5994,43 @@ function wp_update_https_detection_errors() {

update_option( 'https_detection_errors', $support_errors );
}

/**
* Adds `decoding` attribute to an `img` HTML tag.
*
* The `decoding` attribute allows developers to indicate whether the
* browser can decode the image off the main thread (`async`), on the
* main thread (`sync`) or as determined by the browser (`auto`).
*
* By default WordPress adds `decoding="async"` to images but developers
* can use the {@see 'wp_img_tag_add_decoding_attr'} filter to modify this
* to remove the attribute or set it to another accepted value.
*
* @since 6.1.0
* @deprecated 6.4.0 Use wp_img_tag_add_loading_optimization_attrs() instead.
* @see wp_img_tag_add_loading_optimization_attrs()
*
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
* @return string Converted `img` tag with `decoding` attribute added.
*/
function wp_img_tag_add_decoding_attr( $image, $context ) {
_deprecated_function( __FUNCTION__, '6.4.0', 'wp_img_tag_add_loading_optimization_attrs()' );

/*
* Only apply the decoding attribute to images that have a src attribute that
* starts with a double quote, ensuring escaped JSON is also excluded.
*/
if ( ! str_contains( $image, ' src="' ) ) {
return $image;
}

/** This action is documented in wp-includes/media.php */
$value = apply_filters( 'wp_img_tag_add_decoding_attr', 'async', $image, $context );

if ( in_array( $value, array( 'async', 'sync', 'auto' ), true ) ) {
$image = str_replace( '<img ', '<img decoding="' . esc_attr( $value ) . '" ', $image );
}

return $image;
}
133 changes: 66 additions & 67 deletions src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -1060,10 +1060,9 @@ function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = f
}

$default_attr = array(
'src' => $src,
'class' => "attachment-$size_class size-$size_class",
'alt' => trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ),
'decoding' => 'async',
'src' => $src,
'class' => "attachment-$size_class size-$size_class",
'alt' => trim( strip_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ),
);

/**
Expand Down Expand Up @@ -1892,11 +1891,6 @@ function wp_filter_content_tags( $content, $context = null ) {
// Add loading optimization attributes if applicable.
$filtered_image = wp_img_tag_add_loading_optimization_attrs( $filtered_image, $context );

// Add 'decoding=async' attribute unless a 'decoding' attribute is already present.
if ( ! str_contains( $filtered_image, ' decoding=' ) ) {
$filtered_image = wp_img_tag_add_decoding_attr( $filtered_image, $context );
}

/**
* Filters an img tag within the content for a given context.
*
Expand Down Expand Up @@ -1957,6 +1951,7 @@ function wp_img_tag_add_loading_optimization_attrs( $image, $context ) {
$height = preg_match( '/ height=["\']([0-9]+)["\']/', $image, $match_height ) ? (int) $match_height[1] : null;
$loading_val = preg_match( '/ loading=["\']([A-Za-z]+)["\']/', $image, $match_loading ) ? $match_loading[1] : null;
$fetchpriority_val = preg_match( '/ fetchpriority=["\']([A-Za-z]+)["\']/', $image, $match_fetchpriority ) ? $match_fetchpriority[1] : null;
$decoding_val = preg_match( '/ decoding=["\']([A-Za-z]+)["\']/', $image, $match_decoding ) ? $match_decoding[1] : null;

/*
* Get loading optimization attributes to use.
Expand All @@ -1970,12 +1965,53 @@ function wp_img_tag_add_loading_optimization_attrs( $image, $context ) {
'height' => $height,
'loading' => $loading_val,
'fetchpriority' => $fetchpriority_val,
'decoding' => $decoding_val,
),
$context
);

// Images should have source and dimension attributes for the loading optimization attributes to be added.
if ( ! str_contains( $image, ' src="' ) || ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) {
// Images should have source for the loading optimization attributes to be added.
if ( ! str_contains( $image, ' src="' ) ) {
return $image;
}

if ( empty( $decoding_val ) ) {
/**
* Filters the `decoding` attribute value to add to an image. Default `async`.
*
* Returning a falsey value will omit the attribute.
*
* @since 6.1.0
*
* @param string|false|null $value The `decoding` attribute value. Returning a falsey value
* will result in the attribute being omitted for the image.
* Otherwise, it may be: 'async', 'sync', or 'auto'. Defaults to false.
* @param string $image The HTML `img` tag to be filtered.
* @param string $context Additional context about how the function was called
* or where the img tag is.
*/
$filtered_decoding_attr = apply_filters(
'wp_img_tag_add_decoding_attr',
isset( $optimization_attrs['decoding'] ) ? $optimization_attrs['decoding'] : false,
$image,
$context
);

// Validate the values after filtering.
if ( isset( $optimization_attrs['decoding'] ) && ! $filtered_decoding_attr ) {
// Unset `decoding` attribute if `$filtered_decoding_attr` is set to `false`.
unset( $optimization_attrs['decoding'] );
} elseif ( in_array( $filtered_decoding_attr, array( 'async', 'sync', 'auto' ), true ) ) {
$optimization_attrs['decoding'] = $filtered_decoding_attr;
}

if ( ! empty( $optimization_attrs['decoding'] ) ) {
$image = str_replace( '<img', '<img decoding="' . esc_attr( $optimization_attrs['decoding'] ) . '"', $image );
}
}

// Images should have dimension attributes for the 'loading' and 'fetchpriority' attributes to be added.
if ( ! str_contains( $image, ' width="' ) || ! str_contains( $image, ' height="' ) ) {
return $image;
}

Expand Down Expand Up @@ -2043,56 +2079,6 @@ function wp_img_tag_add_loading_optimization_attrs( $image, $context ) {
return $image;
}

/**
* Adds `decoding` attribute to an `img` HTML tag.
*
* The `decoding` attribute allows developers to indicate whether the
* browser can decode the image off the main thread (`async`), on the
* main thread (`sync`) or as determined by the browser (`auto`).
*
* By default WordPress adds `decoding="async"` to images but developers
* can use the {@see 'wp_img_tag_add_decoding_attr'} filter to modify this
* to remove the attribute or set it to another accepted value.
*
* @since 6.1.0
*
* @param string $image The HTML `img` tag where the attribute should be added.
* @param string $context Additional context to pass to the filters.
*
* @return string Converted `img` tag with `decoding` attribute added.
*/
function wp_img_tag_add_decoding_attr( $image, $context ) {
/*
* Only apply the decoding attribute to images that have a src attribute that
* starts with a double quote, ensuring escaped JSON is also excluded.
*/
if ( ! str_contains( $image, ' src="' ) ) {
return $image;
}

/**
* Filters the `decoding` attribute value to add to an image. Default `async`.
*
* Returning a falsey value will omit the attribute.
*
* @since 6.1.0
*
* @param string|false|null $value The `decoding` attribute value. Returning a falsey value
* will result in the attribute being omitted for the image.
* Otherwise, it may be: 'async' (default), 'sync', or 'auto'.
* @param string $image The HTML `img` tag to be filtered.
* @param string $context Additional context about how the function was called
* or where the img tag is.
*/
$value = apply_filters( 'wp_img_tag_add_decoding_attr', 'async', $image, $context );

if ( in_array( $value, array( 'async', 'sync', 'auto' ), true ) ) {
$image = str_replace( '<img ', '<img decoding="' . esc_attr( $value ) . '" ', $image );
}

return $image;
}

/**
* Adds `width` and `height` attributes to an `img` HTML tag.
*
Expand Down Expand Up @@ -5608,6 +5594,7 @@ function wp_get_webp_info( $filename ) {
* loading performance. Potential attributes returned by this function are:
* - `loading` attribute with a value of "lazy"
* - `fetchpriority` attribute with a value of "high"
* - `decoding` attribute with a value of "async"
*
* If any of these attributes are already present in the given attributes, they will not be modified. Note that no
* element should have both `loading="lazy"` and `fetchpriority="high"`, so the function will trigger a warning in case
Expand Down Expand Up @@ -5661,12 +5648,6 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}

// For any resources, width and height must be provided, to avoid layout shifts.
if ( ! isset( $attr['width'], $attr['height'] ) ) {
/** This filter is documented in wp-includes/media.php */
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}

/*
* Skip programmatically created images within post content as they need to be handled together with the other
* images within the post content.
Expand All @@ -5680,6 +5661,24 @@ function wp_get_loading_optimization_attributes( $tag_name, $attr, $context ) {
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}

/*
* Add `decoding` with a value of "async" for every image unless it has a
* conflicting `decoding` attribute already present.
*/
if ( 'img' === $tag_name ) {
if ( isset( $attr['decoding'] ) ) {
$loading_attrs['decoding'] = $attr['decoding'];
} else {
$loading_attrs['decoding'] = 'async';
}
}

// For any resources, width and height must be provided, to avoid layout shifts.
if ( ! isset( $attr['width'], $attr['height'] ) ) {
/** This filter is documented in wp-includes/media.php */
return apply_filters( 'wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );
}

/*
* The key function logic starts here.
*/
Expand Down
1 change: 0 additions & 1 deletion src/wp-includes/pluggable.php
Original file line number Diff line number Diff line change
Expand Up @@ -2845,7 +2845,6 @@ function get_avatar( $id_or_email, $size = 96, $default_value = '', $alt = '', $
'loading' => null,
'fetchpriority' => null,
'extra_attr' => '',
'decoding' => 'async',
);

if ( empty( $args ) ) {
Expand Down
9 changes: 4 additions & 5 deletions src/wp-includes/theme.php
Original file line number Diff line number Diff line change
Expand Up @@ -1288,11 +1288,10 @@ function get_header_image_tag( $attr = array() ) {
$attr = wp_parse_args(
$attr,
array(
'src' => $header->url,
'width' => $width,
'height' => $height,
'alt' => $alt,
'decoding' => 'async',
'src' => $header->url,
'width' => $width,
'height' => $height,
'alt' => $alt,
)
);

Expand Down
11 changes: 5 additions & 6 deletions src/wp-includes/widgets/class-wp-widget-media-image.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,11 @@ public function render_media( $instance ) {
}

$attr = array(
'class' => $classes,
'src' => $instance['url'],
'alt' => $instance['alt'],
'width' => $instance['width'],
'height' => $instance['height'],
'decoding' => 'async',
'class' => $classes,
'src' => $instance['url'],
'alt' => $instance['alt'],
'width' => $instance['width'],
'height' => $instance['height'],
);

$loading_optimization_attr = wp_get_loading_optimization_attributes(
Expand Down
Loading

0 comments on commit d33027c

Please sign in to comment.