From 802abafe65e79644f4741a4f9a301fb19b98c6df Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Mon, 20 Jan 2020 15:39:41 -0800 Subject: [PATCH 1/2] Abstract and update filtering of tags - Add filter for each tag. - Make it easy to filter other tags and/or add more attributes in the future. --- wp-lazy-loading.php | 174 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 140 insertions(+), 34 deletions(-) diff --git a/wp-lazy-loading.php b/wp-lazy-loading.php index 2668eb3..053be19 100644 --- a/wp-lazy-loading.php +++ b/wp-lazy-loading.php @@ -32,15 +32,24 @@ function _wp_lazy_loading_initialize_filters() { // The following filters would be merged into core. foreach ( array( 'the_content', 'the_excerpt', 'comment_text', 'widget_text_content' ) as $filter ) { - // Before parsing blocks and shortcodes. - // TODO: Comments do not support images. Revisit. - // TODO: This should not exclude images from dynamic blocks and shortcodes. Look at fixing the filter priority. - add_filter( $filter, 'wp_add_lazy_load_attributes', 8 ); + // After parsing blocks and shortcodes. + // TODO: Comments and excerpts do not support images. Revisit? + // TODO: This includes images added from shortcodes. Needs more testing. + add_filter( $filter, '_wp_filter_html_tags', 25 ); } + add_filter( 'wp_filter_img_tags', 'wp_add_lazy_loading_to_img_tags', 10, 3 ); + // The following filters are only needed while this is a feature plugin. add_filter( 'wp_get_attachment_image_attributes', '_wp_lazy_loading_add_attribute_to_attachment_image' ); add_filter( 'get_avatar', '_wp_lazy_loading_add_attribute_to_avatar' ); + + // Exprerimental, testing only. + if ( isset( $_GET['wp-lazy-loading-iframes'] ) ) { + add_filter( 'wp_get_tags_to_filter', 'wp_lazy_loading_add_iframe_tag', 10, 2 ); + add_filter( 'wp_filter_iframe_tags', 'wp_add_lazy_loading_to_iframe_tags', 10, 3 ); + } + } add_action( 'plugins_loaded', '_wp_lazy_loading_initialize_filters', 1 ); @@ -62,7 +71,7 @@ function _wp_lazy_loading_initialize_filters() { * @return string Modified tag. */ function _wp_lazy_loading_add_attribute_to_avatar( $avatar ) { - if ( in_array( 'img', wp_get_lazy_load_tags(), true ) && false === strpos( $avatar, ' loading=' ) ) { + if ( wp_add_lazy_loading_to( 'img', 'get_avatar' ) && false === strpos( $avatar, ' loading=' ) ) { $avatar = str_replace( '` tags. * * Currently the "loading" attribute is only supported for `img`, and is enabled by default. - * Support for `iframe` is for testing purposes only. + * Support for `iframe` can be enabled for testing purposes. * * @since (TBD) * - * @param string $content The raw post content to be filtered. + * @param string $tag_html The tag markup. + * @param string $content The (HTML) content where the img tag is. + * @param string $context Optional. Additional context passed to the function. * @return string Converted content with 'loading' attributes added to images. */ -function wp_add_lazy_load_attributes( $content ) { - $tags = wp_get_lazy_load_tags(); +function wp_add_lazy_loading_to_img_tags( $tag_html, $content, $context = null ) { + if ( wp_add_lazy_loading_to( 'img', $context ) && ! preg_match( '/\bloading\s*=/', $tag_html ) ) { + $unfiltered = $tag_html; + $tag_html = str_replace( ' $tag_name ) { + if ( ! has_filter( "wp_filter_{$tag_name}_tags" ) || false === strpos( $content, "<$tag_name" ) ) { + unset( $tags[ $index ] ); + } + } if ( empty( $tags ) ) { return $content; } + // Expects well-formed HTML 5.0. + // Intended for `img` and `iframe`. return preg_replace_callback( - '/<(' . implode( '|', $tags ) . ')(\s)[^>]+>/', - function( array $matches ) { - if ( ! preg_match( '/\sloading\s*=/', $matches[0] ) ) { - $tag = $matches[1]; - $space = $matches[2]; + '/<(' . implode( '|', $tags ) . ')(?:\s[^>]+)?>/', + function( array $matches ) use ( $content, $context ) { + $tag_html = $matches[0]; + $tag_name = $matches[1]; - return str_replace( '<' . $tag . $space, '<' . $tag . $space . 'loading="lazy" ', $matches[0] ); - } - - return $matches[0]; + /** + * Filters each of the HTML tags that were found in $content. + * + * The variable part of the filter is the name of the matched tag. + * + * @since (TBD) + * + * @param string $tag_html The matched HTML markup. + * @param string $content The (HTML) content being filtered. + * @param string $context Optional. Additional context. May be the current filter name or specific context passed to the function. + */ + return apply_filters( "wp_filter_{$tag_name}_tags", $tag_html, $content, $context ); }, $content ); } - From cd22d3e1b99b6f2c602fb20f19e75219d9172e33 Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Tue, 21 Jan 2020 17:43:57 -0800 Subject: [PATCH 2/2] Update tests --- tests/phpunit/tests/media.php | 26 +++++++++++++++++++------- wp-lazy-loading.php | 26 +++++++++++++++++--------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index b9b98dd..98b7c67 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -52,7 +52,7 @@ function test_wp_lazy_load_content_media() { $content_unfiltered = sprintf( $content, $img, $img_xhtml, $img_html5, $iframe, $img_eager ); $content_filtered = sprintf( $content, $lazy_img, $lazy_img_xhtml, $lazy_img_html5, $iframe, $img_eager ); - $this->assertSame( $content_filtered, wp_add_lazy_load_attributes( $content_unfiltered ) ); + $this->assertSame( $content_filtered, _wp_filter_html_tags( $content_unfiltered ) ); } /** @@ -75,10 +75,22 @@ function test_wp_lazy_load_content_media_opted_in() { $content_unfiltered = sprintf( $content, $img, $iframe ); $content_filtered = sprintf( $content, $lazy_img, $lazy_iframe ); - add_filter( 'wp_get_lazy_load_tags', '__return_true' ); + add_filter( 'wp_add_lazy_loading_to', '__return_true' ); + add_filter( 'wp_get_tags_to_filter', array( $this, 'wp_get_tags_to_filter_callback' ) ); + add_filter( 'wp_filter_iframe_tags', array( $this, 'wp_filter_iframe_tags_callback' ) ); - $this->assertSame( $content_filtered, wp_add_lazy_load_attributes( $content_unfiltered ) ); - remove_filter( 'wp_get_lazy_load_tags', '__return_true' ); + $this->assertSame( $content_filtered, _wp_filter_html_tags( $content_unfiltered ) ); + remove_filter( 'wp_add_lazy_loading_to', '__return_true' ); + remove_filter( 'wp_get_tags_to_filter', array( $this, 'wp_get_tags_to_filter_callback' ) ); + remove_filter( 'wp_filter_iframe_tags', array( $this, 'wp_filter_iframe_tags_callback' ) ); + } + + function wp_get_tags_to_filter_callback() { + return array( 'img', 'iframe' ); + } + + function wp_filter_iframe_tags_callback( $tag_html ) { + return str_replace( 'assertSame( $content, wp_add_lazy_load_attributes( $content ) ); - remove_filter( 'wp_get_lazy_load_tags', '__return_false' ); + $this->assertSame( $content, _wp_filter_html_tags( $content ) ); + remove_filter( 'wp_add_lazy_loading_to', '__return_false' ); } } diff --git a/wp-lazy-loading.php b/wp-lazy-loading.php index 053be19..a96961e 100644 --- a/wp-lazy-loading.php +++ b/wp-lazy-loading.php @@ -45,11 +45,17 @@ function _wp_lazy_loading_initialize_filters() { add_filter( 'get_avatar', '_wp_lazy_loading_add_attribute_to_avatar' ); // Exprerimental, testing only. + // To test with iframes: add `?wp-lazy-loading-iframes` to the current URL. if ( isset( $_GET['wp-lazy-loading-iframes'] ) ) { + // Add to all tags. + add_filter( 'wp_add_lazy_loading_to', '__return_true' ); + + // Add filterig for the iframe tag. add_filter( 'wp_get_tags_to_filter', 'wp_lazy_loading_add_iframe_tag', 10, 2 ); + + // Add the actual attribute, and filter the tag after that. add_filter( 'wp_filter_iframe_tags', 'wp_add_lazy_loading_to_iframe_tags', 10, 3 ); } - } add_action( 'plugins_loaded', '_wp_lazy_loading_initialize_filters', 1 ); @@ -92,7 +98,7 @@ function _wp_lazy_loading_add_attribute_to_avatar( $avatar ) { * @return array Modified attributes. */ function _wp_lazy_loading_add_attribute_to_attachment_image( $attr ) { - if ( wp_add_lazy_loading_to( 'img', 'wp_get_attachment_image_attributes' ) && ! isset( $attr['loading'] ) ) { + if ( wp_add_lazy_loading_to( 'img', 'wp_get_attachment_image' ) && ! isset( $attr['loading'] ) ) { $attr['loading'] = 'lazy'; } @@ -100,14 +106,14 @@ function _wp_lazy_loading_add_attribute_to_attachment_image( $attr ) { } -// Helper functions to enable adding of `loading="lazy"` to iframes. +// Helper functions to enable adding of `loading="lazy"` to iframes (not for merging for now). function wp_add_lazy_loading_to_iframe_tags( $tag_html, $content, $context = null ) { if ( wp_add_lazy_loading_to( 'iframe', $context ) && ! preg_match( '/\bloading\s*=/', $tag_html ) ) { $unfiltered = $tag_html; $tag_html = str_replace( '