Make WordPress Core

Changeset 55318


Ignore:
Timestamp:
02/13/2023 06:32:40 PM (4 years ago)
Author:
flixos90
Message:

Media: Enhance logic to determine LCP image in block themes and avoid lazy-loading it.

[52065] originally introduced the logic to guess the LCP image based on certain heuristics and to not lazy-load that image. However, with the introduction of block themes, that logic was not functioning correctly, resulting in all featured images to be lazy-loaded, regardless of whether it was the LCP image or not.

Together with an update to the core/post-featured-image block included in [55079], this changeset fixes the logic to correctly handle featured images in block themes as well.

Additionally, in combination with an update to the core/template-part block from [55246], this changeset includes an enhancement which uses the benefits of block template parts to avoid lazy-loading images in the header block template part, making the lazy-loading heuristics even more accurate for sites using a block theme.

Props flixos90, adamsilverstein, mamaduka, antonvlasenko, shahidul95, reduanmasud, costdev, mukesh27, ironprogrammer, manfcarlo, robinwpdeveloper, spacedmonkey.
Fixes #56930.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/block-template.php

    r54817 r55318  
    242242        $content = convert_smilies( $content );
    243243        $content = shortcode_unautop( $content );
    244         $content = wp_filter_content_tags( $content );
     244        $content = wp_filter_content_tags( $content, 'template' );
    245245        $content = do_shortcode( $content );
    246246        $content = str_replace( ']]>', ']]>', $content );
  • trunk/src/wp-includes/media.php

    r55251 r55318  
    54455445 */
    54465446function wp_get_loading_attr_default( $context ) {
    5447         // Only elements with 'the_content' or 'the_post_thumbnail' context have special handling.
    5448         if ( 'the_content' !== $context && 'the_post_thumbnail' !== $context ) {
     5447        // Skip lazy-loading for the overall block template, as it is handled more granularly.
     5448        if ( 'template' === $context ) {
     5449                return false;
     5450        }
     5451
     5452        // Do not lazy-load images in the header block template part, as they are likely above the fold.
     5453        $header_area = WP_TEMPLATE_PART_AREA_HEADER;
     5454        if ( "template_part_{$header_area}" === $context ) {
     5455                return false;
     5456        }
     5457
     5458        /*
     5459         * The first elements in 'the_content' or 'the_post_thumbnail' should not be lazy-loaded,
     5460         * as they are likely above the fold.
     5461         */
     5462        if ( 'the_content' === $context || 'the_post_thumbnail' === $context ) {
     5463                // Only elements within the main query loop have special handling.
     5464                if ( is_admin() || ! in_the_loop() || ! is_main_query() ) {
     5465                        return 'lazy';
     5466                }
     5467
     5468                // Increase the counter since this is a main query content element.
     5469                $content_media_count = wp_increase_content_media_count();
     5470
     5471                // If the count so far is below the threshold, return `false` so that the `loading` attribute is omitted.
     5472                if ( $content_media_count <= wp_omit_loading_attr_threshold() ) {
     5473                        return false;
     5474                }
     5475
     5476                // For elements after the threshold, lazy-load them as usual.
    54495477                return 'lazy';
    54505478        }
    54515479
    5452         // Only elements within the main query loop have special handling.
    5453         if ( is_admin() || ! in_the_loop() || ! is_main_query() ) {
    5454                 return 'lazy';
    5455         }
    5456 
    5457         // Increase the counter since this is a main query content element.
    5458         $content_media_count = wp_increase_content_media_count();
    5459 
    5460         // If the count so far is below the threshold, return `false` so that the `loading` attribute is omitted.
    5461         if ( $content_media_count <= wp_omit_loading_attr_threshold() ) {
    5462                 return false;
    5463         }
    5464 
    5465         // For elements after the threshold, lazy-load them as usual.
     5480        // Lazy-load by default for any unknown context.
    54665481        return 'lazy';
    54675482}
  • trunk/tests/phpunit/tests/media.php

    r55278 r55318  
    35483548
    35493549        /**
     3550         * Tests that wp_get_loading_attr_default() returns the expected loading attribute value.
     3551         *
    35503552         * @ticket 53675
     3553         * @ticket 56930
     3554         *
     3555         * @covers ::wp_get_loading_attr_default
     3556         *
    35513557         * @dataProvider data_wp_get_loading_attr_default
    35523558         *
     
    35893595                        $this->assertSame( 'lazy', wp_get_loading_attr_default( $context ) );
    35903596                }
     3597
     3598                // Exceptions: In the following contexts, images shouldn't be lazy-loaded by default.
     3599                $this->assertFalse( wp_get_loading_attr_default( 'template' ), 'Images run through the overall block template filter should not be lazy-loaded.' );
     3600                $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.' );
    35913601        }
    35923602
     
    37013711        }
    37023712
     3713        /**
     3714         * Tests that wp_filter_content_tags() does not add loading="lazy" to the first
     3715         * image in the loop when using a block theme.
     3716         *
     3717         * @ticket 56930
     3718         *
     3719         * @covers ::wp_filter_content_tags
     3720         * @covers ::wp_get_loading_attr_default
     3721         */
     3722        public function test_wp_filter_content_tags_does_not_lazy_load_first_image_in_block_theme() {
     3723                global $_wp_current_template_content, $wp_query, $wp_the_query, $post;
     3724
     3725                // Do not add srcset, sizes, or decoding attributes as they are irrelevant for this test.
     3726                add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     3727                add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
     3728
     3729                $img1      = get_image_tag( self::$large_id, '', '', '', 'large' );
     3730                $img2      = get_image_tag( self::$large_id, '', '', '', 'medium' );
     3731                $lazy_img2 = wp_img_tag_add_loading_attr( $img2, 'the_content' );
     3732
     3733                // Only the second image should be lazy-loaded.
     3734                $post_content     = $img1 . $img2;
     3735                $expected_content = wpautop( $img1 . $lazy_img2 );
     3736
     3737                // Update the post to test with so that it has the above post content.
     3738                wp_update_post(
     3739                        array(
     3740                                'ID'                    => self::$post_ids['publish'],
     3741                                'post_content'          => $post_content,
     3742                                'post_content_filtered' => $post_content,
     3743                        )
     3744                );
     3745
     3746                $wp_query     = new WP_Query( array( 'p' => self::$post_ids['publish'] ) );
     3747                $wp_the_query = $wp_query;
     3748                $post         = get_post( self::$post_ids['publish'] );
     3749                $this->reset_content_media_count();
     3750                $this->reset_omit_loading_attr_filter();
     3751
     3752                $_wp_current_template_content = '<!-- wp:post-content /-->';
     3753
     3754                $html = get_the_block_template_html();
     3755                $this->assertSame( '<div class="wp-site-blocks"><div class="entry-content wp-block-post-content is-layout-flow">' . $expected_content . '</div></div>', $html );
     3756        }
     3757
     3758        /**
     3759         * Tests that wp_filter_content_tags() does not add loading="lazy"
     3760         * to the featured image when using a block theme.
     3761         *
     3762         * @ticket 56930
     3763         *
     3764         * @covers ::wp_filter_content_tags
     3765         * @covers ::wp_get_loading_attr_default
     3766         */
     3767        public function test_wp_filter_content_tags_does_not_lazy_load_first_featured_image_in_block_theme() {
     3768                global $_wp_current_template_content, $wp_query, $wp_the_query, $post;
     3769
     3770                // Do not add srcset, sizes, or decoding attributes as they are irrelevant for this test.
     3771                add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     3772                add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
     3773                add_filter(
     3774                        'wp_get_attachment_image_attributes',
     3775                        function( $attr ) {
     3776                                unset( $attr['srcset'], $attr['sizes'], $attr['decoding'] );
     3777                                return $attr;
     3778                        }
     3779                );
     3780
     3781                $content_img      = get_image_tag( self::$large_id, '', '', '', 'large' );
     3782                $lazy_content_img = wp_img_tag_add_loading_attr( $content_img, 'the_content' );
     3783
     3784                // The featured image should not be lazy-loaded as it is the first image.
     3785                $featured_image_id = self::$large_id;
     3786                update_post_meta( self::$post_ids['publish'], '_thumbnail_id', $featured_image_id );
     3787                $expected_featured_image = '<figure class="wp-block-post-featured-image">' . get_the_post_thumbnail( self::$post_ids['publish'], 'post-thumbnail', array( 'loading' => false ) ) . '</figure>';
     3788
     3789                // The post content image should be lazy-loaded since the featured image appears above.
     3790                $post_content     = $content_img;
     3791                $expected_content = wpautop( $lazy_content_img );
     3792
     3793                // Update the post to test with so that it has the above post content.
     3794                wp_update_post(
     3795                        array(
     3796                                'ID'                    => self::$post_ids['publish'],
     3797                                'post_content'          => $post_content,
     3798                                'post_content_filtered' => $post_content,
     3799                        )
     3800                );
     3801
     3802                $wp_query     = new WP_Query( array( 'p' => self::$post_ids['publish'] ) );
     3803                $wp_the_query = $wp_query;
     3804                $post         = get_post( self::$post_ids['publish'] );
     3805                $this->reset_content_media_count();
     3806                $this->reset_omit_loading_attr_filter();
     3807
     3808                $_wp_current_template_content = '<!-- wp:post-featured-image /--> <!-- wp:post-content /-->';
     3809
     3810                $html = get_the_block_template_html();
     3811                $this->assertSame( '<div class="wp-site-blocks">' . $expected_featured_image . ' <div class="entry-content wp-block-post-content is-layout-flow">' . $expected_content . '</div></div>', $html );
     3812        }
     3813
     3814        /**
     3815         * Tests that wp_filter_content_tags() does not add loading="lazy" to images
     3816         * in a "Header" template part.
     3817         *
     3818         * @ticket 56930
     3819         *
     3820         * @covers ::wp_filter_content_tags
     3821         * @covers ::wp_get_loading_attr_default
     3822         */
     3823        public function test_wp_filter_content_tags_does_not_lazy_load_images_in_header() {
     3824                global $_wp_current_template_content;
     3825
     3826                // Do not add srcset, sizes, or decoding attributes as they are irrelevant for this test.
     3827                add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     3828                add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' );
     3829
     3830                // Use a single image for each header and footer template parts.
     3831                $header_img = get_image_tag( self::$large_id, '', '', '', 'large' );
     3832                $footer_img = get_image_tag( self::$large_id, '', '', '', 'medium' );
     3833
     3834                // Create header and footer template parts.
     3835                $header_post_id = self::factory()->post->create(
     3836                        array(
     3837                                'post_type'    => 'wp_template_part',
     3838                                'post_status'  => 'publish',
     3839                                'post_name'    => 'header',
     3840                                'post_content' => $header_img,
     3841                        )
     3842                );
     3843                wp_set_post_terms( $header_post_id, WP_TEMPLATE_PART_AREA_HEADER, 'wp_template_part_area' );
     3844                wp_set_post_terms( $header_post_id, get_stylesheet(), 'wp_theme' );
     3845                $footer_post_id = self::factory()->post->create(
     3846                        array(
     3847                                'post_type'    => 'wp_template_part',
     3848                                'post_status'  => 'publish',
     3849                                'post_name'    => 'footer',
     3850                                'post_content' => $footer_img,
     3851                        )
     3852                );
     3853                wp_set_post_terms( $footer_post_id, WP_TEMPLATE_PART_AREA_FOOTER, 'wp_template_part_area' );
     3854                wp_set_post_terms( $footer_post_id, get_stylesheet(), 'wp_theme' );
     3855
     3856                $_wp_current_template_content = '<!-- wp:template-part {"slug":"header","theme":"' . get_stylesheet() . '","tagName":"header"} /--><!-- wp:template-part {"slug":"footer","theme":"' . get_stylesheet() . '","tagName":"footer"} /-->';
     3857
     3858                // Header image should not be lazy-loaded, footer image should be lazy-loaded.
     3859                $expected_template_content  = '<header class="wp-block-template-part">' . $header_img . '</header>';
     3860                $expected_template_content .= '<footer class="wp-block-template-part">' . wp_img_tag_add_loading_attr( $footer_img, 'force-lazy' ) . '</footer>';
     3861
     3862                $html = get_the_block_template_html();
     3863                $this->assertSame( '<div class="wp-site-blocks">' . $expected_template_content . '</div>', $html );
     3864        }
     3865
    37033866        private function reset_content_media_count() {
    37043867                // Get current value without increasing.
Note: See TracChangeset for help on using the changeset viewer.