Make WordPress Core


Ignore:
Timestamp:
04/08/2020 12:53:18 AM (4 years ago)
Author:
azaozz
Message:

Media: Enable lazy-loading of images by automatically adding the new loading="lazy" attribute to image tags on the front-end.

  • Introduces wp_lazy_loading_enabled(), wp_filter_content_tags(), wp_img_tag_add_loading_attr(), and wp_img_tag_add_srcset_and_sizes_attr() functions.
  • Introduces wp_lazy_loading_enabled, wp_img_tag_add_loading_attr, and wp_img_tag_add_srcset_and_sizes_attr filters.

Props flixos90, addyosmani, mor10, swissspidy, pierlo, westonruter, spacedmonkey, mikeschroder, jonoaldersonwp, peterwilsoncc, narwen, jeffpaul, OptimizingMatters, futtta, mukeshpanchal27, azaozz.

Fixes #44427.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/media.php

    r47122 r47554  
    13331333    function test_wp_get_attachment_image_defaults() {
    13341334        $image    = image_downsize( self::$large_id, 'thumbnail' );
    1335         $expected = sprintf( '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="" />', $image[1], $image[2], $image[0] );
     1335        $expected = sprintf( '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="" loading="lazy" />', $image[1], $image[2], $image[0] );
    13361336
    13371337        $this->assertEquals( $expected, wp_get_attachment_image( self::$large_id ) );
     
    13481348
    13491349        $image    = image_downsize( self::$large_id, 'thumbnail' );
    1350         $expected = sprintf( '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="Some very clever alt text" />', $image[1], $image[2], $image[0] );
     1350        $expected = sprintf( '<img width="%1$d" height="%2$d" src="%3$s" class="attachment-thumbnail size-thumbnail" alt="Some very clever alt text" loading="lazy" />', $image[1], $image[2], $image[0] );
    13511351
    13521352        $this->assertEquals( $expected, wp_get_attachment_image( self::$large_id ) );
     
    19651965     * @ticket 33641
    19661966     */
    1967     function test_wp_make_content_images_responsive() {
     1967    function test_wp_filter_content_tags() {
    19681968        $image_meta = wp_get_attachment_metadata( self::$large_id );
    19691969        $size_array = $this->_get_image_size_array_from_meta( $image_meta, 'medium' );
     
    19741974        // Function used to build HTML for the editor.
    19751975        $img                  = get_image_tag( self::$large_id, '', '', '', 'medium' );
     1976        $img                  = wp_img_tag_add_loading_attr( $img, 'test' );
    19761977        $img_no_size_in_class = str_replace( 'size-', '', $img );
    19771978        $img_no_width_height  = str_replace( ' width="' . $size_array[0] . '"', '', $img );
     
    20152016        $content_filtered   = sprintf( $content, $respimg, $respimg_no_size_in_class, $respimg_no_width_height, $img_no_size_id, $respimg_with_sizes_attr, $respimg_xhtml, $respimg_html5 );
    20162017
    2017         $this->assertSame( $content_filtered, wp_make_content_images_responsive( $content_unfiltered ) );
     2018        $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) );
    20182019    }
    20192020
     
    20292030     * @ticket 33641
    20302031     */
    2031     function test_wp_make_content_images_responsive_wrong() {
    2032         $image = get_image_tag( self::$large_id, '', '', '', 'medium' );
     2032    function test_wp_filter_content_tags_wrong() {
     2033        $img = get_image_tag( self::$large_id, '', '', '', 'medium' );
     2034        $img = wp_img_tag_add_loading_attr( $img, 'test' );
    20332035
    20342036        // Replace the src URL.
    2035         $image_wrong_src = preg_replace( '|src="[^"]+"|', 'src="http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/foo.jpg"', $image );
    2036 
    2037         $this->assertSame( $image_wrong_src, wp_make_content_images_responsive( $image_wrong_src ) );
     2037        $image_wrong_src = preg_replace( '|src="[^"]+"|', 'src="http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/foo.jpg"', $img );
     2038
     2039        $this->assertSame( $image_wrong_src, wp_filter_content_tags( $image_wrong_src ) );
    20382040    }
    20392041
     
    20412043     * @ticket 33641
    20422044     */
    2043     function test_wp_make_content_images_responsive_with_preexisting_srcset() {
     2045    function test_wp_filter_content_tags_with_preexisting_srcset() {
    20442046        // Generate HTML and add a dummy srcset attribute.
    2045         $image_html = get_image_tag( self::$large_id, '', '', '', 'medium' );
    2046         $image_html = preg_replace( '|<img ([^>]+) />|', '<img $1 ' . 'srcset="image2x.jpg 2x" />', $image_html );
     2047        $img = get_image_tag( self::$large_id, '', '', '', 'medium' );
     2048        $img = wp_img_tag_add_loading_attr( $img, 'test' );
     2049        $img = preg_replace( '|<img ([^>]+) />|', '<img $1 ' . 'srcset="image2x.jpg 2x" />', $img );
    20472050
    20482051        // The content filter should return the image unchanged.
    2049         $this->assertSame( $image_html, wp_make_content_images_responsive( $image_html ) );
     2052        $this->assertSame( $img, wp_filter_content_tags( $img ) );
    20502053    }
    20512054
     
    20982101     * @ticket 33641
    20992102     */
    2100     function test_wp_make_content_images_responsive_schemes() {
     2103    function test_wp_filter_content_tags_schemes() {
    21012104        $image_meta = wp_get_attachment_metadata( self::$large_id );
    21022105        $size_array = $this->_get_image_size_array_from_meta( $image_meta, 'medium' );
     
    21072110        // Build HTML for the editor.
    21082111        $img          = get_image_tag( self::$large_id, '', '', '', 'medium' );
     2112        $img          = wp_img_tag_add_loading_attr( $img, 'test' );
    21092113        $img_https    = str_replace( 'http://', 'https://', $img );
    21102114        $img_relative = str_replace( 'http://', '//', $img );
     
    21272131        $unfiltered = sprintf( $content, $img, $img_https, $img_relative );
    21282132        $expected   = sprintf( $content, $respimg, $respimg_https, $respimg_relative );
    2129         $actual     = wp_make_content_images_responsive( $unfiltered );
     2133        $actual     = wp_filter_content_tags( $unfiltered );
    21302134
    21312135        $this->assertSame( $expected, $actual );
     
    22612265
    22622266        $expected = '<img width="999" height="999" src="http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/' . $year . '/' . $month . '/test-image-testsize-999x999.png"' .
    2263             ' class="attachment-testsize size-testsize" alt=""' .
     2267            ' class="attachment-testsize size-testsize" alt="" loading="lazy"' .
    22642268            ' srcset="http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/' . $year . '/' . $month . '/test-image-testsize-999x999.png 999w,' .
    22652269                ' http://' . WP_TESTS_DOMAIN . '/wp-content/uploads/' . $year . '/' . $month . '/test-image-large-150x150.png 150w"' .
     
    25242528        $this->assertSame( $expected, $url );
    25252529    }
     2530
     2531    /**
     2532     * @ticket 44427
     2533     */
     2534    function test_wp_lazy_load_content_media() {
     2535        $img       = get_image_tag( self::$large_id, '', '', '', 'medium' );
     2536        $img_xhtml = str_replace( ' />', '/>', $img );
     2537        $img_html5 = str_replace( ' />', '>', $img );
     2538        $iframe    = '<iframe src="https://www.example.com"></iframe>';
     2539
     2540        $lazy_img       = wp_img_tag_add_loading_attr( $img, 'test' );
     2541        $lazy_img_xhtml = wp_img_tag_add_loading_attr( $img_xhtml, 'test' );
     2542        $lazy_img_html5 = wp_img_tag_add_loading_attr( $img_html5, 'test' );
     2543
     2544        // The following should not be modified because there already is a 'loading' attribute.
     2545        $img_eager = str_replace( ' />', ' loading="eager" />', $img );
     2546
     2547        $content = '
     2548            <p>Image, standard.</p>
     2549            %1$s
     2550            <p>Image, XHTML 1.0 style (no space before the closing slash).</p>
     2551            %2$s
     2552            <p>Image, HTML 5.0 style.</p>
     2553            %3$s
     2554            <p>Image, with pre-existing "loading" attribute.</p>
     2555            %5$s
     2556            <p>Iframe, standard. Should not be modified.</p>
     2557            %4$s';
     2558
     2559        $content_unfiltered = sprintf( $content, $img, $img_xhtml, $img_html5, $iframe, $img_eager );
     2560        $content_filtered   = sprintf( $content, $lazy_img, $lazy_img_xhtml, $lazy_img_html5, $iframe, $img_eager );
     2561
     2562        // Do not add srcset and sizes.
     2563        add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     2564
     2565        $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) );
     2566
     2567        remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     2568    }
     2569
     2570    /**
     2571     * @ticket 44427
     2572     */
     2573    function test_wp_lazy_load_content_media_opted_in() {
     2574        $img      = get_image_tag( self::$large_id, '', '', '', 'medium' );
     2575        $lazy_img = wp_img_tag_add_loading_attr( $img, 'test' );
     2576
     2577        $content = '
     2578            <p>Image, standard.</p>
     2579            %1$s';
     2580
     2581        $content_unfiltered = sprintf( $content, $img );
     2582        $content_filtered   = sprintf( $content, $lazy_img );
     2583
     2584        // Do not add srcset and sizes while testing.
     2585        add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     2586
     2587        // Enable globally for all tags.
     2588        add_filter( 'wp_lazy_loading_enabled', '__return_true' );
     2589
     2590        $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) );
     2591        remove_filter( 'wp_lazy_loading_enabled', '__return_true' );
     2592        remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     2593    }
     2594
     2595    /**
     2596     * @ticket 44427
     2597     */
     2598    function test_wp_lazy_load_content_media_opted_out() {
     2599        $img = get_image_tag( self::$large_id, '', '', '', 'medium' );
     2600
     2601        $content = '
     2602            <p>Image, standard.</p>
     2603            %1$s';
     2604        $content = sprintf( $content, $img );
     2605
     2606        // Do not add srcset and sizes while testing.
     2607        add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     2608
     2609        // Disable globally for all tags.
     2610        add_filter( 'wp_lazy_loading_enabled', '__return_false' );
     2611
     2612        $this->assertSame( $content, wp_filter_content_tags( $content ) );
     2613        remove_filter( 'wp_lazy_loading_enabled', '__return_false' );
     2614        remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
     2615    }
     2616
     2617    /**
     2618     * @ticket 44427
     2619     */
     2620    function test_wp_img_tag_add_loading_attr_single_quote() {
     2621        $img = "<img src='example.png' alt='' width='300' height='225' />";
     2622        $img = wp_img_tag_add_loading_attr( $img, 'test' );
     2623
     2624        $this->assertContains( " loading='lazy'", $img );
     2625    }
    25262626}
    25272627
Note: See TracChangeset for help on using the changeset viewer.