From 8964275967e0c595902a2a53f96c376ab1952db8 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Mon, 25 Sep 2023 22:38:17 +0000 Subject: [PATCH] Media: Rely on `wp_get_loading_optimization_attributes()` to add `decoding="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. Built from https://develop.svn.wordpress.org/trunk@56690 git-svn-id: http://core.svn.wordpress.org/trunk@56202 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/deprecated.php | 40 ++++++ wp-includes/media.php | 133 +++++++++--------- wp-includes/pluggable.php | 1 - wp-includes/theme.php | 9 +- wp-includes/version.php | 2 +- .../widgets/class-wp-widget-media-image.php | 11 +- 6 files changed, 116 insertions(+), 80 deletions(-) diff --git a/wp-includes/deprecated.php b/wp-includes/deprecated.php index a341958a4e..607843e989 100644 --- a/wp-includes/deprecated.php +++ b/wp-includes/deprecated.php @@ -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( ' $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 ) ) ), ); /** @@ -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. * @@ -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. @@ -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( ' null, 'fetchpriority' => null, 'extra_attr' => '', - 'decoding' => 'async', ); if ( empty( $args ) ) { diff --git a/wp-includes/theme.php b/wp-includes/theme.php index ba88a83fde..087d563352 100644 --- a/wp-includes/theme.php +++ b/wp-includes/theme.php @@ -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, ) ); diff --git a/wp-includes/version.php b/wp-includes/version.php index 12c498d428..49eedfd198 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.4-alpha-56689'; +$wp_version = '6.4-alpha-56690'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-includes/widgets/class-wp-widget-media-image.php b/wp-includes/widgets/class-wp-widget-media-image.php index 23822fb425..2505f26b88 100644 --- a/wp-includes/widgets/class-wp-widget-media-image.php +++ b/wp-includes/widgets/class-wp-widget-media-image.php @@ -240,12 +240,11 @@ class WP_Widget_Media_Image extends WP_Widget_Media { } $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(