Changeset 59008
- Timestamp:
- 09/10/2024 11:59:54 PM (3 months ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/media.php
r58974 r59008 1138 1138 } 1139 1139 1140 // Adds 'auto' to the sizes attribute if applicable. 1141 if ( 1142 isset( $attr['loading'] ) && 1143 'lazy' === $attr['loading'] && 1144 isset( $attr['sizes'] ) && 1145 ! wp_sizes_attribute_includes_valid_auto( $attr['sizes'] ) 1146 ) { 1147 $attr['sizes'] = 'auto, ' . $attr['sizes']; 1148 } 1149 1140 1150 /** 1141 1151 * Filters the list of attachment image attributes. … … 1918 1928 $filtered_image = wp_img_tag_add_loading_optimization_attrs( $filtered_image, $context ); 1919 1929 1930 // Adds 'auto' to the sizes attribute if applicable. 1931 $filtered_image = wp_img_tag_add_auto_sizes( $filtered_image ); 1932 1920 1933 /** 1921 1934 * Filters an img tag within the content for a given context. … … 1962 1975 1963 1976 return $content; 1977 } 1978 1979 /** 1980 * Adds 'auto' to the sizes attribute to the image, if the image is lazy loaded and does not already include it. 1981 * 1982 * @since 6.7.0 1983 * 1984 * @param string $image The image tag markup being filtered. 1985 * @return string The filtered image tag markup. 1986 */ 1987 function wp_img_tag_add_auto_sizes( string $image ): string { 1988 $processor = new WP_HTML_Tag_Processor( $image ); 1989 1990 // Bail if there is no IMG tag. 1991 if ( ! $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) { 1992 return $image; 1993 } 1994 1995 // Bail early if the image is not lazy-loaded. 1996 $value = $processor->get_attribute( 'loading' ); 1997 if ( ! is_string( $value ) || 'lazy' !== strtolower( trim( $value, " \t\f\r\n" ) ) ) { 1998 return $image; 1999 } 2000 2001 $sizes = $processor->get_attribute( 'sizes' ); 2002 2003 // Bail early if the image is not responsive. 2004 if ( ! is_string( $sizes ) ) { 2005 return $image; 2006 } 2007 2008 // Don't add 'auto' to the sizes attribute if it already exists. 2009 if ( wp_sizes_attribute_includes_valid_auto( $sizes ) ) { 2010 return $image; 2011 } 2012 2013 $processor->set_attribute( 'sizes', "auto, $sizes" ); 2014 return $processor->get_updated_html(); 2015 } 2016 2017 /** 2018 * Checks whether the given 'sizes' attribute includes the 'auto' keyword as the first item in the list. 2019 * 2020 * Per the HTML spec, if present it must be the first entry. 2021 * 2022 * @since 6.7.0 2023 * 2024 * @param string $sizes_attr The 'sizes' attribute value. 2025 * @return bool True if the 'auto' keyword is present, false otherwise. 2026 */ 2027 function wp_sizes_attribute_includes_valid_auto( string $sizes_attr ): bool { 2028 list( $first_size ) = explode( ',', $sizes_attr, 2 ); 2029 return 'auto' === strtolower( trim( $first_size, " \t\f\r\n" ) ); 1964 2030 } 1965 2031 -
trunk/tests/phpunit/tests/media.php
r58974 r59008 2468 2468 */ 2469 2469 public function test_wp_filter_content_tags_schemes() { 2470 // Disable lazy loading attribute to not add the 'auto' keyword to the `sizes` attribute. 2471 add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); 2472 2470 2473 $image_meta = wp_get_attachment_metadata( self::$large_id ); 2471 2474 $size_array = $this->get_image_size_array_from_meta( $image_meta, 'medium' ); … … 2681 2684 'class="attachment-testsize size-testsize" alt="" decoding="async" loading="lazy" ' . 2682 2685 'srcset="' . $uploads_url . 'test-image-testsize-999x999.jpg 999w, ' . $uploads_url . $basename . '-150x150.jpg 150w" ' . 2683 'sizes=" (max-width: 999px) 100vw, 999px" />';2686 'sizes="auto, (max-width: 999px) 100vw, 999px" />'; 2684 2687 2685 2688 $actual = wp_get_attachment_image( self::$large_id, 'testsize' ); … … 5117 5120 } 5118 5121 ); 5122 5123 // Do not calculate sizes attribute as it is irrelevant for this test. 5124 add_filter( 'wp_calculate_image_sizes', '__return_false' ); 5119 5125 5120 5126 // Add shortcode that prints a large image, and a block type that wraps it. … … 6030 6036 6031 6037 /** 6038 * Test generated markup for an image with lazy loading gets auto-sizes. 6039 * 6040 * @ticket 61847 6041 */ 6042 public function test_image_with_lazy_loading_has_auto_sizes() { 6043 $this->assertStringContainsString( 6044 'sizes="auto, ', 6045 wp_get_attachment_image( self::$large_id, 'large', false, array( 'loading' => 'lazy' ) ), 6046 'Failed asserting that the sizes attribute for a lazy-loaded image includes "auto".' 6047 ); 6048 } 6049 6050 /** 6051 * Test generated markup for an image without lazy loading does not get auto-sizes. 6052 * 6053 * @ticket 61847 6054 */ 6055 public function test_image_without_lazy_loading_does_not_have_auto_sizes() { 6056 $this->assertStringNotContainsString( 6057 'sizes="auto, ', 6058 wp_get_attachment_image( self::$large_id, 'large', false, array( 'loading' => false ) ), 6059 'Failed asserting that the sizes attribute for an image without lazy loading does not include "auto".' 6060 ); 6061 } 6062 6063 /** 6064 * Test content filtered markup with lazy loading gets auto-sizes. 6065 * 6066 * @ticket 61847 6067 * 6068 * @covers ::wp_img_tag_add_auto_sizes 6069 */ 6070 public function test_content_image_with_lazy_loading_has_auto_sizes() { 6071 // Force lazy loading attribute. 6072 add_filter( 'wp_img_tag_add_loading_attr', '__return_true' ); 6073 6074 $this->assertStringContainsString( 6075 'sizes="auto, (max-width: 1024px) 100vw, 1024px"', 6076 wp_filter_content_tags( get_image_tag( self::$large_id, '', '', '', 'large' ) ), 6077 'Failed asserting that the sizes attribute for a content image with lazy loading includes "auto" with the expected sizes.' 6078 ); 6079 } 6080 6081 /** 6082 * Test content filtered markup without lazy loading does not get auto-sizes. 6083 * 6084 * @ticket 61847 6085 * 6086 * @covers ::wp_img_tag_add_auto_sizes 6087 */ 6088 public function test_content_image_without_lazy_loading_does_not_have_auto_sizes() { 6089 // Disable lazy loading attribute. 6090 add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); 6091 6092 $this->assertStringNotContainsString( 6093 'sizes="auto, ', 6094 wp_filter_content_tags( get_image_tag( self::$large_id, '', '', '', 'large' ) ), 6095 'Failed asserting that the sizes attribute for a content image without lazy loading does not include "auto" with the expected sizes.' 6096 ); 6097 } 6098 6099 /** 6100 * Test generated markup for an image with 'auto' keyword already present in sizes does not receive it again. 6101 * 6102 * @ticket 61847 6103 * 6104 * @covers ::wp_img_tag_add_auto_sizes 6105 * @covers ::wp_sizes_attribute_includes_valid_auto 6106 * 6107 * @dataProvider data_image_with_existing_auto_sizes 6108 * 6109 * @param string $initial_sizes The initial sizes attribute to test. 6110 * @param bool $expected_processed Whether the auto sizes should be processed or not. 6111 */ 6112 public function test_image_with_existing_auto_sizes_is_not_processed_again( string $initial_sizes, bool $expected_processed ) { 6113 $image_tag = wp_get_attachment_image( 6114 self::$large_id, 6115 'large', 6116 false, 6117 array( 6118 // Force pre-existing 'sizes' attribute and lazy-loading. 6119 'sizes' => $initial_sizes, 6120 'loading' => 'lazy', 6121 ) 6122 ); 6123 if ( $expected_processed ) { 6124 $this->assertStringContainsString( 6125 'sizes="auto, ' . $initial_sizes . '"', 6126 $image_tag, 6127 'Failed asserting that "auto" keyword is not added to sizes attribute when it already exists.' 6128 ); 6129 } else { 6130 $this->assertStringContainsString( 6131 'sizes="' . $initial_sizes . '"', 6132 $image_tag, 6133 'Failed asserting that "auto" keyword is not added to sizes attribute when it already exists.' 6134 ); 6135 } 6136 } 6137 6138 /** 6139 * Test content filtered markup with 'auto' keyword already present in sizes does not receive it again. 6140 * 6141 * @ticket 61847 6142 * 6143 * @covers ::wp_img_tag_add_auto_sizes 6144 * @covers ::wp_sizes_attribute_includes_valid_auto 6145 * 6146 * @dataProvider data_image_with_existing_auto_sizes 6147 * 6148 * @param string $initial_sizes The initial sizes attribute to test. 6149 * @param bool $expected_processed Whether the auto sizes should be processed or not. 6150 */ 6151 public function test_content_image_with_existing_auto_sizes_is_not_processed_again( string $initial_sizes, bool $expected_processed ) { 6152 // Force lazy loading attribute. 6153 add_filter( 'wp_img_tag_add_loading_attr', '__return_true' ); 6154 6155 add_filter( 6156 'get_image_tag', 6157 static function ( $html ) use ( $initial_sizes ) { 6158 return str_replace( 6159 '" />', 6160 '" sizes="' . $initial_sizes . '" />', 6161 $html 6162 ); 6163 } 6164 ); 6165 6166 $image_content = wp_filter_content_tags( get_image_tag( self::$large_id, '', '', '', 'large' ) ); 6167 if ( $expected_processed ) { 6168 $this->assertStringContainsString( 6169 'sizes="auto, ' . $initial_sizes . '"', 6170 $image_content, 6171 'Failed asserting that "auto" keyword is not added to sizes attribute in filtered content when it already exists.' 6172 ); 6173 } else { 6174 $this->assertStringContainsString( 6175 'sizes="' . $initial_sizes . '"', 6176 $image_content, 6177 'Failed asserting that "auto" keyword is not added to sizes attribute in filtered content when it already exists.' 6178 ); 6179 } 6180 } 6181 6182 /** 6183 * Returns data for the above test methods to assert correct behavior with a pre-existing sizes attribute. 6184 * 6185 * @return array<string, mixed[]> Arguments for the test scenarios. 6186 */ 6187 public function data_image_with_existing_auto_sizes() { 6188 return array( 6189 'not present' => array( 6190 '(max-width: 1024px) 100vw, 1024px', 6191 true, 6192 ), 6193 'in beginning, without space' => array( 6194 'auto,(max-width: 1024px) 100vw, 1024px', 6195 false, 6196 ), 6197 'in beginning, with space' => array( 6198 'auto, (max-width: 1024px) 100vw, 1024px', 6199 false, 6200 ), 6201 'sole keyword' => array( 6202 'auto', 6203 false, 6204 ), 6205 'with space before' => array( 6206 ' auto, (max-width: 1024px) 100vw, 1024px', 6207 false, 6208 ), 6209 'with uppercase' => array( 6210 'AUTO, (max-width: 1024px) 100vw, 1024px', 6211 false, 6212 ), 6213 6214 /* 6215 * The following scenarios technically include the 'auto' keyword, 6216 * but it is in the wrong place, as per the HTML spec it must be 6217 * the first entry in the list. 6218 * Therefore in these invalid cases the 'auto' keyword should still 6219 * be added to the beginning of the list. 6220 */ 6221 'within, without space' => array( 6222 '(max-width: 1024px) 100vw, auto,1024px', 6223 true, 6224 ), 6225 'within, with space' => array( 6226 '(max-width: 1024px) 100vw, auto, 1024px', 6227 true, 6228 ), 6229 'at the end, without space' => array( 6230 '(max-width: 1024px) 100vw,auto', 6231 true, 6232 ), 6233 'at the end, with space' => array( 6234 '(max-width: 1024px) 100vw, auto', 6235 true, 6236 ), 6237 ); 6238 } 6239 6240 /** 6241 * Data provider for test_wp_img_tag_add_auto_sizes(). 6242 * 6243 * @return array<string, mixed> 6244 */ 6245 public function data_provider_to_test_wp_img_tag_add_auto_sizes() { 6246 return array( 6247 'expected_with_single_quoted_attributes' => array( 6248 'input' => "<img src='https://example.com/foo-300x225.jpg' srcset='https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w' sizes='(max-width: 650px) 100vw, 650px' loading='lazy'>", 6249 'expected' => "<img src='https://example.com/foo-300x225.jpg' srcset='https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w' sizes=\"auto, (max-width: 650px) 100vw, 650px\" loading='lazy'>", 6250 ), 6251 'expected_with_data_sizes_attribute' => array( 6252 'input' => '<img data-tshirt-sizes="S M L" src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="(max-width: 650px) 100vw, 650px" loading="lazy">', 6253 'expected' => '<img data-tshirt-sizes="S M L" src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="auto, (max-width: 650px) 100vw, 650px" loading="lazy">', 6254 ), 6255 'expected_with_data_sizes_attribute_already_present' => array( 6256 'input' => '<img data-tshirt-sizes="S M L" src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="AUTO, (max-width: 650px) 100vw, 650px" loading="lazy">', 6257 'expected' => '<img data-tshirt-sizes="S M L" src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="AUTO, (max-width: 650px) 100vw, 650px" loading="lazy">', 6258 ), 6259 'not_expected_with_loading_lazy_in_attr_value' => array( 6260 'input' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="(max-width: 650px) 100vw, 650px" alt=\'This is the LCP image and it should not get loading="lazy"!\'>', 6261 'expected' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="(max-width: 650px) 100vw, 650px" alt=\'This is the LCP image and it should not get loading="lazy"!\'>', 6262 ), 6263 'not_expected_with_data_loading_attribute_present' => array( 6264 'input' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="(max-width: 650px) 100vw, 650px" data-removed-loading="lazy">', 6265 'expected' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="(max-width: 650px) 100vw, 650px" data-removed-loading="lazy">', 6266 ), 6267 'expected_when_attributes_have_spaces_after_them' => array( 6268 'input' => '<img src = "https://example.com/foo-300x225.jpg" srcset = "https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes = "(max-width: 650px) 100vw, 650px" loading = "lazy">', 6269 'expected' => '<img src = "https://example.com/foo-300x225.jpg" srcset = "https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="auto, (max-width: 650px) 100vw, 650px" loading = "lazy">', 6270 ), 6271 'expected_when_attributes_are_upper_case' => array( 6272 'input' => '<IMG SRC="https://example.com/foo-300x225.jpg" SRCSET="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" SIZES="(max-width: 650px) 100vw, 650px" LOADING="LAZY">', 6273 'expected' => '<IMG SRC="https://example.com/foo-300x225.jpg" SRCSET="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="auto, (max-width: 650px) 100vw, 650px" LOADING="LAZY">', 6274 ), 6275 'expected_when_loading_lazy_lacks_quotes' => array( 6276 'input' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="(max-width: 650px) 100vw, 650px" loading=lazy>', 6277 'expected' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="auto, (max-width: 650px) 100vw, 650px" loading=lazy>', 6278 ), 6279 'expected_when_loading_lazy_has_whitespace' => array( 6280 'input' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="(max-width: 650px) 100vw, 650px" loading=" lazy ">', 6281 'expected' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes="auto, (max-width: 650px) 100vw, 650px" loading=" lazy ">', 6282 ), 6283 'not_expected_when_sizes_auto_lacks_quotes' => array( 6284 'input' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes=auto loading="lazy">', 6285 'expected' => '<img src="https://example.com/foo-300x225.jpg" srcset="https://example.com/foo-300x225.jpg 300w, https://example.com/foo-1024x768.jpg 1024w, https://example.com/foo-768x576.jpg 768w, https://example.com/foo-1536x1152.jpg 1536w, https://example.com/foo-2048x1536.jpg 2048w" sizes=auto loading="lazy">', 6286 ), 6287 ); 6288 } 6289 6290 /** 6291 * @ticket 61847 6292 * 6293 * @covers ::wp_img_tag_add_auto_sizes 6294 * 6295 * @dataProvider data_provider_to_test_wp_img_tag_add_auto_sizes 6296 * 6297 * @param string $input The input HTML string. 6298 * @param string $expected The expected output HTML string. 6299 */ 6300 public function test_wp_img_tag_add_auto_sizes( string $input, string $expected ) { 6301 $this->assertSame( 6302 $expected, 6303 wp_img_tag_add_auto_sizes( $input ), 6304 'Failed asserting that "auto" keyword is correctly added or not added to sizes attribute in the image tag.' 6305 ); 6306 } 6307 6308 /** 6032 6309 * Helper method to keep track of the last context returned by the 'wp_get_attachment_image_context' filter. 6033 6310 *
Note: See TracChangeset
for help on using the changeset viewer.