Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use more robust HTML Tag Processor for auto sizes injection #1471

Merged
merged 4 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions plugins/auto-sizes/hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,32 @@ function auto_sizes_update_content_img_tag( $html ): string {
$html = '';
}

$processor = new WP_HTML_Tag_Processor( $html );

// Bail if there is no IMG tag.
if ( ! $processor->next_tag( array( 'tag_name' => 'IMG' ) ) ) {
return $html;
}

// Bail early if the image is not lazy-loaded.
if ( false === strpos( $html, 'loading="lazy"' ) ) {
if ( 'lazy' !== $processor->get_attribute( 'loading' ) ) {
return $html;
}

$sizes = $processor->get_attribute( 'sizes' );

// Bail early if the image is not responsive.
if ( 1 !== preg_match( '/sizes="([^"]+)"/', $html, $match ) ) {
if ( ! is_string( $sizes ) ) {
return $html;
}

// Don't add 'auto' to the sizes attribute if it already exists.
if ( auto_sizes_attribute_includes_valid_auto( $match[1] ) ) {
if ( auto_sizes_attribute_includes_valid_auto( $sizes ) ) {
return $html;
}

$html = str_replace( 'sizes="', 'sizes="auto, ', $html );

return $html;
$processor->set_attribute( 'sizes', "auto, $sizes" );
return $processor->get_updated_html();
}
add_filter( 'wp_content_img_tag', 'auto_sizes_update_content_img_tag' );

Expand Down
93 changes: 93 additions & 0 deletions plugins/auto-sizes/tests/test-auto-sizes.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,97 @@ public function test_auto_sizes_render_generator(): void {
$this->assertStringContainsString( 'generator', $tag );
$this->assertStringContainsString( 'auto-sizes ' . IMAGE_AUTO_SIZES_VERSION, $tag );
}

public function test_content_image_with_single_quote_replacement_does_not_have_auto_sizes(): void {
add_filter(
'get_image_tag',
static function ( $html ) {
return str_replace(
'" />',
'" loading="lazy" sizes="(max-width: 1024px) 100vw, 1024px" />',
$html
);
}
);

$image_tag = str_replace( '"', "'", $this->get_image_tag( self::$image_id ) );
$image_content = wp_filter_content_tags( $image_tag );

$processor = new WP_HTML_Tag_Processor( $image_content );
$this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' );
$sizes = $processor->get_attribute( 'sizes' );
$this->assertTrue( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' );
$this->assertStringContainsString( 'auto', $sizes, 'The sizes attribute does not contain "auto".' );
}

public function test_content_image_with_custom_attribute_name_with_sizes_at_the_end_does_not_have_auto_sizes(): void {
add_filter(
'get_image_tag',
static function ( $html ) {
return str_replace(
'" />',
'" loading="lazy" sizes="(max-width: 1024px) 100vw, 1024px" data-tshirt-sizes="S M L" />',
$html
);
}
);

$image_tag = $this->get_image_tag( self::$image_id );
$image_content = wp_filter_content_tags( $image_tag );

$processor = new WP_HTML_Tag_Processor( $image_content );
$this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' );
$data_tshirt_sizes = $processor->get_attribute( 'data-tshirt-sizes' );
$this->assertStringNotContainsString( 'auto', $data_tshirt_sizes, 'The data-tshirt-sizes attribute should not contain "auto".' );
$this->assertSame( 'S M L', $data_tshirt_sizes, 'The data-tshirt-sizes attribute does not match the expected value.' );
}

public function test_content_image_with_lazy_load_text_in_alt_does_not_have_auto_sizes(): void {
add_filter(
'get_image_tag',
static function ( $html ) {
return str_replace(
'alt="',
'alt="This is the LCP image and it should not get loading="lazy"!',
$html
);
}
);

$image_tag = $this->get_image_tag( self::$image_id );
$image_content = wp_filter_content_tags( $image_tag );

$processor = new WP_HTML_Tag_Processor( $image_content );
$this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' );
$this->assertNull( $processor->get_attribute( 'loading' ), 'The loading attribute should be null when lazy-load text is in the alt attribute.' );
$sizes = $processor->get_attribute( 'sizes' );
$this->assertFalse( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' );
$this->assertStringNotContainsString( 'auto', $sizes, 'The sizes attribute should not contain "auto".' );
}

public function test_content_image_with_custom_attribute_name_with_loading_lazy_at_the_end_does_not_have_auto_sizes(): void {
// Force lazy loading attribute.
add_filter( 'wp_img_tag_add_loading_attr', '__return_false' );

add_filter(
'get_image_tag',
static function ( $html ) {
return str_replace(
'" />',
'" data-removed-loading="lazy" />',
$html
);
}
);

$image_tag = $this->get_image_tag( self::$image_id );
$image_content = wp_filter_content_tags( $image_tag );

$processor = new WP_HTML_Tag_Processor( $image_content );
$this->assertTrue( $processor->next_tag( array( 'tag_name' => 'IMG' ) ), 'Failed to find the IMG tag.' );
$this->assertNull( $processor->get_attribute( 'loading' ), 'The loading attribute should be null when a custom attribute name is used.' );
$sizes = $processor->get_attribute( 'sizes' );
$this->assertFalse( auto_sizes_attribute_includes_valid_auto( $sizes ), 'The sizes attribute does not include "auto" as the first item in the list.' );
$this->assertStringNotContainsString( 'auto', $sizes, 'The sizes attribute should not contain "auto".' );
}
}