From a2b13439eacde3117b0167a1b5d51d21a0719d50 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Tue, 12 Apr 2022 05:16:46 +0000 Subject: [PATCH] Media: Run the `wp_content_img_tag` filter once per image. Prevent multiple identical `img` tags in a block of content causing the `wp_content_img_tag` filter to fire multiple times for that image. Follow up to [53028]. Props superpoincare, flixos90, pbearne, peterwilsoncc. Fixes #55510. See #55347. git-svn-id: https://develop.svn.wordpress.org/trunk@53149 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/media.php | 12 +++++++ tests/phpunit/tests/media.php | 67 +++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index 260db26cac..2b46167afc 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -1857,6 +1857,12 @@ function wp_filter_content_tags( $content, $context = null ) { if ( $filtered_image !== $match[0] ) { $content = str_replace( $match[0], $filtered_image, $content ); } + + /* + * Unset image lookup to not run the same logic again unnecessarily if the same image tag is used more than + * once in the same blob of content. + */ + unset( $images[ $match[0] ] ); } // Filter an iframe match. @@ -1871,6 +1877,12 @@ function wp_filter_content_tags( $content, $context = null ) { if ( $filtered_iframe !== $match[0] ) { $content = str_replace( $match[0], $filtered_iframe, $content ); } + + /* + * Unset iframe lookup to not run the same logic again unnecessarily if the same iframe tag is used more + * than once in the same blob of content. + */ + unset( $iframes[ $match[0] ] ); } } diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index 88a402e298..8f3340aaf7 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -2304,6 +2304,73 @@ EOF; wp_filter_content_tags( $img_tag_1 ); $this->assertSame( 1, $filter->get_call_count() ); } + + /** + * @ticket 55510 + * @covers ::wp_filter_content_tags + */ + public function test_wp_filter_content_tags_handles_duplicate_img_and_iframe_tags_once() { + $img = get_image_tag( self::$large_id, '', '', '', 'large' ); + $iframe = ''; + $content = "$img\n$img\n$iframe\n$iframe"; + + // Record how often one of the available img and iframe filters is run. + // Both images and iframes support lazy-loading, so that's why this is used here. + $img_filter = new MockAction(); + add_filter( 'wp_img_tag_add_loading_attr', array( &$img_filter, 'filter' ) ); + $iframe_filter = new MockAction(); + add_filter( 'wp_iframe_tag_add_loading_attr', array( &$iframe_filter, 'filter' ) ); + + // Ensure the img and iframe filters only ran once because the content is a single duplicated img tag and a + // single duplicate iframe tag. + wp_filter_content_tags( $content ); + $this->assertSame( 1, $img_filter->get_call_count() ); + $this->assertSame( 1, $iframe_filter->get_call_count() ); + } + + /** + * @ticket 55510 + * @covers ::wp_filter_content_tags + */ + public function test_wp_filter_content_tags_filter_with_identical_image_tags_custom_attributes() { + $img = get_image_tag( self::$large_id, '', '', '', 'large' ); + $img = str_replace( '$filtered_image"; + } + ); + + // Ensure there is no duplicate wrapping the image. + $this->assertStringNotContainsString( '$filtered_image"; + } + ); + + // Ensure the output has both instances of the image wrapped with a single . + $this->assertSame( "$img\n$img", wp_filter_content_tags( $content ) ); + } + /** * @ticket 33641 * @ticket 34528