diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php
index a341958a4e31f..607843e989b5a 100644
--- a/src/wp-includes/deprecated.php
+++ b/src/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/src/wp-includes/theme.php b/src/wp-includes/theme.php
index ba88a83fded1a..087d5633521e8 100644
--- a/src/wp-includes/theme.php
+++ b/src/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/src/wp-includes/widgets/class-wp-widget-media-image.php b/src/wp-includes/widgets/class-wp-widget-media-image.php
index 23822fb4257b6..2505f26b8860d 100644
--- a/src/wp-includes/widgets/class-wp-widget-media-image.php
+++ b/src/wp-includes/widgets/class-wp-widget-media-image.php
@@ -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(
diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php
index f1cd87dd717f1..d70b54261aa6c 100644
--- a/tests/phpunit/tests/media.php
+++ b/tests/phpunit/tests/media.php
@@ -2263,16 +2263,17 @@ public function test_wp_filter_content_tags_srcset_sizes() {
$respimg_xhtml,
$respimg_html5
);
- $content_filtered = wp_img_tag_add_decoding_attr( $content_filtered, 'the_content' );
// Do not add width, height, and loading.
add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' );
add_filter( 'wp_img_tag_add_loading_attr', '__return_false' );
+ add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
$this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) );
remove_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' );
remove_filter( 'wp_img_tag_add_loading_attr', '__return_false' );
+ remove_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
}
/**
@@ -2289,7 +2290,6 @@ public function test_wp_filter_content_tags_srcset_sizes() {
public function test_wp_filter_content_tags_srcset_sizes_wrong() {
$img = get_image_tag( self::$large_id, '', '', '', 'medium' );
$img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' );
- $img = wp_img_tag_add_decoding_attr( $img, 'the_content' );
// Replace the src URL.
$image_wrong_src = preg_replace( '|src="[^"]+"|', 'src="http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/foo.jpg"', $img );
@@ -2304,7 +2304,6 @@ public function test_wp_filter_content_tags_srcset_sizes_with_preexisting_srcset
// Generate HTML and add a dummy srcset attribute.
$img = get_image_tag( self::$large_id, '', '', '', 'medium' );
$img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' );
- $img = wp_img_tag_add_decoding_attr( $img, 'the_content' );
$img = preg_replace( '|]+) />|', '', $img );
// The content filter should return the image unchanged.
@@ -2480,7 +2479,6 @@ public function test_wp_filter_content_tags_schemes() {
$respimg_https,
$respimg_relative
);
- $expected = wp_img_tag_add_decoding_attr( $expected, 'the_content' );
$actual = wp_filter_content_tags( $unfiltered );
@@ -2973,16 +2971,17 @@ public function test_wp_filter_content_tags_width_height() {
$img_no_width,
$img_no_height
);
- $content_filtered = wp_img_tag_add_decoding_attr( $content_filtered, 'the_content' );
// Do not add loading, srcset, and sizes.
add_filter( 'wp_img_tag_add_loading_attr', '__return_false' );
add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
+ add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
$this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) );
remove_filter( 'wp_img_tag_add_loading_attr', '__return_false' );
remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
+ remove_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
}
/**
@@ -3004,6 +3003,8 @@ public function test_wp_filter_content_tags_loading_lazy() {
$iframe = '';
$iframe_no_width_height = '';
+ add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
+
$lazy_img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' );
$lazy_img_xhtml = wp_img_tag_add_loading_optimization_attrs( $img_xhtml, 'test' );
$lazy_img_html5 = wp_img_tag_add_loading_optimization_attrs( $img_html5, 'test' );
@@ -3054,7 +3055,6 @@ public function test_wp_filter_content_tags_loading_lazy() {
$iframe_eager,
$iframe_no_width_height
);
- $content_filtered = wp_img_tag_add_decoding_attr( $content_filtered, 'the_content' );
// Do not add width, height, srcset, and sizes.
add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' );
@@ -3064,6 +3064,7 @@ public function test_wp_filter_content_tags_loading_lazy() {
remove_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' );
remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
+ remove_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
}
/**
@@ -3074,7 +3075,6 @@ public function test_wp_filter_content_tags_loading_lazy() {
public function test_wp_filter_content_tags_loading_lazy_opted_in() {
$img = get_image_tag( self::$large_id, '', '', '', 'medium' );
$lazy_img = wp_img_tag_add_loading_optimization_attrs( $img, 'test' );
- $lazy_img = wp_img_tag_add_decoding_attr( $lazy_img, 'the_content' );
$iframe = '';
$lazy_iframe = wp_iframe_tag_add_loading_attr( $iframe, 'test' );
@@ -3104,7 +3104,6 @@ public function test_wp_filter_content_tags_loading_lazy_opted_in() {
*/
public function test_wp_filter_content_tags_loading_lazy_opted_out() {
$img = get_image_tag( self::$large_id, '', '', '', 'medium' );
- $img = wp_img_tag_add_decoding_attr( $img, 'the_content' );
$iframe = '';
$content = '
@@ -3119,10 +3118,12 @@ public function test_wp_filter_content_tags_loading_lazy_opted_out() {
// Disable globally for all tags.
add_filter( 'wp_lazy_loading_enabled', '__return_false' );
+ add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
$this->assertSame( $content, wp_filter_content_tags( $content ) );
remove_filter( 'wp_lazy_loading_enabled', '__return_false' );
remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
+ remove_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
}
/**
@@ -3186,6 +3187,8 @@ public function test_wp_img_tag_add_loading_attr_opt_out() {
* Test that decoding="async" is not applied to img tags with single quotes.
*
* @ticket 56969
+ *
+ * @expectedDeprecated wp_img_tag_add_decoding_attr
*/
public function test_wp_img_tag_add_decoding_attr_with_single_quotes() {
$img = "";
@@ -3437,10 +3440,6 @@ public function data_wp_get_attachment_image_decoding_attr() {
'decoding' => false,
'expected' => 'no value',
),
- 'null' => array(
- 'decoding' => null,
- 'expected' => 'no value',
- ),
'zero' => array(
'decoding' => 0,
'expected' => 'no value',
@@ -3719,6 +3718,7 @@ public function data_wp_get_loading_attr_default() {
/**
* @ticket 53675
* @ticket 58235
+ * @ticket 58892
*/
public function test_wp_omit_loading_attr_threshold_filter() {
// Using a smaller image here.
@@ -3738,15 +3738,21 @@ public function test_wp_omit_loading_attr_threshold_filter() {
// Due to the filter, now the first five elements should not be lazy-loaded, i.e. return `false`.
for ( $i = 0; $i < 5; $i++ ) {
- $this->assertEmpty(
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
'Expected second image to not be lazy-loaded.'
);
}
// For following elements, lazy-load them again.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' )
);
}
@@ -3761,6 +3767,7 @@ public function test_wp_omit_loading_attr_threshold_filter() {
* @covers ::wp_get_loading_optimization_attributes
*/
public function test_wp_filter_content_tags_with_loading_optimization_attrs() {
+ add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
$img1 = get_image_tag( self::$large_id, '', '', '', 'large' );
$iframe1 = '';
$img2 = get_image_tag( self::$large_id, '', '', '', 'medium' );
@@ -3777,7 +3784,6 @@ public function test_wp_filter_content_tags_with_loading_optimization_attrs() {
// Following the threshold of 2, the first two content media elements should not be lazy-loaded.
$content_unfiltered = $img1 . $iframe1 . $img2 . $img3 . $iframe2;
$content_expected = $prio_img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2;
- $content_expected = wp_img_tag_add_decoding_attr( $content_expected, 'the_content' );
$query = $this->get_new_wp_query_for_published_post();
$this->set_main_query( $query );
@@ -3789,6 +3795,7 @@ public function test_wp_filter_content_tags_with_loading_optimization_attrs() {
$content_filtered = wp_filter_content_tags( $content_unfiltered, 'the_content' );
remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
}
+ remove_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
// After filtering, the first image should not be lazy-loaded while the other ones should be.
$this->assertSame( $content_expected, $content_filtered );
@@ -4128,6 +4135,7 @@ public function test_wp_filter_content_tags_does_not_lazy_load_images_in_header(
/**
* @ticket 58089
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_filter_content_tags
* @covers ::wp_get_loading_optimization_attributes
@@ -4143,6 +4151,7 @@ public function test_wp_filter_content_tags_does_not_apply_loading_optimization_
array(
'loading' => false,
'fetchpriority' => false,
+ 'decoding' => false,
)
);
@@ -4181,7 +4190,7 @@ static function () use ( &$image_within_content ) {
$this->assertSame( $expected_image, $image_within_content, 'Image with wp_get_attachment_image context within post content should not receive loading optimization attributes' );
// Ensure that parsed content has the image with fetchpriority as it is the first large image.
- $expected_content = wpautop( str_replace( 'assertSame( $expected_content, $content, 'Post content with programmatically injected image is missing loading optimization attributes' );
}
@@ -4261,6 +4270,7 @@ public function data_special_contexts_for_the_content_wp_get_loading_attr_defaul
* @ticket 53675
* @ticket 56930
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_get_loading_optimization_attributes
*
@@ -4272,18 +4282,27 @@ public function test_wp_get_loading_optimization_attributes( $context ) {
$attr = $this->get_width_height_for_high_priority();
// Return 'lazy' by default.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'test' )
);
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'wp_get_attachment_image' )
);
// Return 'lazy' if not in the loop or the main query.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
@@ -4293,8 +4312,11 @@ public function test_wp_get_loading_optimization_attributes( $context ) {
the_post();
// Return 'lazy' if in the loop but not in the main query.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
@@ -4302,29 +4324,44 @@ public function test_wp_get_loading_optimization_attributes( $context ) {
$this->set_main_query( $query );
// First three element are not lazy loaded. However, first image is loaded with fetchpriority high.
- $this->assertSame(
- array( 'fetchpriority' => 'high' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'fetchpriority' => 'high',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
"Expected first image to not be lazy-loaded. First large image get's high fetchpriority."
);
- $this->assertEmpty(
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'Expected second image to not be lazy-loaded.'
);
- $this->assertEmpty(
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'Expected third image to not be lazy-loaded.'
);
// Return 'lazy' if in the loop and in the main query for any subsequent elements.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
// Yes, for all subsequent elements.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
}
@@ -4344,8 +4381,11 @@ public function test_wp_get_loading_optimization_attributes( $context ) {
public function test_wp_get_loading_optimization_attributes_with_arbitrary_contexts_in_main_loop( $context ) {
$attr = $this->get_width_height_for_high_priority();
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'The "loading" attribute should be "lazy" when not in the loop or the main query.'
);
@@ -4358,8 +4398,11 @@ public function test_wp_get_loading_optimization_attributes_with_arbitrary_conte
while ( have_posts() ) {
the_post();
- $this->assertSame(
- array( 'fetchpriority' => 'high' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'fetchpriority' => 'high',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'The "fetchpriority" attribute should be "high" while in the loop and the main query.'
);
@@ -4388,8 +4431,11 @@ public function test_wp_get_loading_optimization_attributes_with_arbitrary_conte
// Set as main query.
$this->set_main_query( $query );
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'The "loading" attribute should be "lazy" before the main query loop.'
);
@@ -4397,8 +4443,11 @@ public function test_wp_get_loading_optimization_attributes_with_arbitrary_conte
while ( have_posts() ) {
the_post();
- $this->assertSame(
- array( 'fetchpriority' => 'high' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'fetchpriority' => 'high',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'The "fetchpriority" attribute should be "high" while in the loop and the main query.'
);
@@ -4467,8 +4516,11 @@ public function test_wp_get_loading_optimization_attributes_header_contexts( $co
add_filter( 'wp_loading_optimization_force_header_contexts', '__return_empty_array' );
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'Images in the header context should get lazy-loaded after the wp_loading_optimization_force_header_contexts filter.'
);
@@ -4502,8 +4554,11 @@ function ( $context ) {
}
);
- $this->assertSame(
- array( 'fetchpriority' => 'high' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'fetchpriority' => 'high',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'something_completely_arbitrary' )
);
}
@@ -4513,6 +4568,7 @@ function ( $context ) {
*
* @ticket 58211
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_get_loading_optimization_attributes
*
@@ -4530,8 +4586,11 @@ public function test_wp_get_loading_optimization_attributes_before_loop_if_not_m
$attr = $this->get_width_height_for_high_priority();
// Lazy if not main query.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
}
@@ -4541,6 +4600,7 @@ public function test_wp_get_loading_optimization_attributes_before_loop_if_not_m
*
* @ticket 58211
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_get_loading_optimization_attributes
*
@@ -4557,8 +4617,11 @@ public function test_wp_get_loading_optimization_attributes_before_loop_in_main_
$attr = $this->get_width_height_for_high_priority();
// Lazy if header not called.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
}
@@ -4585,8 +4648,11 @@ public function test_wp_get_loading_optimization_attributes_before_loop_if_main_
$attr = $this->get_width_height_for_high_priority();
// First image is loaded with high fetchpriority.
- $this->assertSame(
- array( 'fetchpriority' => 'high' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'fetchpriority' => 'high',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context ),
'Expected first image to not be lazy-loaded. First large image is loaded with high fetchpriority.'
);
@@ -4597,6 +4663,7 @@ public function test_wp_get_loading_optimization_attributes_before_loop_if_main_
*
* @ticket 58211
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_get_loading_optimization_attributes
*
@@ -4617,8 +4684,11 @@ public function test_wp_get_loading_optimization_attributes_after_loop( $context
}
$attr = $this->get_width_height_for_high_priority();
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
}
@@ -4628,6 +4698,7 @@ public function test_wp_get_loading_optimization_attributes_after_loop( $context
*
* @ticket 58211
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_get_loading_optimization_attributes
*
@@ -4648,8 +4719,11 @@ public function test_wp_get_loading_optimization_attributes_no_loop( $context )
$attr = $this->get_width_height_for_high_priority();
// Load lazy if the there is no loop and footer was called.
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
}
@@ -4659,6 +4733,7 @@ public function test_wp_get_loading_optimization_attributes_no_loop( $context )
*
* @ticket 58089
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_get_loading_optimization_attributes
*
@@ -4668,8 +4743,11 @@ public function test_wp_get_loading_optimization_attributes_no_loop( $context )
*/
public function test_wp_get_loading_optimization_attributes_should_return_lazy_for_special_contexts_outside_of_the_content( $context ) {
$attr = $this->get_width_height_for_high_priority();
- $this->assertSame(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, $context )
);
}
@@ -4703,6 +4781,54 @@ function ( $content ) use ( &$result, $context ) {
$this->assertSame( array(), $result );
}
+ /**
+ * Tests to cover the decoding attribute within wp_get_loading_optimization_attributes().
+ *
+ * @ticket 58892
+ *
+ * @covers ::wp_get_loading_optimization_attributes
+ */
+ public function test_wp_get_loading_optimization_attributes_decoding_attribute() {
+
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ ),
+ wp_get_loading_optimization_attributes( 'img', array(), 'the_content' ),
+ 'Expected decoding attribute to be async.'
+ );
+
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'auto',
+ ),
+ wp_get_loading_optimization_attributes( 'img', array( 'decoding' => 'auto' ), 'the_content' ),
+ 'Expected decoding attribute to be auto.'
+ );
+
+ $result = null;
+ add_filter(
+ 'the_content',
+ static function ( $content ) use ( &$result ) {
+ $result = wp_get_loading_optimization_attributes( 'img', array(), 'something_completely_arbitrary' );
+ return $content;
+ }
+ );
+ apply_filters( 'the_content', '' );
+
+ $this->assertSameSetsWithIndex(
+ array(),
+ $result,
+ 'Expected decoding attribute to be empty for img on arbitrary context, while running the_content.'
+ );
+
+ $this->assertSameSetsWithIndex(
+ array(),
+ wp_get_loading_optimization_attributes( 'iframe', array(), 'the_content' ),
+ 'Expected decoding attribute to be empty for iframe.'
+ );
+ }
+
/**
* @ticket 44427
* @ticket 50367
@@ -4809,6 +4935,7 @@ public function test_the_excerpt_does_not_affect_omit_lazy_loading_logic() {
'post-thumbnail',
array(
'loading' => false,
+ 'decoding' => 'async',
'fetchpriority' => 'high',
)
);
@@ -5015,20 +5142,27 @@ public function data_wp_get_loading_optimization_attributes_min_required_attrs()
'width' => 100,
'height' => 100,
),
- array( 'loading' => 'lazy' ),
- 'Expected default `loading="lazy"`.',
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
+ 'Expected default `decoding="async"` and `loading="lazy"`.',
),
'img_without_height' => array(
'img',
array( 'width' => 100 ),
- array(),
- 'Expected blank array as height is required.',
+ array(
+ 'decoding' => 'async',
+ ),
+ 'Only `decoding` is set as height is required for `loading` attribute.',
),
'img_without_width' => array(
'img',
array( 'height' => 100 ),
- array(),
- 'Expected blank array as width is required.',
+ array(
+ 'decoding' => 'async',
+ ),
+ 'Only `decoding` is set as width is required for `loading` attribute.',
),
);
}
@@ -5061,8 +5195,11 @@ public function data_wp_get_loading_optimization_attributes_check_allowed_tags()
return array(
'img' => array(
'img',
- array( 'loading' => 'lazy' ),
- 'Expected `loading="lazy"` for the img.',
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
+ 'Expected `decoding="async"` and `loading="lazy"` and `decoding="async"` for the img.',
),
'iframe' => array(
'iframe',
@@ -5105,8 +5242,11 @@ public function test_wp_get_loading_optimization_attributes_header_block_templat
$attr = $this->get_width_height_for_high_priority();
// Skip logic if context is `template`.
- $this->assertSame(
- array( 'fetchpriority' => 'high' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'fetchpriority' => 'high',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'template_part_' . WP_TEMPLATE_PART_AREA_HEADER ),
'Images in the header block template part should not be lazy-loaded and first large image is set high fetchpriority.'
);
@@ -5114,6 +5254,7 @@ public function test_wp_get_loading_optimization_attributes_header_block_templat
/**
* @ticket 58235
+ * @ticket 58892
*
* @covers ::wp_get_loading_optimization_attributes
* @expectedIncorrectUsage wp_get_loading_optimization_attributes
@@ -5125,6 +5266,7 @@ public function test_wp_get_loading_optimization_attributes_incorrect_loading_at
$this->assertEqualSetsWithIndex(
array(
+ 'decoding' => 'async',
'loading' => 'lazy',
'fetchpriority' => 'high',
),
@@ -5143,8 +5285,9 @@ public function test_wp_get_loading_optimization_attributes_if_loading_attr_pres
$attr['loading'] = 'eager';
// Check fetchpriority high logic if loading attribute is present.
- $this->assertSame(
+ $this->assertSameSetsWithIndex(
array(
+ 'decoding' => 'async',
'fetchpriority' => 'high',
),
wp_get_loading_optimization_attributes( 'img', $attr, 'test' ),
@@ -5166,7 +5309,9 @@ public function test_wp_get_loading_optimization_attributes_low_res_image() {
// fetchpriority not set as image is of lower resolution.
$this->assertSame(
- array(),
+ array(
+ 'decoding' => 'async',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'test' ),
'loading optimization attr array should be empty.'
);
@@ -5182,7 +5327,7 @@ public function test_wp_get_loading_optimization_attributes_in_shortcodes( $setu
$setup();
// The first image processed in a shortcode should have fetchpriority set to high.
- $this->assertSame(
+ $this->assertSameSetsWithIndex(
$expected,
wp_get_loading_optimization_attributes( 'img', $attr, 'do_shortcode' ),
$message
@@ -5200,6 +5345,7 @@ public function data_wp_get_loading_optimization_attributes_in_shortcodes() {
$this->set_main_query( $wp_query );
},
'expected' => array(
+ 'decoding' => 'async',
'fetchpriority' => 'high',
),
'message' => 'Fetch priority not applied to during shortcode rendering.',
@@ -5217,9 +5363,10 @@ public function data_wp_get_loading_optimization_attributes_in_shortcodes() {
wp_increase_content_media_count( 3 );
},
'expected' => array(
- 'loading' => 'lazy',
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
),
- 'message' => 'Lazy-loading not applied to during shortcode rendering.',
+ 'message' => 'Lazy-loading or decoding not applied to during shortcode rendering.',
),
'shortcode_image_outside_of_the_loop_are_loaded_lazy' => array(
'setup' => function () {
@@ -5227,9 +5374,10 @@ public function data_wp_get_loading_optimization_attributes_in_shortcodes() {
return;
},
'expected' => array(
- 'loading' => 'lazy',
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
),
- 'message' => 'Lazy-loading not applied to shortcodes outside the loop.',
+ 'message' => 'Lazy-loading or decoding not applied to shortcodes outside the loop.',
),
);
}
@@ -5326,7 +5474,10 @@ public function data_wp_maybe_add_fetchpriority_high_attr() {
'high',
),
'image with loading=lazy' => array(
- array( 'loading' => 'lazy' ),
+ array(
+ 'loading' => 'lazy',
+ 'decoding' => 'async',
+ ),
'img',
$this->get_width_height_for_high_priority(),
false,
@@ -5463,7 +5614,7 @@ static function ( $loading_attrs ) {
$attr = $this->get_width_height_for_high_priority();
- $this->assertSame(
+ $this->assertSameSetsWithIndex(
array( 'fetchpriority' => 'high' ),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
'The filter did not return early fetchpriority attribute'
@@ -5472,8 +5623,11 @@ static function ( $loading_attrs ) {
// Clean up the filter.
add_filter( 'pre_wp_get_loading_optimization_attributes', '__return_false' );
- $this->assertSameSets(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
'The filter did not return the default attributes.'
);
@@ -5481,7 +5635,7 @@ static function ( $loading_attrs ) {
// Return no loading attributes.
add_filter( 'pre_wp_get_loading_optimization_attributes', '__return_empty_array' );
- $this->assertSameSets(
+ $this->assertSameSetsWithIndex(
array(),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
'The filter did not clean up all attributes.'
@@ -5503,7 +5657,7 @@ static function ( $loading_attrs ) {
1
);
- $this->assertSameSets(
+ $this->assertSameSetsWithIndex(
array( 'custom_attr' => 'custom_value' ),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
'The filter did not return custom attributes.'
@@ -5518,8 +5672,11 @@ static function ( $loading_attrs ) {
public function test_wp_get_loading_optimization_attributes_filter() {
$attr = $this->get_width_height_for_high_priority();
- $this->assertSameSets(
- array( 'loading' => 'lazy' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'loading' => 'lazy',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
'Before the filter it will not return the loading attribute.'
);
@@ -5536,8 +5693,11 @@ static function ( $loading_attrs ) {
1
);
- $this->assertSameSets(
- array( 'fetchpriority' => 'high' ),
+ $this->assertSameSetsWithIndex(
+ array(
+ 'decoding' => 'async',
+ 'fetchpriority' => 'high',
+ ),
wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
'After the filter it will not return the fetchpriority attribute.'
);
diff --git a/tests/phpunit/tests/media/wpImageTagAddDecodingAttr.php b/tests/phpunit/tests/media/wpImageTagAddDecodingAttr.php
index 7011d816da1ab..15e1859084a03 100644
--- a/tests/phpunit/tests/media/wpImageTagAddDecodingAttr.php
+++ b/tests/phpunit/tests/media/wpImageTagAddDecodingAttr.php
@@ -19,6 +19,8 @@ class Tests_Media_Wp_Img_Tag_Add_Decoding_Attr extends WP_UnitTestCase {
* @param string $context Additional context to pass to the filters.
* @param string $decoding The value for the 'decoding' attribute. 'no value' for default.
* @param string $expected The expected `img` tag.
+ *
+ * @expectedDeprecated wp_img_tag_add_decoding_attr
*/
public function test_should_add_decoding_attr( $image, $context, $decoding, $expected ) {
// Falsey values are allowed in the filter, cannot use `null` or `false` here.
@@ -80,6 +82,8 @@ public function data_should_add_decoding_attr() {
* @param string $context Additional context to pass to the filters.
* @param mixed $decoding The value for the 'decoding' attribute. 'no value' for default.
* @param string $expected The expected `img` tag.
+ *
+ * @expectedDeprecated wp_img_tag_add_decoding_attr
*/
public function test_should_not_add_decoding_attr( $image, $context, $decoding, $expected ) {
// Falsey values are allowed in the filter, cannot use `null` or `false` here.