WordPress.org

Make WordPress Core


Ignore:
Timestamp:
12/16/2020 09:17:24 PM (4 weeks 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.