From 0ff1c4d8533b2e6f041925254be709305461773b Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Fri, 18 Mar 2022 15:09:37 +0000 Subject: [PATCH 1/8] calculate performant mime type for attachment --- modules/images/webp-uploads/load.php | 75 ++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 4cf4f0213e..b4bd5424c8 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -706,3 +706,78 @@ function webp_uploads_update_rest_attachment( WP_REST_Response $response, WP_Pos return rest_ensure_response( $data ); } add_filter( 'rest_prepare_attachment', 'webp_uploads_update_rest_attachment', 10, 3 ); + +/** + * Returns the attachment sources array ordered by filesize. + * + * @since n.e.xt + * @private + * + * @param int $attachment_id The attachment ID. + * @param string $size The attachment size. + * + * @return array The attachment sources array. + */ +function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail' ) { + // Check for the sources attribute in attachment metadata. + $metadata = wp_get_attachment_metadata( $attachment_id ); + + // Return full image size sources. + if ( 'full' === $size && ! empty( $metadata['sources'] ) ) { + return $metadata['sources']; + } + + // Return the resized image sources. + if ( ! empty( $metadata['sizes'][ $size ]['sources'] ) ) { + return $metadata['sizes'][ $size ]['sources']; + } + + // Return an empty array if no sources found. + return array(); +} + +/** +* Returns the attachment smallest filesize source. + * + * @since n.e.xt + * @private + * + * @param array $mime_types The list of mime types that can be used to update images in the content. + * @param int $attachment_id The attachment ID. + * @param string $context The current context. + * + * @return array Array of mime types ordered by filesize. + */ +function webp_uploads_get_mime_types_by_filesize( $mime_types, $attachment_id, $context ) { + $sources = webp_uploads_get_attachment_sources( $attachment_id, 'full' ); + + if ( empty( $sources ) ) { + return $mime_types; + } + + // Remove mime types with filesize of 0. + $sources = array_filter( + $sources, + function( $source ) { + return $source['filesize'] > 0; + } + ); + + // Order sources on filesize in ascending order. + uasort( + $sources, + function( $a, $b ) { + if ( $a['filesize'] === $b['filesize'] ) { + return 0; + } + + return ($a['filesize'] < $b['filesize']) ? -1 : 1; + } + ); + + // Create an array available mime types ordered by smallest filesize. + $mime_types = array_values( array_keys( $sources ) ); + + return $mime_types; +} +add_filter( 'webp_uploads_content_image_mimes', 'webp_uploads_get_mime_types_by_filesize', 10, 3 ); From 3368bbd03c6656671db163b53b5a7484ba7a6b01 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Mon, 21 Mar 2022 11:06:42 +0000 Subject: [PATCH 2/8] remove array reverse as mime types are ordered by most progressive first --- modules/images/webp-uploads/load.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index b4bd5424c8..a47c18056b 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -613,7 +613,6 @@ function webp_uploads_img_tag_update_mime_type( $image, $context, $attachment_id $target_mime = null; // Look for the most progressive image format first. - $target_mimes = array_reverse( $target_mimes ); foreach ( $target_mimes as $mime ) { if ( isset( $metadata['sources'][ $mime ] ) ) { $target_mime = $mime; @@ -737,7 +736,8 @@ function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail } /** -* Returns the attachment smallest filesize source. + * Filters on `webp_uploads_content_image_mimes` to generate the available mime types for an attachment + * and orders them by the smallest filesize first. * * @since n.e.xt * @private @@ -746,7 +746,7 @@ function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail * @param int $attachment_id The attachment ID. * @param string $context The current context. * - * @return array Array of mime types ordered by filesize. + * @return array Array of available mime types ordered by filesize. */ function webp_uploads_get_mime_types_by_filesize( $mime_types, $attachment_id, $context ) { $sources = webp_uploads_get_attachment_sources( $attachment_id, 'full' ); @@ -763,7 +763,7 @@ function( $source ) { } ); - // Order sources on filesize in ascending order. + // Order sources by filesize in ascending order. uasort( $sources, function( $a, $b ) { @@ -775,7 +775,7 @@ function( $a, $b ) { } ); - // Create an array available mime types ordered by smallest filesize. + // Create an array of available mime types ordered by smallest filesize. $mime_types = array_values( array_keys( $sources ) ); return $mime_types; From 320ee8258f01485158de2767b680b6124d5d00f5 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Mon, 21 Mar 2022 16:19:10 +0000 Subject: [PATCH 3/8] fix linting errors --- modules/images/webp-uploads/load.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index a47c18056b..075a494dd4 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -771,7 +771,7 @@ function( $a, $b ) { return 0; } - return ($a['filesize'] < $b['filesize']) ? -1 : 1; + return ( $a['filesize'] < $b['filesize'] ) ? -1 : 1; } ); From ed6f0cb2c5463083c639cd23876c75c0b3fdbf9f Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Wed, 23 Mar 2022 14:38:10 +0000 Subject: [PATCH 4/8] add tests --- .../images/webp-uploads/webp-uploads-test.php | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/tests/modules/images/webp-uploads/webp-uploads-test.php b/tests/modules/images/webp-uploads/webp-uploads-test.php index be37d5fc10..c9401a1d09 100644 --- a/tests/modules/images/webp-uploads/webp-uploads-test.php +++ b/tests/modules/images/webp-uploads/webp-uploads-test.php @@ -808,4 +808,95 @@ function( $transforms ) { $this->assertImageNotHasSizeSource( $attachment_id, $size_name, 'image/jpeg' ); } } + + /** + * Test webp_uploads_get_mime_types_by_filesize returns smallest filesize, in this case webp. + * + * @test + */ + public function it_should_return_smaller_webp_mime_type() { + // File should generate smallest webp image size. + $attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/car.jpeg' ); + + $mime_types = webp_uploads_get_mime_types_by_filesize( array( 'image/jpeg', 'image/webp' ), $attachment_id, 'the_content' ); + + $this->assertIsArray( $mime_types ); + $this->assertSame( 'image/webp', $mime_types[0] ); + $this->assertSame( 'image/jpeg', $mime_types[1] ); + } + + /** + * Test webp_uploads_get_mime_types_by_filesize returns smallest filesize, in this case jpeg. + * + * @test + */ + public function it_should_return_smaller_jpeg_mime_type() { + // File should generate smallest jpeg image size. + $attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/paint.jpeg' ); + + // Mock attachment meta data to test when jpeg image is smaller. + add_filter( + 'wp_get_attachment_metadata', + function( $data, $attachment_id ) { + $data['sources'] = array( + 'image/jpeg' => array( + 'file' => 'paint.jpeg', + 'filesize' => 1000, + ), + 'image/webp' => array( + 'file' => 'paint.webp', + 'filesize' => 2000, + ), + ); + }, + 10, + 2 + ); + + $mime_types = webp_uploads_get_mime_types_by_filesize( array( 'image/jpeg', 'image/webp' ), $attachment_id, 'the_content' ); + + $this->assertIsArray( $mime_types ); + $this->assertSame( 'image/jpeg', $mime_types[0] ); + $this->assertSame( 'image/webp', $mime_types[1] ); + } + + /** + * Test webp_uploads_get_mime_types_by_filesize removes invalid mime types with zero filesize. + * + * @test + */ + public function it_should_remove_mime_types_with_zero_filesize() { + // File should generate smallest jpeg image size. + $attachment_id = $this->factory->attachment->create_upload_object( TESTS_PLUGIN_DIR . '/tests/testdata/modules/images/paint.jpeg' ); + + // Mock attachment meta data to test mime type with zero filesize. + add_filter( + 'wp_get_attachment_metadata', + function( $data, $attachment_id ) { + $data['sources'] = array( + 'image/jpeg' => array( + 'file' => 'paint.jpeg', + 'filesize' => 1000, + ), + 'image/webp' => array( + 'file' => 'paint.webp', + 'filesize' => 2000, + ), + 'image/invalid' => array( + 'file' => 'paint.avif', + 'filesize' => 0, + ), + ); + }, + 10, + 2 + ); + + $mime_types = webp_uploads_get_mime_types_by_filesize( array( 'image/jpeg', 'image/webp' ), $attachment_id, 'the_content' ); + + $this->assertIsArray( $mime_types ); + $this->assertNotContains( 'image/invalid', $mime_types ); + $this->assertSame( 'image/jpeg', $mime_types[0] ); + $this->assertSame( 'image/webp', $mime_types[1] ); + } } From 9cf04792668f94c5229af1286d03e396a8f47341 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Wed, 23 Mar 2022 14:41:56 +0000 Subject: [PATCH 5/8] address pr feedback --- modules/images/webp-uploads/load.php | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 075a494dd4..f9ebbd4178 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -709,8 +709,7 @@ function webp_uploads_update_rest_attachment( WP_REST_Response $response, WP_Pos /** * Returns the attachment sources array ordered by filesize. * - * @since n.e.xt - * @private + * @since n.e.x.t * * @param int $attachment_id The attachment ID. * @param string $size The attachment size. @@ -739,8 +738,7 @@ function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail * Filters on `webp_uploads_content_image_mimes` to generate the available mime types for an attachment * and orders them by the smallest filesize first. * - * @since n.e.xt - * @private + * @since n.e.x.t * * @param array $mime_types The list of mime types that can be used to update images in the content. * @param int $attachment_id The attachment ID. @@ -759,7 +757,7 @@ function webp_uploads_get_mime_types_by_filesize( $mime_types, $attachment_id, $ $sources = array_filter( $sources, function( $source ) { - return $source['filesize'] > 0; + return isset( $source['filesize'] ) && $source['filesize'] > 0; } ); @@ -767,17 +765,11 @@ function( $source ) { uasort( $sources, function( $a, $b ) { - if ( $a['filesize'] === $b['filesize'] ) { - return 0; - } - - return ( $a['filesize'] < $b['filesize'] ) ? -1 : 1; + return $a['filesize'] - $b['filesize']; } ); // Create an array of available mime types ordered by smallest filesize. - $mime_types = array_values( array_keys( $sources ) ); - - return $mime_types; + return array_keys( $sources ); } add_filter( 'webp_uploads_content_image_mimes', 'webp_uploads_get_mime_types_by_filesize', 10, 3 ); From b872564d5b6534f762c194bf17ac16c9bdc1079a Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Thu, 24 Mar 2022 14:20:10 +0000 Subject: [PATCH 6/8] update function based on feedback --- modules/images/webp-uploads/load.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 038400c66a..53fc4ea721 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -712,7 +712,6 @@ function webp_uploads_update_rest_attachment( WP_REST_Response $response, WP_Pos * * @param int $attachment_id The attachment ID. * @param string $size The attachment size. - * * @return array The attachment sources array. */ function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail' ) { @@ -741,11 +740,9 @@ function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail * * @param array $mime_types The list of mime types that can be used to update images in the content. * @param int $attachment_id The attachment ID. - * @param string $context The current context. - * * @return array Array of available mime types ordered by filesize. */ -function webp_uploads_get_mime_types_by_filesize( $mime_types, $attachment_id, $context ) { +function webp_uploads_get_mime_types_by_filesize( $mime_types, $attachment_id ) { $sources = webp_uploads_get_attachment_sources( $attachment_id, 'full' ); if ( empty( $sources ) ) { @@ -771,4 +768,4 @@ function( $a, $b ) { // Create an array of available mime types ordered by smallest filesize. return array_keys( $sources ); } -add_filter( 'webp_uploads_content_image_mimes', 'webp_uploads_get_mime_types_by_filesize', 10, 3 ); +add_filter( 'webp_uploads_content_image_mimes', 'webp_uploads_get_mime_types_by_filesize', 10, 2 ); From 64fe72a084893f677201fc0c5d74e5f19c853047 Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Thu, 24 Mar 2022 14:20:25 +0000 Subject: [PATCH 7/8] update tests --- .../images/webp-uploads/webp-uploads-test.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/modules/images/webp-uploads/webp-uploads-test.php b/tests/modules/images/webp-uploads/webp-uploads-test.php index c9401a1d09..c4c3f2f20e 100644 --- a/tests/modules/images/webp-uploads/webp-uploads-test.php +++ b/tests/modules/images/webp-uploads/webp-uploads-test.php @@ -821,8 +821,7 @@ public function it_should_return_smaller_webp_mime_type() { $mime_types = webp_uploads_get_mime_types_by_filesize( array( 'image/jpeg', 'image/webp' ), $attachment_id, 'the_content' ); $this->assertIsArray( $mime_types ); - $this->assertSame( 'image/webp', $mime_types[0] ); - $this->assertSame( 'image/jpeg', $mime_types[1] ); + $this->assertSame( array( 'image/webp', 'image/jpeg' ), $mime_types ); } /** @@ -848,6 +847,8 @@ function( $data, $attachment_id ) { 'filesize' => 2000, ), ); + + return $data; }, 10, 2 @@ -856,8 +857,7 @@ function( $data, $attachment_id ) { $mime_types = webp_uploads_get_mime_types_by_filesize( array( 'image/jpeg', 'image/webp' ), $attachment_id, 'the_content' ); $this->assertIsArray( $mime_types ); - $this->assertSame( 'image/jpeg', $mime_types[0] ); - $this->assertSame( 'image/webp', $mime_types[1] ); + $this->assertSame( array( 'image/jpeg', 'image/webp' ), $mime_types ); } /** @@ -887,6 +887,8 @@ function( $data, $attachment_id ) { 'filesize' => 0, ), ); + + return $data; }, 10, 2 @@ -896,7 +898,6 @@ function( $data, $attachment_id ) { $this->assertIsArray( $mime_types ); $this->assertNotContains( 'image/invalid', $mime_types ); - $this->assertSame( 'image/jpeg', $mime_types[0] ); - $this->assertSame( 'image/webp', $mime_types[1] ); + $this->assertSame( array( 'image/jpeg', 'image/webp' ), $mime_types ); } } From 0374fb5d4be0d1e37c18fae4eef580e5a3a17dca Mon Sep 17 00:00:00 2001 From: jjgrainger Date: Wed, 30 Mar 2022 14:05:19 +0100 Subject: [PATCH 8/8] fix linting errors --- modules/images/webp-uploads/load.php | 4 ++-- tests/modules/images/webp-uploads/webp-uploads-test.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/images/webp-uploads/load.php b/modules/images/webp-uploads/load.php index 563d69d83f..f83c17be61 100644 --- a/modules/images/webp-uploads/load.php +++ b/modules/images/webp-uploads/load.php @@ -738,8 +738,8 @@ function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail * * @since n.e.x.t * - * @param array $mime_types The list of mime types that can be used to update images in the content. - * @param int $attachment_id The attachment ID. + * @param array $mime_types The list of mime types that can be used to update images in the content. + * @param int $attachment_id The attachment ID. * @return array Array of available mime types ordered by filesize. */ function webp_uploads_get_mime_types_by_filesize( $mime_types, $attachment_id ) { diff --git a/tests/modules/images/webp-uploads/webp-uploads-test.php b/tests/modules/images/webp-uploads/webp-uploads-test.php index 124668e9f4..76bd7b57cc 100644 --- a/tests/modules/images/webp-uploads/webp-uploads-test.php +++ b/tests/modules/images/webp-uploads/webp-uploads-test.php @@ -902,11 +902,11 @@ public function it_should_remove_mime_types_with_zero_filesize() { 'wp_get_attachment_metadata', function( $data, $attachment_id ) { $data['sources'] = array( - 'image/jpeg' => array( + 'image/jpeg' => array( 'file' => 'paint.jpeg', 'filesize' => 1000, ), - 'image/webp' => array( + 'image/webp' => array( 'file' => 'paint.webp', 'filesize' => 2000, ),