diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 19f3b5fb140ec..4d5742a4b91a1 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -241,7 +241,7 @@ function get_the_block_template_html() { $content = wptexturize( $content ); $content = convert_smilies( $content ); $content = shortcode_unautop( $content ); - $content = wp_filter_content_tags( $content ); + $content = wp_filter_content_tags( $content, 'template' ); $content = do_shortcode( $content ); $content = str_replace( ']]>', ']]>', $content ); diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index 01062855a1da8..95836d98a24b2 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -5444,25 +5444,40 @@ function wp_get_webp_info( $filename ) { * that the `loading` attribute should be skipped. */ function wp_get_loading_attr_default( $context ) { - // Only elements with 'the_content' or 'the_post_thumbnail' context have special handling. - if ( 'the_content' !== $context && 'the_post_thumbnail' !== $context ) { - return 'lazy'; + // Skip lazy-loading for the overall block template, as it is handled more granularly. + if ( 'template' === $context ) { + return false; } - // Only elements within the main query loop have special handling. - if ( is_admin() || ! in_the_loop() || ! is_main_query() ) { - return 'lazy'; + // Do not lazy-load images in the header block template part, as they are likely above the fold. + $header_area = WP_TEMPLATE_PART_AREA_HEADER; + if ( "template_part_{$header_area}" === $context ) { + return false; } - // Increase the counter since this is a main query content element. - $content_media_count = wp_increase_content_media_count(); + /* + * The first elements in 'the_content' or 'the_post_thumbnail' should not be lazy-loaded, + * as they are likely above the fold. + */ + if ( 'the_content' === $context || 'the_post_thumbnail' === $context ) { + // Only elements within the main query loop have special handling. + if ( is_admin() || ! in_the_loop() || ! is_main_query() ) { + return 'lazy'; + } - // If the count so far is below the threshold, return `false` so that the `loading` attribute is omitted. - if ( $content_media_count <= wp_omit_loading_attr_threshold() ) { - return false; + // Increase the counter since this is a main query content element. + $content_media_count = wp_increase_content_media_count(); + + // If the count so far is below the threshold, return `false` so that the `loading` attribute is omitted. + if ( $content_media_count <= wp_omit_loading_attr_threshold() ) { + return false; + } + + // For elements after the threshold, lazy-load them as usual. + return 'lazy'; } - // For elements after the threshold, lazy-load them as usual. + // Lazy-load by default for any unknown context. return 'lazy'; } diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index fb93d781c3054..8e76c43807fcd 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -3547,7 +3547,13 @@ public function data_attachment_permalinks_based_on_parent_status() { } /** + * Tests that wp_get_loading_attr_default() returns the expected loading attribute value. + * * @ticket 53675 + * @ticket 56930 + * + * @covers ::wp_get_loading_attr_default + * * @dataProvider data_wp_get_loading_attr_default * * @param string $context @@ -3588,6 +3594,10 @@ public function test_wp_get_loading_attr_default( $context ) { // Yes, for all subsequent elements. $this->assertSame( 'lazy', wp_get_loading_attr_default( $context ) ); } + + // Exceptions: In the following contexts, images shouldn't be lazy-loaded by default. + $this->assertFalse( wp_get_loading_attr_default( 'template' ), 'Images run through the overall block template filter should not be lazy-loaded.' ); + $this->assertFalse( wp_get_loading_attr_default( 'template_part_' . WP_TEMPLATE_PART_AREA_HEADER ), 'Images in the footer block template part should not be lazy-loaded.' ); } public function data_wp_get_loading_attr_default() { @@ -3700,6 +3710,159 @@ function() { $this->assertSame( 3, $omit_threshold ); } + /** + * Tests that wp_filter_content_tags() does not add loading="lazy" to the first + * image in the loop when using a block theme. + * + * @ticket 56930 + * + * @covers ::wp_filter_content_tags + * @covers ::wp_get_loading_attr_default + */ + public function test_wp_filter_content_tags_does_not_lazy_load_first_image_in_block_theme() { + global $_wp_current_template_content, $wp_query, $wp_the_query, $post; + + // Do not add srcset, sizes, or decoding attributes as they are irrelevant for this test. + add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); + add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' ); + + $img1 = get_image_tag( self::$large_id, '', '', '', 'large' ); + $img2 = get_image_tag( self::$large_id, '', '', '', 'medium' ); + $lazy_img2 = wp_img_tag_add_loading_attr( $img2, 'the_content' ); + + // Only the second image should be lazy-loaded. + $post_content = $img1 . $img2; + $expected_content = wpautop( $img1 . $lazy_img2 ); + + // Update the post to test with so that it has the above post content. + wp_update_post( + array( + 'ID' => self::$post_ids['publish'], + 'post_content' => $post_content, + 'post_content_filtered' => $post_content, + ) + ); + + $wp_query = new WP_Query( array( 'p' => self::$post_ids['publish'] ) ); + $wp_the_query = $wp_query; + $post = get_post( self::$post_ids['publish'] ); + $this->reset_content_media_count(); + $this->reset_omit_loading_attr_filter(); + + $_wp_current_template_content = ''; + + $html = get_the_block_template_html(); + $this->assertSame( '