Refine logic to select smaller image file in the frontend based on webp_uploads_prefer_smaller_image_file filter#302
Conversation
felixarntz
left a comment
There was a problem hiding this comment.
@jjgrainger Mostly looks good, it needs a few small refinements. Most importantly though, I think we should remove the function previously introduced since it's not really helpful or accurate anyway. The new approach here works good just by itself.
8a72560 to
a2719bb
Compare
felixarntz
left a comment
There was a problem hiding this comment.
@jjgrainger This looks close, two follow-up comments though. One is actually critical, the PR currently doesn't cover the full sized image yet.
Last but not least, can you also add tests for the new logic?
mitogh
left a comment
There was a problem hiding this comment.
Besides the comment from @felixarntz this looks good to me @jjgrainger
Thanks.
felixarntz
left a comment
There was a problem hiding this comment.
@jjgrainger Production logic now looks good to me, just one nit-pick on the filter and a potential issue with the test.
| // File produces larger webp image, original jpg is smaller. | ||
| $attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/leafs.jpg' ); | ||
| $metadata = wp_get_attachment_metadata( $attachment_id ); | ||
| $tag = wp_get_attachment_image( $attachment_id, 'full', false, array( 'class' => "wp-image-{$attachment_id}" ) ); | ||
| $updated_tag = webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ); | ||
|
|
||
| $mime_types = webp_uploads_get_mime_types_by_filesize( array( 'image/jpeg', 'image/webp' ), $attachment_id, 'the_content' ); | ||
| // The full size WebP is smaller. | ||
| $expected_tag = str_replace( $metadata['sources']['image/jpeg']['file'], $metadata['sources']['image/webp']['file'], $tag ); | ||
|
|
||
| $this->assertIsArray( $mime_types ); | ||
| $this->assertNotContains( 'image/invalid', $mime_types ); | ||
| $this->assertSame( array( 'image/jpeg', 'image/webp' ), $mime_types ); | ||
| $this->assertSame( $expected_tag, $updated_tag ); |
There was a problem hiding this comment.
Is this test in fact doing what the comment above says? It says this test covers the case where JPEG is smaller than WebP, but then for the $expected_tag it replaces the JPEG version with WebP, so that seems not right. If the JPEG version is smaller, the test should expect that the JPEG version is still used even though a WebP version exists.
There was a problem hiding this comment.
Thanks @felixarntz
I've updated the comments to make things clearer and reviewed the logic and can confirm it is correct. This image produces a smaller WebP file size of the full image. All sub sizes have a smaller JPG.
I've taken an example of the image code when the webp_uploads_prefer_smaller_image_file filter is set to true here:
<img loading="lazy" width="1080" height="720" src="http://localhost:8888/wp-content/uploads/2022/04/leafs.webp" alt="" class="wp-image-15" srcset="http://localhost:8888/wp-content/uploads/2022/04/leafs.webp 1080w, http://localhost:8888/wp-content/uploads/2022/04/leafs-300x200.jpg 300w, http://localhost:8888/wp-content/uploads/2022/04/leafs-1024x683.jpg 1024w, http://localhost:8888/wp-content/uploads/2022/04/leafs-768x512.jpg 768w" sizes="(max-width: 1080px) 100vw, 1080px">From the srcset you can see all sub sizes use the JPG version as they are smaller than their WebP version.
The replace updates the original image tag, which uses only JPG, to replace the full size with the WebP version in order to match the output of webp_uploads_img_tag_update_mime_type when the webp_uploads_prefer_smaller_image_file is set to true.
I've also created a shorthand version of the metadata array to compare filesizes and this is correct.
Array
(
[file] => 2022/04/leafs.jpg
[full] => Array
(
[image/jpeg] => 336884
[image/webp] => 328322
)
[medium] => Array
(
[image/jpeg] => 19820
[image/webp] => 22332
)
[large] => Array
(
[image/jpeg] => 237115
[image/webp] => 257974
)
[thumbnail] => Array
(
[image/jpeg] => 8082
[image/webp] => 9008
)
[medium_large] => Array
(
[image/jpeg] => 135786
[image/webp] => 153226
)
)There was a problem hiding this comment.
Ah, thanks for clarifying. That makes sense, in that case indeed the updated comments look better.
|
@adamsilverstein @mitogh Can one of you please review this as well so we can get it merged? |
adamsilverstein
left a comment
There was a problem hiding this comment.
Change looks good to me (although I think webp_uploads_prefer_smaller_image_file could start true here), I'll work on adding something similar to the core patch.
| if ( apply_filters( 'webp_uploads_prefer_smaller_image_file', false ) ) { | ||
| $target_mimes = webp_uploads_get_mime_types_by_filesize( $target_mimes, $attachment_id ); | ||
| } | ||
| $prefer_smaller_image_file = apply_filters( 'webp_uploads_prefer_smaller_image_file', false ); |
There was a problem hiding this comment.
working on adding to core patch so this could be true
There was a problem hiding this comment.
@adamsilverstein Not sure we should add this to the initial core patch as it feels like an extra enhancement. The main patch has a ton of code already and this enhancement could easily be separate.
There was a problem hiding this comment.
Ok, I'll add it as a separate patch
| if ( | ||
| $prefer_smaller_image_file && | ||
| ! empty( $metadata['sources'][ $target_mime ]['filesize'] ) && | ||
| ! empty( $metadata['sources'][ $original_mime ]['filesize'] ) && |
There was a problem hiding this comment.
Looking at this part I realized that there could potentially be several mime types in the sources array (eg. JPEG, WebP, AVIF), we should probably check all of them for the smallest size, rather than just the original and the mapped type.
What do you think @felixarntz ? Fine to address in a follow up so we can get this merged since it covers our primary use case as is.
There was a problem hiding this comment.
@adamsilverstein That's a good point, I think eventually that would make sense. It would require a bit more complex reworking though indeed, for example right now we only have a single $target_mime, and then there will need to be a list, all of which we would need to go through.
+1 to doing it in a separate issue.
There was a problem hiding this comment.
I'm taking the "look thru every mime type for the smallest" approach for the (follow up) core patch, basically go thru all sources to find the smallest and use that:
foreach( $metadata['sources'] as $source ) {
if ( empty( $source['filesize'] ) ) {
continue;
}
if ( $source['filesize'] < $target_file['filesize'] ) {
$target_file = $source;
}
}webp_uploads_prefer_smaller_image_file filter
Summary
Fixes #292
Relevant technical choices
webp_uploads_prefer_smaller_image_filefilter is enabled.Checklist
[Focus]orInfrastructurelabel.[Type]label.no milestonelabel.