diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php
index 90b7003..b26bd7e 100644
--- a/tests/phpunit/tests/media.php
+++ b/tests/phpunit/tests/media.php
@@ -52,7 +52,12 @@ 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 ) );
+ // Do not add srcset and sizes while testing.
+ add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
+
+ $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) );
+
+ remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
}
/**
@@ -70,11 +75,15 @@ function test_wp_lazy_load_content_media_opted_in() {
$content_unfiltered = sprintf( $content, $img );
$content_filtered = sprintf( $content, $lazy_img );
+ // Do not add srcset and sizes while testing.
+ add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
+
// Enable globally for all tags.
add_filter( 'wp_lazy_loading_enabled', '__return_true' );
- $this->assertSame( $content_filtered, wp_add_lazy_load_attributes( $content_unfiltered ) );
+ $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) );
remove_filter( 'wp_lazy_loading_enabled', '__return_true' );
+ remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
}
/**
@@ -88,10 +97,14 @@ function test_wp_lazy_load_content_media_opted_out() {
%1$s';
$content = sprintf( $content, $img );
+ // Do not add srcset and sizes while testing.
+ add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
+
// Disable globally for all tags.
add_filter( 'wp_lazy_loading_enabled', '__return_false' );
- $this->assertSame( $content, wp_add_lazy_load_attributes( $content ) );
+ $this->assertSame( $content, wp_filter_content_tags( $content ) );
remove_filter( 'wp_lazy_loading_enabled', '__return_false' );
+ remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' );
}
}
diff --git a/wp-lazy-loading.php b/wp-lazy-loading.php
index 1eefea1..5c5c28b 100644
--- a/wp-lazy-loading.php
+++ b/wp-lazy-loading.php
@@ -31,14 +31,16 @@
*/
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 ) {
- // After parsing blocks and shortcodes.
- add_filter( $filter, 'wp_add_lazy_load_attributes', 25 );
+ foreach ( array( 'the_content', 'the_excerpt', 'widget_text_content' ) as $filter ) {
+ add_filter( $filter, 'wp_filter_content_tags' );
}
// 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' );
+
+ // The following relevant filter from core should be removed when merged.
+ remove_filter( 'the_content', 'wp_make_content_images_responsive' );
}
add_action( 'plugins_loaded', '_wp_lazy_loading_initialize_filters', 1 );
@@ -102,7 +104,7 @@ function _wp_lazy_loading_add_attribute_to_attachment_image( $attr ) {
*/
function wp_lazy_loading_enabled( $tag_name, $context ) {
// By default add to all 'img' tags.
- // See https://github.com/whatwg/html/issues/2806
+ // See https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading
$default = ( 'img' === $tag_name );
/**
@@ -118,57 +120,150 @@ function wp_lazy_loading_enabled( $tag_name, $context ) {
}
/**
- * Add `loading="lazy"` to `img` HTML tags.
+ * Filters specific tags in post content and modifies their markup.
*
- * Currently the "loading" attribute is only supported for `img`, and is enabled by default.
+ * This function adds `srcset`, `sizes`, and `loading` attributes to `img` HTML tags.
*
* @since (TBD)
*
+ * @see wp_img_tag_add_loading_attr()
+ * @see wp_img_tag_add_srcset_and_sizes_attr()
+ *
* @param string $content The HTML content to be filtered.
* @param string $context Optional. Additional context to pass to the filters. Defaults to `current_filter()` when not set.
- * @return string Converted content with 'loading' attributes added to images.
+ * @return string Converted content with images modified.
*/
-function wp_add_lazy_load_attributes( $content, $context = null ) {
+function wp_filter_content_tags( $content, $context = null ) {
if ( null === $context ) {
$context = current_filter();
}
- if ( ! wp_lazy_loading_enabled( 'img', $context ) ) {
+ $add_loading_attr = wp_lazy_loading_enabled( 'img', $context );
+
+ if ( false === strpos( $content, '
]+>/',
- function( array $matches ) use( $content, $context ) {
- if ( ! preg_match( '/\sloading\s*=/', $matches[0] ) ) {
- $tag_html = $matches[0];
-
- /**
- * Filters the `loading` attribute value. Default `lazy`.
- *
- * Returning `false` or an empty string will not add the attribute.
- * Returning `true` will add the default value.
- *
- * @since (TBD)
- *
- * @param string $default The filtered value, defaults to `lazy`.
- * @param string $tag_html The tag's HTML.
- * @param string $content The HTML containing the image tag.
- * @param string $context Optional. Additional context. Defaults to `current_filter()`.
- */
- $value = apply_filters( 'wp_set_image_loading_attr', 'lazy', $tag_html, $content, $context );
+ if ( ! preg_match_all( '/
]+>/', $content, $matches ) ) {
+ return $content;
+ }
+
+ // List of the unique `img` tags found in $content.
+ $images = array();
- if ( $value ) {
- if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) {
- $value = 'lazy';
- }
+ foreach ( $matches[0] as $image ) {
+ if ( preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) ) {
+ $attachment_id = absint( $class_id[1] );
- return str_replace( '
1 ) {
+ /*
+ * Warm the object cache with post and meta information for all found
+ * images to avoid making individual database calls.
+ */
+ _prime_post_caches( $attachment_ids, false, true );
+ }
+
+ foreach ( $images as $image => $attachment_id ) {
+ $filtered_image = $image;
+
+ // Add 'srcset' and 'sizes' attributes if applicable.
+ if ( $attachment_id > 0 && false === strpos( $filtered_image, ' srcset=' ) ) {
+ $filtered_image = wp_img_tag_add_srcset_and_sizes_attr( $filtered_image, $context, $attachment_id );
+ }
+
+ // Add 'loading' attribute if applicable.
+ if ( $add_loading_attr && false === strpos( $filtered_image, ' loading=' ) ) {
+ $filtered_image = wp_img_tag_add_loading_attr( $filtered_image, $context );
+ }
+
+ if ( $filtered_image !== $image ) {
+ $content = str_replace( $image, $filtered_image, $content );
+ }
+ }
+
+ return $content;
+}
+
+/**
+ * Adds `loading` attribute to an existing `img` HTML tag.
+ *
+ * @since (TBD)
+ *
+ * @param string $image The HTML `img` tag where the attribute should be added.
+ * @param string $context Additional context to pass to the filters.
+ * @return string Converted `img` tag with `loading` attribute added.
+ */
+function wp_img_tag_add_loading_attr( $image, $context ) {
+ /**
+ * Filters the `loading` attribute value. Default `lazy`.
+ *
+ * Returning `false` or an empty string will not add the attribute.
+ * Returning `true` will add the default value.
+ *
+ * @since (TBD)
+ *
+ * @param string $value The 'loading' attribute value, defaults to `lazy`.
+ * @param string $image The HTML 'img' element to be filtered.
+ * @param string $context Additional context about how the function was called or where the img tag is.
+ */
+ $value = apply_filters( 'wp_img_tag_add_loading_attr', 'lazy', $image, $context );
+
+ if ( $value ) {
+ if ( ! in_array( $value, array( 'lazy', 'eager' ), true ) ) {
+ $value = 'lazy';
+ }
+
+ return str_replace( '![]()