Skip to content
65 changes: 65 additions & 0 deletions modules/images/webp-uploads/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -704,3 +704,68 @@ 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.x.t
*
* @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();
}

/**
* 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.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.
* @return array Array of available mime types ordered by filesize.
*/
function webp_uploads_get_mime_types_by_filesize( $mime_types, $attachment_id ) {
$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 isset( $source['filesize'] ) && $source['filesize'] > 0;
}
);

// Order sources by filesize in ascending order.
uasort(
$sources,
function( $a, $b ) {
return $a['filesize'] - $b['filesize'];
}
);

// 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, 2 );
92 changes: 92 additions & 0 deletions tests/modules/images/webp-uploads/webp-uploads-test.php
Original file line number Diff line number Diff line change
Expand Up @@ -836,4 +836,96 @@ function () {
$this->assertImageHasSizeSource( $attachment_id, 'thumbnail', 'image/jpeg' );
$this->assertImageHasSizeSource( $attachment_id, 'thumbnail', 'image/webp' );
}

/**
* 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( array( 'image/webp', 'image/jpeg' ), $mime_types );
}

/**
* 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 ) {
Comment thread
mitogh marked this conversation as resolved.
$data['sources'] = array(
'image/jpeg' => array(
'file' => 'paint.jpeg',
'filesize' => 1000,
),
'image/webp' => array(
'file' => 'paint.webp',
'filesize' => 2000,
),
);

return $data;
},
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( array( 'image/jpeg', 'image/webp' ), $mime_types );
}

/**
* 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(
Comment thread
mitogh marked this conversation as resolved.
'image/jpeg' => array(
'file' => 'paint.jpeg',
'filesize' => 1000,
),
'image/webp' => array(
'file' => 'paint.webp',
'filesize' => 2000,
),
'image/invalid' => array(
'file' => 'paint.avif',
'filesize' => 0,
),
);

return $data;
},
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( array( 'image/jpeg', 'image/webp' ), $mime_types );
}
}