diff --git src/wp-includes/media.php src/wp-includes/media.php
index 2b46167afc..25c939b629 100644
--- src/wp-includes/media.php
+++ src/wp-includes/media.php
@@ -1011,16 +1011,18 @@ function wp_get_attachment_image_src( $attachment_id, $size = 'thumbnail', $icon
  * @param string|array $attr {
  *     Optional. Attributes for the image markup.
  *
- *     @type string       $src     Image attachment URL.
- *     @type string       $class   CSS class name or space-separated list of classes.
- *                                 Default `attachment-$size_class size-$size_class`,
- *                                 where `$size_class` is the image size being requested.
- *     @type string       $alt     Image description for the alt attribute.
- *     @type string       $srcset  The 'srcset' attribute value.
- *     @type string       $sizes   The 'sizes' attribute value.
- *     @type string|false $loading The 'loading' attribute value. Passing a value of false
- *                                 will result in the attribute being omitted for the image.
- *                                 Defaults to 'lazy', depending on wp_lazy_loading_enabled().
+ *     @type string       $src      Image attachment URL.
+ *     @type string       $class    CSS class name or space-separated list of classes.
+ *                                  Default `attachment-$size_class size-$size_class`,
+ *                                  where `$size_class` is the image size being requested.
+ *     @type string       $alt      Image description for the alt attribute.
+ *     @type string       $srcset   The 'srcset' attribute value.
+ *     @type string       $sizes    The 'sizes' attribute value.
+ *     @type string|false $loading  The 'loading' attribute value. Passing a value of false
+ *                                  will result in the attribute being omitted for the image.
+ *                                  Defaults to 'lazy', depending on wp_lazy_loading_enabled().
+ *     @type string       $decoding The 'decoding' attribute value. Possible values are
+ *                                  'async' (default), 'sync', or 'auto'.
  * }
  * @return string HTML img element or empty string on failure.
  */
@@ -1040,9 +1042,10 @@ 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 ) ) ),
+			'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',
 		);
 
 		// Add `loading` attribute.
@@ -1843,6 +1846,11 @@ function wp_filter_content_tags( $content, $context = null ) {
 				$filtered_image = wp_img_tag_add_loading_attr( $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.
 			 *
@@ -1934,6 +1942,46 @@ function wp_img_tag_add_loading_attr( $image, $context ) {
 	return $image;
 }
 
+/**
+ * Add `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.0.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 ) {
+	/**
+	 * Filters the `decoding` attribute value to add to an image. Default `async`.
+	 *
+	 * Returning a falsey value will omit the attribute.
+	 *
+	 * @since 6.0.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.
  *
diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php
index fdbfdea250..71e3079cc7 100644
--- src/wp-includes/pluggable.php
+++ src/wp-includes/pluggable.php
@@ -2694,6 +2694,7 @@ if ( ! function_exists( 'get_avatar' ) ) :
 			'force_display' => false,
 			'loading'       => null,
 			'extra_attr'    => '',
+			'decoding'      => 'async',
 		);
 
 		if ( wp_lazy_loading_enabled( 'img', 'get_avatar' ) ) {
@@ -2781,6 +2782,13 @@ if ( ! function_exists( 'get_avatar' ) ) :
 			$extra_attr .= "loading='{$loading}'";
 		}
 
+		if ( in_array( $args['decoding'], array( 'async', 'sync', 'auto' ) ) && ! preg_match( '/\bdecoding\s*=/', $extra_attr ) ) {
+			if ( ! empty( $extra_attr ) ) {
+				$extra_attr .= ' ';
+			}
+			$extra_attr .= "decoding='{$args['decoding']}'";
+		}
+
 		$avatar = sprintf(
 			"<img alt='%s' src='%s' srcset='%s' class='%s' height='%d' width='%d' %s/>",
 			esc_attr( $args['alt'] ),
diff --git tests/phpunit/tests/avatar.php tests/phpunit/tests/avatar.php
index 336ab611e2..026809b4a1 100644
--- tests/phpunit/tests/avatar.php
+++ tests/phpunit/tests/avatar.php
@@ -169,7 +169,7 @@ class Tests_Avatar extends WP_UnitTestCase {
 
 	public function test_get_avatar() {
 		$img = get_avatar( 1 );
-		$this->assertSame( preg_match( "|^<img alt='[^']*' src='[^']*' srcset='[^']*' class='[^']*' height='[^']*' width='[^']*' loading='lazy'/>$|", $img ), 1 );
+		$this->assertSame( preg_match( "|^<img alt='[^']*' src='[^']*' srcset='[^']*' class='[^']*' height='[^']*' width='[^']*' loading='lazy' decoding='async'/>$|", $img ), 1 );
 	}
 
 	public function test_get_avatar_size() {
diff --git tests/phpunit/tests/media.php tests/phpunit/tests/media.php
index 8f3340aaf7..0f3f581196 100644
--- tests/phpunit/tests/media.php
+++ tests/phpunit/tests/media.php
@@ -1474,7 +1474,7 @@ EOF;
 	public function test_wp_get_attachment_image_defaults() {
 		$image    = image_downsize( self::$large_id, 'thumbnail' );
 		$expected = sprintf(
-			'<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" />',
+			'<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="" decoding="async" loading="lazy" />',
 			$image[1],
 			$image[2],
 			$image[0]
@@ -1512,7 +1512,7 @@ EOF;
 
 		$image    = image_downsize( self::$large_id, 'thumbnail' );
 		$expected = sprintf(
-			'<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="Some very clever alt text" loading="lazy" />',
+			'<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="Some very clever alt text" decoding="async" loading="lazy" />',
 			$image[1],
 			$image[2],
 			$image[0]
@@ -2248,6 +2248,7 @@ EOF;
 			$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' );
@@ -2273,6 +2274,7 @@ EOF;
 	public function test_wp_filter_content_tags_srcset_sizes_wrong() {
 		$img = get_image_tag( self::$large_id, '', '', '', 'medium' );
 		$img = wp_img_tag_add_loading_attr( $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 );
@@ -2287,6 +2289,7 @@ EOF;
 		// Generate HTML and add a dummy srcset attribute.
 		$img = get_image_tag( self::$large_id, '', '', '', 'medium' );
 		$img = wp_img_tag_add_loading_attr( $img, 'test' );
+		$img = wp_img_tag_add_decoding_attr( $img, 'the_content' );
 		$img = preg_replace( '|<img ([^>]+) />|', '<img $1 ' . 'srcset="image2x.jpg 2x" />', $img );
 
 		// The content filter should return the image unchanged.
@@ -2334,7 +2337,7 @@ EOF;
 	 */
 	public function test_wp_filter_content_tags_filter_with_identical_image_tags_custom_attributes() {
 		$img     = get_image_tag( self::$large_id, '', '', '', 'large' );
-		$img     = str_replace( '<img ', '<img srcset="custom" sizes="custom" loading="custom" ', $img );
+		$img     = str_replace( '<img ', '<img srcset="custom" sizes="custom" loading="custom" decoding="custom"', $img );
 		$content = "$img\n$img";
 
 		add_filter(
@@ -2359,6 +2362,7 @@ EOF;
 		add_filter( 'wp_img_tag_add_loading_attr', '__return_false' );
 		add_filter( 'wp_img_tag_add_width_and_height_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' );
 
 		add_filter(
 			'wp_content_img_tag',
@@ -2461,6 +2465,7 @@ EOF;
 			$respimg_https,
 			$respimg_relative
 		);
+		$expected = wp_img_tag_add_decoding_attr( $expected, 'the_content' );
 
 		$actual = wp_filter_content_tags( $unfiltered );
 
@@ -2603,7 +2608,7 @@ EOF;
 
 		$expected = '<img width="999" height="999" ' .
 			'src="' . $uploads_url . 'test-image-testsize-999x999.jpg" ' .
-			'class="attachment-testsize size-testsize" alt="" loading="lazy" ' .
+			'class="attachment-testsize size-testsize" alt="" decoding="async" loading="lazy" ' .
 			'srcset="' . $uploads_url . 'test-image-testsize-999x999.jpg 999w, ' . $uploads_url . $basename . '-150x150.jpg 150w" ' .
 			'sizes="(max-width: 999px) 100vw, 999px" />';
 
@@ -2910,7 +2915,7 @@ EOF;
 			%4$s';
 
 		$content_unfiltered = sprintf( $content, $img, $img_no_width_height, $img_no_width, $img_no_height );
-		$content_filtered   = sprintf( $content, $img, $respimg_no_width_height, $img_no_width, $img_no_height );
+		$content_filtered   = wp_img_tag_add_decoding_attr( sprintf( $content, $img, $respimg_no_width_height, $img_no_width, $img_no_height ), 'the_content' );
 
 		// Do not add loading, srcset, and sizes.
 		add_filter( 'wp_img_tag_add_loading_attr', '__return_false' );
@@ -2968,7 +2973,7 @@ EOF;
 			%8$s';
 
 		$content_unfiltered = sprintf( $content, $img, $img_xhtml, $img_html5, $img_eager, $img_no_width_height, $iframe, $iframe_eager, $iframe_no_width_height );
-		$content_filtered   = sprintf( $content, $lazy_img, $lazy_img_xhtml, $lazy_img_html5, $img_eager, $img_no_width_height, $lazy_iframe, $iframe_eager, $iframe_no_width_height );
+		$content_filtered   = wp_img_tag_add_decoding_attr( sprintf( $content, $lazy_img, $lazy_img_xhtml, $lazy_img_html5, $img_eager, $img_no_width_height, $lazy_iframe, $iframe_eager, $iframe_no_width_height ), 'the_content' );
 
 		// Do not add width, height, srcset, and sizes.
 		add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' );
@@ -2997,7 +3002,7 @@ EOF;
 			%2$s';
 
 		$content_unfiltered = sprintf( $content, $img, $iframe );
-		$content_filtered   = sprintf( $content, $lazy_img, $lazy_iframe );
+		$content_filtered   = sprintf( $content, wp_img_tag_add_decoding_attr( $lazy_img, 'the_content' ), $lazy_iframe, 'the_content' );
 
 		// Do not add srcset and sizes while testing.
 		add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
@@ -3015,7 +3020,7 @@ EOF;
 	 * @ticket 50756
 	 */
 	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( get_image_tag( self::$large_id, '', '', '', 'medium' ), 'the_content' );
 		$iframe = '<iframe src="https://www.example.com" width="640" height="360"></iframe>';
 
 		$content = '
@@ -3479,7 +3484,7 @@ EOF;
 
 		// 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   = $img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2;
+		$content_expected   = wp_img_tag_add_decoding_attr( $img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2, 'the_content' );
 
 		$wp_query     = new WP_Query( array( 'post__in' => array( self::$post_ids['publish'] ) ) );
 		$wp_the_query = $wp_query;
diff --git tests/phpunit/tests/media/getAdjacentImageLink.php tests/phpunit/tests/media/getAdjacentImageLink.php
index 735c0ff15c..7f413cab2e 100644
--- tests/phpunit/tests/media/getAdjacentImageLink.php
+++ tests/phpunit/tests/media/getAdjacentImageLink.php
@@ -32,7 +32,7 @@ class Tests_Media_GetAdjacentImageLink extends WP_Test_Adjacent_Image_Link_TestC
 			'when has previous link'           => array(
 				'current_attachment_index'  => 3,
 				'expected_attachment_index' => 2,
-				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="http://example.org/wp-content/uploads/image2.jpg" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" /></a>',
+				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="' . WP_CONTENT_URL . '/uploads/image2.jpg" class="attachment-thumbnail size-thumbnail" alt="" decoding="async" loading="lazy" /></a>',
 			),
 			'with text when has previous link' => array(
 				'current_attachment_index'  => 3,
@@ -43,7 +43,7 @@ class Tests_Media_GetAdjacentImageLink extends WP_Test_Adjacent_Image_Link_TestC
 			'when has next link'               => array(
 				'current_attachment_index'  => 4,
 				'expected_attachment_index' => 5,
-				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="http://example.org/wp-content/uploads/image5.jpg" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" /></a>',
+				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="' . WP_CONTENT_URL . '/uploads/image5.jpg" class="attachment-thumbnail size-thumbnail" alt="" decoding="async" loading="lazy" /></a>',
 				'args'                      => array( 'prev' => false ),
 			),
 			'with text when has next link'     => array(
diff --git tests/phpunit/tests/media/getNextImageLink.php tests/phpunit/tests/media/getNextImageLink.php
index 86a843cbfc..b26f1fcd69 100644
--- tests/phpunit/tests/media/getNextImageLink.php
+++ tests/phpunit/tests/media/getNextImageLink.php
@@ -31,7 +31,7 @@ class Tests_Media_GetNextImageLink extends WP_Test_Adjacent_Image_Link_TestCase
 			'when has next link'           => array(
 				'current_attachment_index'  => 4,
 				'expected_attachment_index' => 5,
-				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="http://example.org/wp-content/uploads/image5.jpg" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" /></a>',
+				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="' . WP_CONTENT_URL . '/uploads/image5.jpg" class="attachment-thumbnail size-thumbnail" alt="" decoding="async" loading="lazy" /></a>',
 			),
 			'with text when has next link' => array(
 				'current_attachment_index'  => 4,
diff --git tests/phpunit/tests/media/getPreviousImageLink.php tests/phpunit/tests/media/getPreviousImageLink.php
index 2d2d511e4f..36652e75ad 100644
--- tests/phpunit/tests/media/getPreviousImageLink.php
+++ tests/phpunit/tests/media/getPreviousImageLink.php
@@ -31,7 +31,7 @@ class Tests_Media_GetPreviousImageLink extends WP_Test_Adjacent_Image_Link_TestC
 			'when has previous link'           => array(
 				'current_attachment_index'  => 3,
 				'expected_attachment_index' => 2,
-				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="http://example.org/wp-content/uploads/image2.jpg" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" /></a>',
+				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="' . WP_CONTENT_URL . '/uploads/image2.jpg" class="attachment-thumbnail size-thumbnail" alt="" decoding="async" loading="lazy" /></a>',
 			),
 			'with text when has previous link' => array(
 				'current_attachment_index'  => 3,
diff --git tests/phpunit/tests/media/nextImageLink.php tests/phpunit/tests/media/nextImageLink.php
index 7799779fa8..569e1900ce 100644
--- tests/phpunit/tests/media/nextImageLink.php
+++ tests/phpunit/tests/media/nextImageLink.php
@@ -30,7 +30,7 @@ class Tests_Media_NextImageLink extends WP_Test_Adjacent_Image_Link_TestCase {
 			'when has next link'           => array(
 				'current_attachment_index'  => 4,
 				'expected_attachment_index' => 5,
-				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="http://example.org/wp-content/uploads/image5.jpg" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" /></a>',
+				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="' . WP_CONTENT_URL . '/uploads/image5.jpg" class="attachment-thumbnail size-thumbnail" alt="" decoding="async" loading="lazy" /></a>',
 			),
 			'with text when has next link' => array(
 				'current_attachment_index'  => 4,
diff --git tests/phpunit/tests/media/previousImageLink.php tests/phpunit/tests/media/previousImageLink.php
index 11d6583d6a..c75e083537 100644
--- tests/phpunit/tests/media/previousImageLink.php
+++ tests/phpunit/tests/media/previousImageLink.php
@@ -30,7 +30,7 @@ class Tests_Media_PreviousImageLink extends WP_Test_Adjacent_Image_Link_TestCase
 			'when has previous link'           => array(
 				'current_attachment_index'  => 3,
 				'expected_attachment_index' => 2,
-				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="http://example.org/wp-content/uploads/image2.jpg" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" /></a>',
+				'expected'                  => '<a href=\'http://example.org/?attachment_id=%%ID%%\'><img width="1" height="1" src="' . WP_CONTENT_URL . '/uploads/image2.jpg" class="attachment-thumbnail size-thumbnail" alt="" decoding="async" loading="lazy" /></a>',
 			),
 			'with text when has previous link' => array(
 				'current_attachment_index'  => 3,
diff --git tests/phpunit/tests/media/wpImageTagAddDecodingAttr.php tests/phpunit/tests/media/wpImageTagAddDecodingAttr.php
new file mode 100644
index 0000000000..76fa203b7e
--- /dev/null
+++ tests/phpunit/tests/media/wpImageTagAddDecodingAttr.php
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * Tests the `wp_img_tag_add_decoding_attr()` function.
+ *
+ * @group media
+ * @covers ::wp_img_tag_add_decoding_attr
+ */
+class Tests_Media_Wp_Img_Tag_Add_Decoding_Attr extends WP_UnitTestCase {
+	/**
+	 * Tests that the `wp_img_tag_add_decoding_attr()` function should add
+	 * the 'decoding' attribute.
+	 *
+	 * @ticket 53232
+	 *
+	 * @dataProvider data_should_add_decoding_attr
+	 *
+	 * @param string $image    The HTML `img` tag where the attribute should be added.
+	 * @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.
+	 */
+	public function test_should_add_decoding_attr( $image, $context, $decoding, $expected ) {
+		// Falsey values are allowed in the filter, cannot use `null` or `false` here.
+		if ( 'no value' !== $decoding ) {
+			add_filter(
+				'wp_img_tag_add_decoding_attr',
+				static function( $value ) use ( $decoding ) {
+					return $decoding;
+				}
+			);
+		}
+
+		$this->assertSame( $expected, wp_img_tag_add_decoding_attr( $image, $context ) );
+	}
+
+	/**
+	 * Data provider.
+	 *
+	 * @return array
+	 */
+	public function data_should_add_decoding_attr() {
+		return array(
+			'default' => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => 'no value',
+				'expected' => '<img decoding="async" src="my-image.png">',
+			),
+			'async'   => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => 'async',
+				'expected' => '<img decoding="async" src="my-image.png">',
+			),
+			'sync'    => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => 'sync',
+				'expected' => '<img decoding="sync" src="my-image.png">',
+			),
+			'auto'    => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => 'auto',
+				'expected' => '<img decoding="auto" src="my-image.png">',
+			),
+		);
+	}
+
+	/**
+	 * Tests that the `wp_img_tag_add_decoding_attr()` function should not add
+	 * the 'decoding' attribute.
+	 *
+	 * @ticket 53232
+	 *
+	 * @dataProvider data_should_not_add_decoding_attr
+	 *
+	 * @param string $image    The HTML `img` tag where the attribute should be added.
+	 * @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.
+	 */
+	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.
+		if ( 'no value' !== $decoding ) {
+			add_filter(
+				'wp_img_tag_add_decoding_attr',
+				static function( $value ) use ( $decoding ) {
+					return $decoding;
+				}
+			);
+		}
+
+		$this->assertSame( $expected, wp_img_tag_add_decoding_attr( $image, $context, $expected ) );
+	}
+
+	/**
+	 * Data provider.
+	 *
+	 * @return array
+	 */
+	public function data_should_not_add_decoding_attr() {
+		return array(
+			// Unhappy paths.
+			'lazy (unaccepted value)' => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => 'lazy',
+				'expected' => '<img src="my-image.png">',
+			),
+			'a non-string value'      => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => array( 'sync' ),
+				'expected' => '<img src="my-image.png">',
+			),
+
+			// Falsey values.
+			'false'                   => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => false,
+				'expected' => '<img src="my-image.png">',
+			),
+			'null'                    => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => null,
+				'expected' => '<img src="my-image.png">',
+			),
+			'empty string'            => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => '',
+				'expected' => '<img src="my-image.png">',
+			),
+			'empty array'             => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => array(),
+				'expected' => '<img src="my-image.png">',
+			),
+			'0 int'                   => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => 0,
+				'expected' => '<img src="my-image.png">',
+			),
+			'0 string'                => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => '0',
+				'expected' => '<img src="my-image.png">',
+			),
+			'0.0 float'               => array(
+				'image'    => '<img src="my-image.png">',
+				'context'  => '',
+				'decoding' => 0.0,
+				'expected' => '<img src="my-image.png">',
+			),
+		);
+	}
+}
