diff --git src/wp-includes/media.php src/wp-includes/media.php
index b3204c2799..60a0d046f5 100644
|
|
function wp_get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = f |
1077 | 1077 | } |
1078 | 1078 | } |
1079 | 1079 | |
| 1080 | $attr['decoding'] = 'async'; |
| 1081 | |
1080 | 1082 | /** |
1081 | 1083 | * Filters the list of attachment image attributes. |
1082 | 1084 | * |
… |
… |
function wp_filter_content_tags( $content, $context = null ) { |
1843 | 1845 | $filtered_image = wp_img_tag_add_loading_attr( $filtered_image, $context ); |
1844 | 1846 | } |
1845 | 1847 | |
| 1848 | // Add 'decoding=async' attribute unless a 'decoding' attribute is already present. |
| 1849 | if ( false === strpos( $filtered_image, ' decoding=' ) ) { |
| 1850 | $filtered_image = wp_img_tag_add_decoding_async_attr( $filtered_image ); |
| 1851 | } |
| 1852 | |
1846 | 1853 | if ( $filtered_image !== $match[0] ) { |
1847 | 1854 | $content = str_replace( $match[0], $filtered_image, $content ); |
1848 | 1855 | } |
… |
… |
function wp_img_tag_add_loading_attr( $image, $context ) { |
1911 | 1918 | return $image; |
1912 | 1919 | } |
1913 | 1920 | |
| 1921 | /** |
| 1922 | * Adds `decoding=async` attribute to an `img` HTML tag. |
| 1923 | * |
| 1924 | * @since 6.0.0 |
| 1925 | * |
| 1926 | * @param string $image The HTML `img` tag where the attribute should be added. |
| 1927 | * @return string Converted `img` tag with `decoding=async` attribute added. |
| 1928 | */ |
| 1929 | function wp_img_tag_add_decoding_async_attr( $image ) { |
| 1930 | return str_replace( '<img ', '<img decoding="async" ', $image ); |
| 1931 | } |
| 1932 | |
1914 | 1933 | /** |
1915 | 1934 | * Adds `width` and `height` attributes to an `img` HTML tag. |
1916 | 1935 | * |
diff --git src/wp-includes/pluggable.php src/wp-includes/pluggable.php
index fdbfdea250..de4ced9bd9 100644
|
|
if ( ! function_exists( 'get_avatar' ) ) : |
2694 | 2694 | 'force_display' => false, |
2695 | 2695 | 'loading' => null, |
2696 | 2696 | 'extra_attr' => '', |
| 2697 | 'decoding' => 'async', |
2697 | 2698 | ); |
2698 | 2699 | |
2699 | 2700 | if ( wp_lazy_loading_enabled( 'img', 'get_avatar' ) ) { |
… |
… |
if ( ! function_exists( 'get_avatar' ) ) : |
2781 | 2782 | $extra_attr .= "loading='{$loading}'"; |
2782 | 2783 | } |
2783 | 2784 | |
| 2785 | if ( isset( $args['decoding'] ) && in_array( $args['decoding'], array( 'async', 'sync', 'auto' ) ) && ! preg_match( '/\bdecoding\s*=/', $extra_attr ) ) { |
| 2786 | if ( ! empty( $extra_attr ) ) { |
| 2787 | $extra_attr .= ' '; |
| 2788 | } |
| 2789 | $extra_attr .= "decoding='{$args['decoding']}'"; |
| 2790 | } |
| 2791 | |
2784 | 2792 | $avatar = sprintf( |
2785 | 2793 | "<img alt='%s' src='%s' srcset='%s' class='%s' height='%d' width='%d' %s/>", |
2786 | 2794 | esc_attr( $args['alt'] ), |
diff --git tests/phpunit/tests/media.php tests/phpunit/tests/media.php
index 5d92d9718b..4f6f4db36b 100644
|
|
EOF; |
1474 | 1474 | public function test_wp_get_attachment_image_defaults() { |
1475 | 1475 | $image = image_downsize( self::$large_id, 'thumbnail' ); |
1476 | 1476 | $expected = sprintf( |
1477 | | '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" />', |
| 1477 | '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" decoding="async" />', |
1478 | 1478 | $image[1], |
1479 | 1479 | $image[2], |
1480 | 1480 | $image[0] |
… |
… |
EOF; |
1512 | 1512 | |
1513 | 1513 | $image = image_downsize( self::$large_id, 'thumbnail' ); |
1514 | 1514 | $expected = sprintf( |
1515 | | '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="Some very clever alt text" loading="lazy" />', |
| 1515 | '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="Some very clever alt text" loading="lazy" decoding="async" />', |
1516 | 1516 | $image[1], |
1517 | 1517 | $image[2], |
1518 | 1518 | $image[0] |
… |
… |
EOF; |
2248 | 2248 | $respimg_xhtml, |
2249 | 2249 | $respimg_html5 |
2250 | 2250 | ); |
| 2251 | $content_filtered = wp_img_tag_add_decoding_async_attr( $content_filtered ); |
2251 | 2252 | |
2252 | 2253 | // Do not add width, height, and loading. |
2253 | 2254 | add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); |
… |
… |
EOF; |
2273 | 2274 | public function test_wp_filter_content_tags_srcset_sizes_wrong() { |
2274 | 2275 | $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); |
2275 | 2276 | $img = wp_img_tag_add_loading_attr( $img, 'test' ); |
| 2277 | $img = wp_img_tag_add_decoding_async_attr( $img ); |
2276 | 2278 | |
2277 | 2279 | // Replace the src URL. |
2278 | 2280 | $image_wrong_src = preg_replace( '|src="[^"]+"|', 'src="http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/foo.jpg"', $img ); |
… |
… |
EOF; |
2287 | 2289 | // Generate HTML and add a dummy srcset attribute. |
2288 | 2290 | $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); |
2289 | 2291 | $img = wp_img_tag_add_loading_attr( $img, 'test' ); |
| 2292 | $img = wp_img_tag_add_decoding_async_attr( $img ); |
2290 | 2293 | $img = preg_replace( '|<img ([^>]+) />|', '<img $1 ' . 'srcset="image2x.jpg 2x" />', $img ); |
2291 | 2294 | |
2292 | 2295 | // The content filter should return the image unchanged. |
… |
… |
EOF; |
2383 | 2386 | $respimg_https, |
2384 | 2387 | $respimg_relative |
2385 | 2388 | ); |
| 2389 | $expected = wp_img_tag_add_decoding_async_attr( $expected ); |
2386 | 2390 | |
2387 | 2391 | $actual = wp_filter_content_tags( $unfiltered ); |
2388 | 2392 | |
… |
… |
EOF; |
2527 | 2531 | 'src="' . $uploads_url . 'test-image-testsize-999x999.jpg" ' . |
2528 | 2532 | 'class="attachment-testsize size-testsize" alt="" loading="lazy" ' . |
2529 | 2533 | 'srcset="' . $uploads_url . 'test-image-testsize-999x999.jpg 999w, ' . $uploads_url . $basename . '-150x150.jpg 150w" ' . |
2530 | | 'sizes="(max-width: 999px) 100vw, 999px" />'; |
| 2534 | 'sizes="(max-width: 999px) 100vw, 999px" decoding="async" />'; |
2531 | 2535 | |
2532 | 2536 | $actual = wp_get_attachment_image( self::$large_id, 'testsize' ); |
2533 | 2537 | |
… |
… |
EOF; |
2832 | 2836 | %4$s'; |
2833 | 2837 | |
2834 | 2838 | $content_unfiltered = sprintf( $content, $img, $img_no_width_height, $img_no_width, $img_no_height ); |
2835 | | $content_filtered = sprintf( $content, $img, $respimg_no_width_height, $img_no_width, $img_no_height ); |
| 2839 | $content_filtered = wp_img_tag_add_decoding_async_attr( sprintf( $content, $img, $respimg_no_width_height, $img_no_width, $img_no_height ) ); |
2836 | 2840 | |
2837 | 2841 | // Do not add loading, srcset, and sizes. |
2838 | 2842 | add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); |
… |
… |
EOF; |
2890 | 2894 | %8$s'; |
2891 | 2895 | |
2892 | 2896 | $content_unfiltered = sprintf( $content, $img, $img_xhtml, $img_html5, $img_eager, $img_no_width_height, $iframe, $iframe_eager, $iframe_no_width_height ); |
2893 | | $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 ); |
| 2897 | $content_filtered = wp_img_tag_add_decoding_async_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 ) ); |
2894 | 2898 | |
2895 | 2899 | // Do not add width, height, srcset, and sizes. |
2896 | 2900 | add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); |
… |
… |
EOF; |
2919 | 2923 | %2$s'; |
2920 | 2924 | |
2921 | 2925 | $content_unfiltered = sprintf( $content, $img, $iframe ); |
2922 | | $content_filtered = sprintf( $content, $lazy_img, $lazy_iframe ); |
| 2926 | $content_filtered = sprintf( $content, wp_img_tag_add_decoding_async_attr( $lazy_img ), $lazy_iframe ); |
2923 | 2927 | |
2924 | 2928 | // Do not add srcset and sizes while testing. |
2925 | 2929 | add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); |
… |
… |
EOF; |
2937 | 2941 | * @ticket 50756 |
2938 | 2942 | */ |
2939 | 2943 | public function test_wp_filter_content_tags_loading_lazy_opted_out() { |
2940 | | $img = get_image_tag( self::$large_id, '', '', '', 'medium' ); |
| 2944 | $img = wp_img_tag_add_decoding_async_attr( get_image_tag( self::$large_id, '', '', '', 'medium' ) ); |
2941 | 2945 | $iframe = '<iframe src="https://www.example.com" width="640" height="360"></iframe>'; |
2942 | 2946 | |
2943 | 2947 | $content = ' |
… |
… |
EOF; |
3401 | 3405 | |
3402 | 3406 | // Following the threshold of 2, the first two content media elements should not be lazy-loaded. |
3403 | 3407 | $content_unfiltered = $img1 . $iframe1 . $img2 . $img3 . $iframe2; |
3404 | | $content_expected = $img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2; |
| 3408 | $content_expected = wp_img_tag_add_decoding_async_attr( $img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2 ); |
3405 | 3409 | |
3406 | 3410 | $wp_query = new WP_Query( array( 'post__in' => array( self::$post_ids['publish'] ) ) ); |
3407 | 3411 | $wp_the_query = $wp_query; |
diff --git tests/phpunit/tests/media/getAdjacentImageLink.php tests/phpunit/tests/media/getAdjacentImageLink.php
index 735c0ff15c..1c4133d6e7 100644
|
|
class Tests_Media_GetAdjacentImageLink extends WP_Test_Adjacent_Image_Link_TestC |
32 | 32 | 'when has previous link' => array( |
33 | 33 | 'current_attachment_index' => 3, |
34 | 34 | 'expected_attachment_index' => 2, |
35 | | '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>', |
| 35 | '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="" loading="lazy" decoding="async" /></a>', |
36 | 36 | ), |
37 | 37 | 'with text when has previous link' => array( |
38 | 38 | 'current_attachment_index' => 3, |
… |
… |
class Tests_Media_GetAdjacentImageLink extends WP_Test_Adjacent_Image_Link_TestC |
43 | 43 | 'when has next link' => array( |
44 | 44 | 'current_attachment_index' => 4, |
45 | 45 | 'expected_attachment_index' => 5, |
46 | | '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>', |
| 46 | '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="" loading="lazy" decoding="async" /></a>', |
47 | 47 | 'args' => array( 'prev' => false ), |
48 | 48 | ), |
49 | 49 | 'with text when has next link' => array( |
diff --git tests/phpunit/tests/media/getNextImageLink.php tests/phpunit/tests/media/getNextImageLink.php
index 86a843cbfc..88ee51a434 100644
|
|
class Tests_Media_GetNextImageLink extends WP_Test_Adjacent_Image_Link_TestCase |
31 | 31 | 'when has next link' => array( |
32 | 32 | 'current_attachment_index' => 4, |
33 | 33 | 'expected_attachment_index' => 5, |
34 | | '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>', |
| 34 | '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="" loading="lazy" decoding="async" /></a>', |
35 | 35 | ), |
36 | 36 | 'with text when has next link' => array( |
37 | 37 | 'current_attachment_index' => 4, |
diff --git tests/phpunit/tests/media/getPreviousImageLink.php tests/phpunit/tests/media/getPreviousImageLink.php
index 2d2d511e4f..d0eba54295 100644
|
|
class Tests_Media_GetPreviousImageLink extends WP_Test_Adjacent_Image_Link_TestC |
31 | 31 | 'when has previous link' => array( |
32 | 32 | 'current_attachment_index' => 3, |
33 | 33 | 'expected_attachment_index' => 2, |
34 | | '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>', |
| 34 | '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="" loading="lazy" decoding="async" /></a>', |
35 | 35 | ), |
36 | 36 | 'with text when has previous link' => array( |
37 | 37 | 'current_attachment_index' => 3, |
diff --git tests/phpunit/tests/media/nextImageLink.php tests/phpunit/tests/media/nextImageLink.php
index 7799779fa8..f6da4605ca 100644
|
|
class Tests_Media_NextImageLink extends WP_Test_Adjacent_Image_Link_TestCase { |
30 | 30 | 'when has next link' => array( |
31 | 31 | 'current_attachment_index' => 4, |
32 | 32 | 'expected_attachment_index' => 5, |
33 | | '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>', |
| 33 | '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="" loading="lazy" decoding="async" /></a>', |
34 | 34 | ), |
35 | 35 | 'with text when has next link' => array( |
36 | 36 | 'current_attachment_index' => 4, |
diff --git tests/phpunit/tests/media/previousImageLink.php tests/phpunit/tests/media/previousImageLink.php
index 11d6583d6a..de422e0379 100644
|
|
class Tests_Media_PreviousImageLink extends WP_Test_Adjacent_Image_Link_TestCase |
30 | 30 | 'when has previous link' => array( |
31 | 31 | 'current_attachment_index' => 3, |
32 | 32 | 'expected_attachment_index' => 2, |
33 | | '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>', |
| 33 | '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="" loading="lazy" decoding="async" /></a>', |
34 | 34 | ), |
35 | 35 | 'with text when has previous link' => array( |
36 | 36 | 'current_attachment_index' => 3, |