Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,11 @@ add_filter('optml_dont_replace_url', function( $old, $url ) {

}, 10, 2);
</code>

= Can I keep the sizes attribute I wrote for an image ? =

Yes. Add the `data-optml-keep-sizes` attribute to the image tag and the page profiler won't add its own entries to the image's `sizes` attribute. Images lazy loaded by Optimole don't keep `srcset` or `sizes`, since the lazy loader doesn't need them. To keep the existing `sizes` attribute on every image, add this snippet:

<code>
add_filter( 'optml_keep_existing_sizes', '__return_true' );
</code>
40 changes: 36 additions & 4 deletions inc/tag_replacer.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ final class Optml_Tag_Replacer extends Optml_App_Replacer {
use Optml_Validator;
use Optml_Dam_Offload_Utils;

/**
* Attribute an image uses to keep its own sizes attribute.
*/
const KEEP_SIZES_ATTRIBUTE = 'data-optml-keep-sizes';

/**
* Cached object instance.
*
Expand Down Expand Up @@ -550,11 +555,16 @@ public function add_missing_srcset_attributes( $tag, $missing_srcsets, $new_url,
$tag = $this->insert_after_attribute( $tag, 'src', $srcset_attr );
}

// Handle sizes attribute - skip if existing sizes contains calc() or complex formulas
// Handle sizes attribute - skip if the image asks to keep its existing sizes, or they contain calc() or complex formulas
if ( ! empty( $new_sizes_entries ) ) {
$should_skip_sizes = false;

if ( $has_existing_sizes ) {
if ( $has_existing_sizes && $this->keeps_existing_sizes( $tag ) ) {
$should_skip_sizes = true;
if ( OPTML_DEBUG ) {
do_action( 'optml_log', 'Keeping the existing sizes attribute: ' . $new_url );
}
Comment thread
pirate-bot marked this conversation as resolved.
} elseif ( $has_existing_sizes ) {
// Check if existing sizes contains calc() or complex formulas
$sizes = $this->find_quoted_attribute( $tag, 'sizes' );
if ( null !== $sizes ) {
Expand Down Expand Up @@ -596,9 +606,9 @@ function ( $a, $b ) {
}
}
} else {
// Log that sizes were skipped due to complex formulas
// Log that sizes were skipped (kept on request, or complex formula)
if ( OPTML_DEBUG ) {
do_action( 'optml_log', 'Skipped adding sizes due to complex formula detection' );
do_action( 'optml_log', 'Skipped adding sizes' );
}
}
}
Expand Down Expand Up @@ -834,6 +844,28 @@ private function has_attribute( string $tag, string $name ): bool {
return in_array( $name, array_column( $this->get_attributes( $tag ) ?? [], 'name' ), true );
}

/**
* Check whether an image's own sizes attribute must be left as it is.
*
* An image opts out with the data-optml-keep-sizes attribute. The optml_keep_existing_sizes filter
* does it for every image, or for the ones it picks, with no change to the markup.
*
* @param string $tag The image tag.
*
* @return bool True if the existing sizes attribute is kept.
*/
private function keeps_existing_sizes( string $tag ): bool {
$keep = $this->has_attribute( $tag, self::KEEP_SIZES_ATTRIBUTE );

/**
* Filters whether Optimole leaves an image's existing sizes attribute unchanged.
*
* @param bool $keep Whether the existing sizes attribute is kept. True when the image has data-optml-keep-sizes.
* @param string $tag The image tag.
*/
return (bool) apply_filters( 'optml_keep_existing_sizes', $keep, $tag );
}

/**
* Check whether the tag's src or srcset is a data: URI placeholder.
*
Expand Down
8 changes: 8 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,11 @@ add_filter('optml_dont_replace_url', function( $old, $url ) {

}, 10, 2);
</code>

= Can I keep the sizes attribute I wrote for an image ? =

Yes. Add the `data-optml-keep-sizes` attribute to the image tag and the page profiler won't add its own entries to the image's `sizes` attribute. Images lazy loaded by Optimole don't keep `srcset` or `sizes`, since the lazy loader doesn't need them. To keep the existing `sizes` attribute on every image, add this snippet:

<code>
add_filter( 'optml_keep_existing_sizes', '__return_true' );
</code>
Comment thread
pirate-bot marked this conversation as resolved.
59 changes: 59 additions & 0 deletions tests/test-srcset.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,65 @@ public function test_add_missing_srcset_attributes_with_existing_sizes() {
$this->assertStringContainsString( '(max-width: 768px) 400px', $result );
}

/**
* An image with data-optml-keep-sizes keeps its hand-written sizes, and still gets the new srcset entries.
*/
public function test_keep_sizes_attribute_preserves_existing_sizes() {
$tag_replacer = new Optml_Tag_Replacer();

$tag = '<img src="https://example.com/image.jpg" srcset="existing-300w.jpg 300w" sizes="(max-width: 480px) 300px" data-optml-keep-sizes alt="Test" />';
$missing_srcsets = [
[ 'w' => 200, 'h' => 150, 'd' => 1, 's' => '200w', 'b' => 320 ],
[ 'w' => 400, 'h' => 300, 'd' => 1, 's' => '400w', 'b' => 768 ],
];

$result = $tag_replacer->add_missing_srcset_attributes( $tag, $missing_srcsets, 'https://example.com/image.jpg', false );

$this->assertStringContainsString( 'sizes="(max-width: 480px) 300px"', $result );
$this->assertStringNotContainsString( '(max-width: 320px) 200px', $result );
$this->assertStringContainsString( '200w', $result );
}

/**
* The optml_keep_existing_sizes filter keeps existing sizes site-wide, with no change to the markup.
*/
public function test_keep_existing_sizes_filter() {
$tag_replacer = new Optml_Tag_Replacer();

$tag = '<img src="https://example.com/image.jpg" srcset="existing-300w.jpg 300w" sizes="(max-width: 480px) 300px" alt="Test" />';
$missing_srcsets = [
[ 'w' => 200, 'h' => 150, 'd' => 1, 's' => '200w', 'b' => 320 ],
];

add_filter( 'optml_keep_existing_sizes', '__return_true' );
$result = $tag_replacer->add_missing_srcset_attributes( $tag, $missing_srcsets, 'https://example.com/image.jpg', false );
remove_filter( 'optml_keep_existing_sizes', '__return_true' );

$this->assertStringContainsString( 'sizes="(max-width: 480px) 300px"', $result );
$this->assertStringNotContainsString( '(max-width: 320px) 200px', $result );
Comment thread
pirate-bot marked this conversation as resolved.
}

/**
* A filter returning false overrides the attribute, so the existing sizes are enhanced again.
*/
public function test_keep_existing_sizes_filter_can_override_attribute() {
$tag_replacer = new Optml_Tag_Replacer();

$tag = '<img src="https://example.com/image.jpg" srcset="existing-300w.jpg 300w" sizes="(max-width: 480px) 300px" data-optml-keep-sizes alt="Test" />';
$missing_srcsets = [
[ 'w' => 200, 'h' => 150, 'd' => 1, 's' => '200w', 'b' => 320 ],
];

$kept = $tag_replacer->add_missing_srcset_attributes( $tag, $missing_srcsets, 'https://example.com/image.jpg', false );
$this->assertStringNotContainsString( '(max-width: 320px) 200px', $kept );

add_filter( 'optml_keep_existing_sizes', '__return_false' );
$result = $tag_replacer->add_missing_srcset_attributes( $tag, $missing_srcsets, 'https://example.com/image.jpg', false );
remove_filter( 'optml_keep_existing_sizes', '__return_false' );

$this->assertStringContainsString( '(max-width: 320px) 200px', $result );
}

/**
* Test retina images setting respect
*/
Expand Down
Loading