Make WordPress Core


Ignore:
Timestamp:
12/16/2020 09:17:24 PM (6 years ago)
Author:
flixos90
Message:

Media: Enable lazy-loading of iframes by adding the loading="lazy" attribute to iframe tags on the front-end.

  • Expands the capabilities of wp_filter_content_tags() to add the attribute to iframe tags if enabled.
  • Modifies the default behavior of wp_lazy_loading_enabled() so that it returns true for iframe tags.
  • Introduces a wp_iframe_tag_add_loading_attr() function.
  • Introduces a wp_iframe_tag_add_loading_attr filter.

Like for images, the attribute is only added to iframes which have both width and height specified (see related #50367).

Props azaozz, flixos90, westonruter.
Fixes #50756.

File:
1 edited

Legend:

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

    r49769 r49808  
    17041704 *
    17051705 * @since 5.5.0
     1706 * @since 5.7.0 Now returns `true` by default for `iframe` tags.
    17061707 *
    17071708 * @param string $tag_name The tag name.
    … …  
    17111712 */
    17121713function wp_lazy_loading_enabled( $tag_name, $context ) {
    1713         // By default add to all 'img' tags.
     1714        // By default add to all 'img' and 'iframe' tags.
    17141715        // See https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading
    1715         $default = ( 'img' === $tag_name );
     1716        // See https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-loading
     1717        $default = ( 'img' === $tag_name || 'iframe' === $tag_name );
    17161718
    17171719        /**
    … …  
    17331735 * Modifies HTML tags in post content to include new browser and HTML technologies
    17341736 * that may not have existed at the time of post creation. These modifications currently
    1735  * include adding `srcset`, `sizes`, and `loading` attributes to `img` HTML tags.
     1737 * include adding `srcset`, `sizes`, and `loading` attributes to `img` HTML tags, as well
     1738 * as adding `loading` attributes to `iframe` HTML tags.
    17361739 * Future similar optimizations should be added/expected here.
    17371740 *
    17381741 * @since 5.5.0
     1742 * @since 5.7.0 Now supports adding `loading` attributes to `iframe` tags.
    17391743 *
    17401744 * @see wp_img_tag_add_width_and_height_attr()
    17411745 * @see wp_img_tag_add_srcset_and_sizes_attr()
    17421746 * @see wp_img_tag_add_loading_attr()
     1747 * @see wp_iframe_tag_add_loading_attr()
    17431748 *
    17441749 * @param string $content The HTML content to be filtered.
    … …  
    17521757        }
    17531758
    1754         $add_loading_attr = wp_lazy_loading_enabled( 'img', $context );
    1755 
    1756         if ( false === strpos( $content, '<img' ) ) {
    1757                 return $content;
    1758         }
    1759 
    1760         if ( ! preg_match_all( '/<img\s[^>]+>/', $content, $matches ) ) {
     1759        $add_img_loading_attr    = wp_lazy_loading_enabled( 'img', $context );
     1760        $add_iframe_loading_attr = wp_lazy_loading_enabled( 'iframe', $context );
     1761
     1762        if ( ! preg_match_all( '/<(img|iframe)\s[^>]+>/', $content, $matches, PREG_SET_ORDER ) ) {
    17611763                return $content;
    17621764        }
    … …  
    17651767        $images = array();
    17661768
    1767         foreach ( $matches[0] as $image ) {
    1768                 if ( preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) ) {
    1769                         $attachment_id = absint( $class_id[1] );
    1770 
    1771                         if ( $attachment_id ) {
    1772                                 // If exactly the same image tag is used more than once, overwrite it.
    1773                                 // All identical tags will be replaced later with 'str_replace()'.
    1774                                 $images[ $image ] = $attachment_id;
    1775                                 continue;
    1776                         }
    1777                 }
    1778 
    1779                 $images[ $image ] = 0;
     1769        // List of the unique `iframe` tags found in $content.
     1770        $iframes = array();
     1771
     1772        foreach ( $matches as $match ) {
     1773                list( $tag, $tag_name ) = $match;
     1774
     1775                switch ( $tag_name ) {
     1776                        case 'img':
     1777                                if ( preg_match( '/wp-image-([0-9]+)/i', $tag, $class_id ) ) {
     1778                                        $attachment_id = absint( $class_id[1] );
     1779
     1780                                        if ( $attachment_id ) {
     1781                                                // If exactly the same image tag is used more than once, overwrite it.
     1782                                                // All identical tags will be replaced later with 'str_replace()'.
     1783                                                $images[ $tag ] = $attachment_id;
     1784                                                break;
     1785                                        }
     1786                                }
     1787                                $images[ $tag ] = 0;
     1788                                break;
     1789                        case 'iframe':
     1790                                $iframes[ $tag ] = 0;
     1791                                break;
     1792                }
    17801793        }
    17811794
    … …  
    18051818
    18061819                // Add 'loading' attribute if applicable.
    1807                 if ( $add_loading_attr && false === strpos( $filtered_image, ' loading=' ) ) {
     1820                if ( $add_img_loading_attr && false === strpos( $filtered_image, ' loading=' ) ) {
    18081821                        $filtered_image = wp_img_tag_add_loading_attr( $filtered_image, $context );
    18091822                }
    … …  
    18111824                if ( $filtered_image !== $image ) {
    18121825                        $content = str_replace( $image, $filtered_image, $content );
     1826                }
     1827        }
     1828
     1829        foreach ( $iframes as $iframe => $attachment_id ) {
     1830                $filtered_iframe = $iframe;
     1831
     1832                // Add 'loading' attribute if applicable.
     1833                if ( $add_iframe_loading_attr && false === strpos( $filtered_iframe, ' loading=' ) ) {
     1834                        $filtered_iframe = wp_iframe_tag_add_loading_attr( $filtered_iframe, $context );
     1835                }
     1836
     1837                if ( $filtered_iframe !== $iframe ) {
     1838                        $content = str_replace( $iframe, $filtered_iframe, $content );
    18131839                }
    18141840        }
    … …  
    18281854function wp_img_tag_add_loading_attr( $image, $context ) {
    18291855        /**
    1830          * Filters the `loading` attribute value. Default `lazy`.
     1856         * Filters the `loading` attribute value to add to an image. Default `lazy`.
    18311857         *
    18321858         * Returning `false` or an empty string will not add the attribute.
    … …  
    19351961
    19361962        return $image;
     1963}
     1964
     1965/**
     1966 * Adds `loading` attribute to an `iframe` HTML tag.
     1967 *
     1968 * @since 5.7.0
     1969 *
     1970 * @param string $iframe  The HTML `iframe` tag where the attribute should be added.
     1971 * @param string $context Additional context to pass to the filters.
     1972 * @return string Converted `iframe` tag with `loading` attribute added.
     1973 */
     1974function wp_iframe_tag_add_loading_attr( $iframe, $context ) {
     1975        /**
     1976         * Filters the `loading` attribute value to add to an iframe. Default `lazy`.
     1977         *
     1978         * Returning `false` or an empty string will not add the attribute.
     1979         * Returning `true` will add the default value.
     1980         *
     1981         * @since 5.7.0
     1982         *
     1983         * @param string|bool $value   The `loading` attribute value. Returning a falsey value will result in
     1984         *                             the attribute being omitted for the iframe. Default 'lazy'.
     1985         * @param string      $iframe  The HTML `iframe` tag to be filtered.
     1986         * @param string      $context Additional context about how the function was called or where the iframe tag is.
     1987         */
     1988        $value = apply_filters( 'wp_iframe_tag_add_loading_attr', 'lazy', $iframe, $context );
     1989
     1990        if ( $value ) {
     1991                if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) {
     1992                        $value = 'lazy';
     1993                }
     1994
     1995                // Iframes should have source and dimension attributes for the `loading` attribute to be added.
     1996                if ( false === strpos( $iframe, ' src="' ) || false === strpos( $iframe, ' width="' ) || false === strpos( $iframe, ' height="' ) ) {
     1997                        return $iframe;
     1998                }
     1999
     2000                return str_replace( '<iframe', '<iframe loading="' . esc_attr( $value ) . '"', $iframe );
     2001        }
     2002
     2003        return $iframe;
    19372004}
    19382005
Note: See TracChangeset for help on using the changeset viewer.