Changeset 52065
- Timestamp:
- 11/09/2021 12:34:17 AM (3 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/media.php
r51903 r52065 1047 1047 // Add `loading` attribute. 1048 1048 if ( wp_lazy_loading_enabled( 'img', 'wp_get_attachment_image' ) ) { 1049 $default_attr['loading'] = 'lazy';1049 $default_attr['loading'] = wp_get_loading_attr_default( 'wp_get_attachment_image' ); 1050 1050 } 1051 1051 … … 1821 1821 } 1822 1822 1823 foreach ( $images as $image => $attachment_id ) { 1824 $filtered_image = $image; 1825 1826 // Add 'width' and 'height' attributes if applicable. 1827 if ( $attachment_id > 0 && false === strpos( $filtered_image, ' width=' ) && false === strpos( $filtered_image, ' height=' ) ) { 1828 $filtered_image = wp_img_tag_add_width_and_height_attr( $filtered_image, $context, $attachment_id ); 1829 } 1830 1831 // Add 'srcset' and 'sizes' attributes if applicable. 1832 if ( $attachment_id > 0 && false === strpos( $filtered_image, ' srcset=' ) ) { 1833 $filtered_image = wp_img_tag_add_srcset_and_sizes_attr( $filtered_image, $context, $attachment_id ); 1834 } 1835 1836 // Add 'loading' attribute if applicable. 1837 if ( $add_img_loading_attr && false === strpos( $filtered_image, ' loading=' ) ) { 1838 $filtered_image = wp_img_tag_add_loading_attr( $filtered_image, $context ); 1839 } 1840 1841 if ( $filtered_image !== $image ) { 1842 $content = str_replace( $image, $filtered_image, $content ); 1843 } 1844 } 1845 1846 foreach ( $iframes as $iframe => $attachment_id ) { 1847 $filtered_iframe = $iframe; 1848 1849 // Add 'loading' attribute if applicable. 1850 if ( $add_iframe_loading_attr && false === strpos( $filtered_iframe, ' loading=' ) ) { 1851 $filtered_iframe = wp_iframe_tag_add_loading_attr( $filtered_iframe, $context ); 1852 } 1853 1854 if ( $filtered_iframe !== $iframe ) { 1855 $content = str_replace( $iframe, $filtered_iframe, $content ); 1823 // Iterate through the matches in order of occurrence as it is relevant for whether or not to lazy-load. 1824 foreach ( $matches as $match ) { 1825 // Filter an image match. 1826 if ( isset( $images[ $match[0] ] ) ) { 1827 $filtered_image = $match[0]; 1828 $attachment_id = $images[ $match[0] ]; 1829 1830 // Add 'width' and 'height' attributes if applicable. 1831 if ( $attachment_id > 0 && false === strpos( $filtered_image, ' width=' ) && false === strpos( $filtered_image, ' height=' ) ) { 1832 $filtered_image = wp_img_tag_add_width_and_height_attr( $filtered_image, $context, $attachment_id ); 1833 } 1834 1835 // Add 'srcset' and 'sizes' attributes if applicable. 1836 if ( $attachment_id > 0 && false === strpos( $filtered_image, ' srcset=' ) ) { 1837 $filtered_image = wp_img_tag_add_srcset_and_sizes_attr( $filtered_image, $context, $attachment_id ); 1838 } 1839 1840 // Add 'loading' attribute if applicable. 1841 if ( $add_img_loading_attr && false === strpos( $filtered_image, ' loading=' ) ) { 1842 $filtered_image = wp_img_tag_add_loading_attr( $filtered_image, $context ); 1843 } 1844 1845 if ( $filtered_image !== $match[0] ) { 1846 $content = str_replace( $match[0], $filtered_image, $content ); 1847 } 1848 } 1849 1850 // Filter an iframe match. 1851 if ( isset( $iframes[ $match[0] ] ) ) { 1852 $filtered_iframe = $match[0]; 1853 1854 // Add 'loading' attribute if applicable. 1855 if ( $add_iframe_loading_attr && false === strpos( $filtered_iframe, ' loading=' ) ) { 1856 $filtered_iframe = wp_iframe_tag_add_loading_attr( $filtered_iframe, $context ); 1857 } 1858 1859 if ( $filtered_iframe !== $match[0] ) { 1860 $content = str_replace( $match[0], $filtered_iframe, $content ); 1861 } 1856 1862 } 1857 1863 } … … 1870 1876 */ 1871 1877 function wp_img_tag_add_loading_attr( $image, $context ) { 1878 // Get loading attribute value to use. This must occur before the conditional check below so that even images that 1879 // are ineligible for being lazy-loaded are considered. 1880 $value = wp_get_loading_attr_default( $context ); 1881 1872 1882 // Images should have source and dimension attributes for the `loading` attribute to be added. 1873 1883 if ( false === strpos( $image, ' src="' ) || false === strpos( $image, ' width="' ) || false === strpos( $image, ' height="' ) ) { … … 1884 1894 * 1885 1895 * @param string|bool $value The `loading` attribute value. Returning a falsey value will result in 1886 * the attribute being omitted for the image. Default 'lazy'.1896 * the attribute being omitted for the image. 1887 1897 * @param string $image The HTML `img` tag to be filtered. 1888 1898 * @param string $context Additional context about how the function was called or where the img tag is. 1889 1899 */ 1890 $value = apply_filters( 'wp_img_tag_add_loading_attr', 'lazy', $image, $context );1900 $value = apply_filters( 'wp_img_tag_add_loading_attr', $value, $image, $context ); 1891 1901 1892 1902 if ( $value ) { … … 1996 2006 } 1997 2007 2008 // Get loading attribute value to use. This must occur before the conditional check below so that even iframes that 2009 // are ineligible for being lazy-loaded are considered. 2010 $value = wp_get_loading_attr_default( $context ); 2011 1998 2012 // Iframes should have source and dimension attributes for the `loading` attribute to be added. 1999 2013 if ( false === strpos( $iframe, ' src="' ) || false === strpos( $iframe, ' width="' ) || false === strpos( $iframe, ' height="' ) ) { … … 2010 2024 * 2011 2025 * @param string|bool $value The `loading` attribute value. Returning a falsey value will result in 2012 * the attribute being omitted for the iframe. Default 'lazy'.2026 * the attribute being omitted for the iframe. 2013 2027 * @param string $iframe The HTML `iframe` tag to be filtered. 2014 2028 * @param string $context Additional context about how the function was called or where the iframe tag is. 2015 2029 */ 2016 $value = apply_filters( 'wp_iframe_tag_add_loading_attr', 'lazy', $iframe, $context );2030 $value = apply_filters( 'wp_iframe_tag_add_loading_attr', $value, $iframe, $context ); 2017 2031 2018 2032 if ( $value ) { … … 5178 5192 return compact( 'width', 'height', 'type' ); 5179 5193 } 5194 5195 /** 5196 * Gets the default value to use for a `loading` attribute on an element. 5197 * 5198 * This function should only be called for a tag and context if lazy-loading is generally enabled. 5199 * 5200 * The function usually returns 'lazy', but uses certain heuristics to guess whether the current element is likely to 5201 * appear above the fold, in which case it returns a boolean `false`, which will lead to the `loading` attribute being 5202 * omitted on the element. The purpose of this refinement is to avoid lazy-loading elements that are within the initial 5203 * viewport, which can have a negative performance impact. 5204 * 5205 * Under the hood, the function uses {@see wp_increase_content_media_count()} every time it is called for an element 5206 * within the main content. If the element is the very first content element, the `loading` attribute will be omitted. 5207 * This default threshold of 1 content element to omit the `loading` attribute for can be customized using the 5208 * {@see 'wp_omit_loading_attr_threshold'} filter. 5209 * 5210 * @since 5.9.0 5211 * 5212 * @param string $context Context for the element for which the `loading` attribute value is requested. 5213 * @return string|bool The default `loading` attribute value. Either 'lazy', 'eager', or a boolean `false`, to indicate 5214 * that the `loading` attribute should be skipped. 5215 */ 5216 function wp_get_loading_attr_default( $context ) { 5217 // Only elements with 'the_content' or 'the_post_thumbnail' context have special handling. 5218 if ( 'the_content' !== $context && 'the_post_thumbnail' !== $context ) { 5219 return 'lazy'; 5220 } 5221 5222 // Only elements within the main query loop have special handling. 5223 if ( is_admin() || ! in_the_loop() || ! is_main_query() ) { 5224 return 'lazy'; 5225 } 5226 5227 // Increase the counter since this is a main query content element. 5228 $content_media_count = wp_increase_content_media_count(); 5229 5230 // If the count so far is below the threshold, return `false` so that the `loading` attribute is omitted. 5231 if ( $content_media_count <= wp_omit_loading_attr_threshold() ) { 5232 return false; 5233 } 5234 5235 // For elements after the threshold, lazy-load them as usual. 5236 return 'lazy'; 5237 } 5238 5239 /** 5240 * Gets the threshold for how many of the first content media elements to not lazy-load. 5241 * 5242 * This function runs the {@see 'wp_omit_loading_attr_threshold'} filter, which uses a default threshold value of 1. 5243 * The filter is only run once per page load, unless the `$force` parameter is used. 5244 * 5245 * @since 5.9.0 5246 * 5247 * @param bool $force Optional. If set to true, the filter will be (re-)applied even if it already has been before. 5248 * Default false. 5249 * @return int The number of content media elements to not lazy-load. 5250 */ 5251 function wp_omit_loading_attr_threshold( $force = false ) { 5252 static $omit_threshold; 5253 5254 // This function may be called multiple times. Run the filter only once per page load. 5255 if ( ! isset( $omit_threshold ) || $force ) { 5256 /** 5257 * Filters the threshold for how many of the first content media elements to not lazy-load. 5258 * 5259 * For these first content media elements, the `loading` attribute will be omitted. By default, this is the case 5260 * for only the very first content media element. 5261 * 5262 * @since 5.9.0 5263 * 5264 * @param int $omit_threshold The number of media elements where the `loading` attribute will not be added. Default 1. 5265 */ 5266 $omit_threshold = apply_filters( 'wp_omit_loading_attr_threshold', 1 ); 5267 } 5268 5269 return $omit_threshold; 5270 } 5271 5272 /** 5273 * Increases an internal content media count variable. 5274 * 5275 * @since 5.9.0 5276 * @access private 5277 * 5278 * @param int $amount Optional. Amount to increase by. Default 1. 5279 * @return int The latest content media count, after the increase. 5280 */ 5281 function wp_increase_content_media_count( $amount = 1 ) { 5282 static $content_media_count = 0; 5283 5284 $content_media_count += $amount; 5285 5286 return $content_media_count; 5287 } -
trunk/src/wp-includes/pluggable.php
r51301 r52065 2679 2679 2680 2680 if ( wp_lazy_loading_enabled( 'img', 'get_avatar' ) ) { 2681 $defaults['loading'] = 'lazy';2681 $defaults['loading'] = wp_get_loading_attr_default( 'get_avatar' ); 2682 2682 } 2683 2683 -
trunk/src/wp-includes/post-thumbnail-template.php
r52028 r52065 187 187 } 188 188 189 // Get the 'loading' attribute value to use as default, taking precedence over the default from 190 // `wp_get_attachment_image()`. 191 $loading = wp_get_loading_attr_default( 'the_post_thumbnail' ); 192 193 // Add the default to the given attributes unless they already include a 'loading' directive. 194 if ( empty( $attr ) ) { 195 $attr = array( 'loading' => $loading ); 196 } elseif ( is_array( $attr ) && ! array_key_exists( 'loading', $attr ) ) { 197 $attr['loading'] = $loading; 198 } elseif ( is_string( $attr ) && ! preg_match( '/(^|&)loading=', $attr ) ) { 199 $attr .= '&loading=' . $loading; 200 } 201 189 202 $html = wp_get_attachment_image( $post_thumbnail_id, $size, false, $attr ); 190 203 -
trunk/tests/phpunit/tests/media.php
r52010 r52065 3025 3025 * @ticket 50425 3026 3026 * @ticket 53463 3027 * @ticket 53675 3027 3028 * @dataProvider data_wp_lazy_loading_enabled_context_defaults 3028 3029 * … … 3047 3048 'get_avatar => true' => array( 'get_avatar', true ), 3048 3049 'arbitrary context => true' => array( 'something_completely_arbitrary', true ), 3050 'the_post_thumbnail => true' => array( 'the_post_thumbnail', true ), 3049 3051 ); 3050 3052 } … … 3187 3189 ); 3188 3190 } 3191 3192 /** 3193 * @ticket 53675 3194 * @dataProvider data_wp_get_loading_attr_default 3195 * 3196 * @param string $context 3197 */ 3198 function test_wp_get_loading_attr_default( $context ) { 3199 global $wp_query, $wp_the_query; 3200 3201 // Return 'lazy' by default. 3202 $this->assertSame( 'lazy', wp_get_loading_attr_default( 'test' ) ); 3203 $this->assertSame( 'lazy', wp_get_loading_attr_default( 'wp_get_attachment_image' ) ); 3204 3205 // Return 'lazy' if not in the loop or the main query. 3206 $this->assertSame( 'lazy', wp_get_loading_attr_default( $context ) ); 3207 3208 $wp_query = new WP_Query( array( 'post__in' => array( self::$post_ids['publish'] ) ) ); 3209 $this->reset_content_media_count(); 3210 $this->reset_omit_loading_attr_filter(); 3211 3212 while ( have_posts() ) { 3213 the_post(); 3214 3215 // Return 'lazy' if in the loop but not in the main query. 3216 $this->assertSame( 'lazy', wp_get_loading_attr_default( $context ) ); 3217 3218 // Set as main query. 3219 $wp_the_query = $wp_query; 3220 3221 // For contexts other than for the main content, still return 'lazy' even in the loop 3222 // and in the main query, and do not increase the content media count. 3223 $this->assertSame( 'lazy', wp_get_loading_attr_default( 'wp_get_attachment_image' ) ); 3224 3225 // Return `false` if in the loop and in the main query and it is the first element. 3226 $this->assertFalse( wp_get_loading_attr_default( $context ) ); 3227 3228 // Return 'lazy' if in the loop and in the main query for any subsequent elements. 3229 $this->assertSame( 'lazy', wp_get_loading_attr_default( $context ) ); 3230 3231 // Yes, for all subsequent elements. 3232 $this->assertSame( 'lazy', wp_get_loading_attr_default( $context ) ); 3233 } 3234 } 3235 3236 function data_wp_get_loading_attr_default() { 3237 return array( 3238 array( 'the_content' ), 3239 array( 'the_post_thumbnail' ), 3240 ); 3241 } 3242 3243 /** 3244 * @ticket 53675 3245 */ 3246 function test_wp_omit_loading_attr_threshold_filter() { 3247 global $wp_query, $wp_the_query; 3248 3249 $wp_query = new WP_Query( array( 'post__in' => array( self::$post_ids['publish'] ) ) ); 3250 $wp_the_query = $wp_query; 3251 $this->reset_content_media_count(); 3252 $this->reset_omit_loading_attr_filter(); 3253 3254 // Use the filter to alter the threshold for not lazy-loading to the first three elements. 3255 add_filter( 3256 'wp_omit_loading_attr_threshold', 3257 function() { 3258 return 3; 3259 } 3260 ); 3261 3262 while ( have_posts() ) { 3263 the_post(); 3264 3265 // Due to the filter, now the first three elements should not be lazy-loaded, i.e. return `false`. 3266 for ( $i = 0; $i < 3; $i++ ) { 3267 $this->assertFalse( wp_get_loading_attr_default( 'the_content' ) ); 3268 } 3269 3270 // For following elements, lazy-load them again. 3271 $this->assertSame( 'lazy', wp_get_loading_attr_default( 'the_content' ) ); 3272 } 3273 } 3274 3275 /** 3276 * @ticket 53675 3277 */ 3278 function test_wp_filter_content_tags_with_wp_get_loading_attr_default() { 3279 global $wp_query, $wp_the_query; 3280 3281 $img1 = get_image_tag( self::$large_id, '', '', '', 'large' ); 3282 $iframe1 = '<iframe src="https://www.example.com" width="640" height="360"></iframe>'; 3283 $img2 = get_image_tag( self::$large_id, '', '', '', 'medium' ); 3284 $img3 = get_image_tag( self::$large_id, '', '', '', 'thumbnail' ); 3285 $iframe2 = '<iframe src="https://wordpress.org" width="640" height="360"></iframe>'; 3286 $lazy_img2 = wp_img_tag_add_loading_attr( $img2, 'the_content' ); 3287 $lazy_img3 = wp_img_tag_add_loading_attr( $img3, 'the_content' ); 3288 $lazy_iframe2 = wp_iframe_tag_add_loading_attr( $iframe2, 'the_content' ); 3289 3290 // Use a threshold of 2. 3291 add_filter( 3292 'wp_omit_loading_attr_threshold', 3293 function() { 3294 return 2; 3295 } 3296 ); 3297 3298 // Following the threshold of 2, the first two content media elements should not be lazy-loaded. 3299 $content_unfiltered = $img1 . $iframe1 . $img2 . $img3 . $iframe2; 3300 $content_expected = $img1 . $iframe1 . $lazy_img2 . $lazy_img3 . $lazy_iframe2; 3301 3302 $wp_query = new WP_Query( array( 'post__in' => array( self::$post_ids['publish'] ) ) ); 3303 $wp_the_query = $wp_query; 3304 $this->reset_content_media_count(); 3305 $this->reset_omit_loading_attr_filter(); 3306 3307 while ( have_posts() ) { 3308 the_post(); 3309 3310 add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 3311 $content_filtered = wp_filter_content_tags( $content_unfiltered, 'the_content' ); 3312 remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 3313 } 3314 3315 // After filtering, the first image should not be lazy-loaded while the other ones should be. 3316 $this->assertSame( $content_expected, $content_filtered ); 3317 } 3318 3319 /** 3320 * @ticket 53675 3321 */ 3322 public function test_wp_omit_loading_attr_threshold() { 3323 $this->reset_omit_loading_attr_filter(); 3324 3325 // Apply filter, ensure default value of 1. 3326 $omit_threshold = wp_omit_loading_attr_threshold(); 3327 $this->assertSame( 1, $omit_threshold ); 3328 3329 // Add a filter that changes the value to 3. However, the filter is not applied a subsequent time in a single 3330 // page load by default, so the value is still 1. 3331 add_filter( 3332 'wp_omit_loading_attr_threshold', 3333 function() { 3334 return 3; 3335 } 3336 ); 3337 $omit_threshold = wp_omit_loading_attr_threshold(); 3338 $this->assertSame( 1, $omit_threshold ); 3339 3340 // Only by enforcing a fresh check, the filter gets re-applied. 3341 $omit_threshold = wp_omit_loading_attr_threshold( true ); 3342 $this->assertSame( 3, $omit_threshold ); 3343 } 3344 3345 private function reset_content_media_count() { 3346 // Get current value without increasing. 3347 $content_media_count = wp_increase_content_media_count( 0 ); 3348 3349 // Decrease it by its current value to "reset" it back to 0. 3350 wp_increase_content_media_count( - $content_media_count ); 3351 } 3352 3353 private function reset_omit_loading_attr_filter() { 3354 // Add filter to "reset" omit threshold back to null (unset). 3355 add_filter( 'wp_omit_loading_attr_threshold', '__return_null', 100 ); 3356 3357 // Force filter application to re-run. 3358 wp_omit_loading_attr_threshold( true ); 3359 3360 // Clean up the above filter. 3361 remove_filter( 'wp_omit_loading_attr_threshold', '__return_null', 100 ); 3362 } 3189 3363 } 3190 3364
Note: See TracChangeset
for help on using the changeset viewer.