Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
32 changes: 32 additions & 0 deletions modules/images/webp-uploads/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,35 @@ function webp_uploads_get_attachment_sources( $attachment_id, $size = 'thumbnail
// Return an empty array if no sources found.
return array();
}

/**
* Check whether the additional image is larger than the original image.
*
* @since n.e.x.t
*
* @param array $original An array with the metadata of the attachment.
* @param array $additional An array containing the filename and file size for additional mime.
* @return bool True if the additional image is larger than the original image, otherwise false.
*/
function webp_uploads_should_discard_additional_image_file( array $original, array $additional ) {
$original_image_filesize = isset( $original['filesize'] ) ? (int) $original['filesize'] : 0;
$additional_image_filesize = isset( $additional['filesize'] ) ? (int) $additional['filesize'] : 0;
if ( $original_image_filesize > 0 && $additional_image_filesize > 0 ) {
/**
* Filter whether WebP images that are larger than the matching JPEG should be discarded.
*
* By default the performance lab plugin will use the mime type with the smaller filesize
* rather than defaulting to `webp`.
*
* @since n.e.x.t
*
* @param bool $preferred_filesize Prioritize file size over mime type. Default true.
*/
$webp_discard_larger_images = apply_filters( 'webp_uploads_discard_larger_generated_images', true );

if ( $webp_discard_larger_images && $additional_image_filesize >= $original_image_filesize ) {
return true;
}
}
return false;
}
159 changes: 67 additions & 92 deletions modules/images/webp-uploads/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id )
continue;
}

if ( webp_uploads_should_discard_additional_image_file( $metadata, $image ) ) {
wp_delete_file_from_directory( $destination, $original_directory );
continue;
}

$metadata['sources'][ $targeted_mime ] = $image;
wp_update_attachment_metadata( $attachment_id, $metadata );
}
Expand Down Expand Up @@ -154,6 +159,12 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id )
continue;
}

if ( webp_uploads_should_discard_additional_image_file( $properties, $source ) ) {
$destination = path_join( $original_directory, $source['file'] );
wp_delete_file_from_directory( $destination, $original_directory );
continue;
}

$properties['sources'][ $mime ] = $source;
$metadata['sizes'][ $size_name ] = $properties;
wp_update_attachment_metadata( $attachment_id, $metadata );
Expand Down Expand Up @@ -415,6 +426,7 @@ function webp_uploads_update_image_references( $content ) {
* for the specified image sizes, the *.webp references are stored inside of each size.
*
* @since 1.0.0
* @since n.e.x.t Remove `webp_uploads_prefer_smaller_image_file` filter
*
* @param string $image An <img> tag where the urls would be updated.
* @param string $context The context where this is function is being used.
Expand All @@ -423,24 +435,11 @@ function webp_uploads_update_image_references( $content ) {
*/
function webp_uploads_img_tag_update_mime_type( $image, $context, $attachment_id ) {
$metadata = wp_get_attachment_metadata( $attachment_id );

if ( empty( $metadata['file'] ) ) {
return $image;
}

/**
* Filters whether the smaller image should be used regardless of which MIME type is preferred overall.
*
* This is disabled by default only because it is not part of the current WordPress core feature proposal.
*
* By enabling this, the plugin will compare the image file sizes and prefer the smaller file regardless of MIME
* type.
*
* @since 1.0.0
*
* @param bool $prefer_smaller_image_file Whether to prefer the smaller image file.
*/
$prefer_smaller_image_file = apply_filters( 'webp_uploads_prefer_smaller_image_file', false );

/**
* Filters mime types that should be used to update all images in the content. The order of
* mime types matters. The first mime type in the list will be used if it is supported by an image.
Expand All @@ -456,63 +455,42 @@ function webp_uploads_img_tag_update_mime_type( $image, $context, $attachment_id
// Get the original mime type for comparison.
$original_mime = get_post_mime_type( $attachment_id );

$target_mime = null;
foreach ( $target_mimes as $mime ) {
if ( isset( $metadata['sources'][ $mime ] ) ) {
$target_mime = $mime;
break;
}
}

if ( null === $target_mime ) {
return $image;
}
foreach ( $target_mimes as $target_mime ) {

// Replace the full size image if present.
if ( isset( $metadata['sources'][ $target_mime ]['file'] ) ) {
// Initially set the target mime as the replacement source.
$replacement_source = $metadata['sources'][ $target_mime ]['file'];

// Check for the smaller image file.
if (
$prefer_smaller_image_file &&
! empty( $metadata['sources'][ $target_mime ]['filesize'] ) &&
! empty( $metadata['sources'][ $original_mime ]['filesize'] ) &&
$metadata['sources'][ $original_mime ]['filesize'] < $metadata['sources'][ $target_mime ]['filesize']
) {
// Set the original source file as the replacement if smaller.
$replacement_source = $metadata['sources'][ $original_mime ]['file'];
if ( $target_mime === $original_mime ) {
continue;
}

$basename = wp_basename( $metadata['file'] );
if ( $basename !== $replacement_source ) {
if ( ! isset( $metadata['sources'][ $target_mime ]['file'] ) ) {
continue;
}

/**
* Filter to replace additional image source file, by locating the original
* mime types of the file and return correct file path in the end.
*
* Altering the $image tag through this filter effectively short-circuits the default replacement logic using the preferred MIME type.
*
* @since 1.1.0
*
* @param string $image An <img> tag where the urls would be updated.
* @param int $attachment_id The ID of the attachment being modified.
* @param string $size The size name that would be used to create this image, out of the registered subsizes.
* @param string $target_mime The target mime in which the image should be created.
* @param string $context The context where this is function is being used.
*/
$filtered_image = (string) apply_filters( 'webp_uploads_pre_replace_additional_image_source', $image, $attachment_id, 'full', $target_mime, $context );
/**
* Filter to replace additional image source file, by locating the original
* mime types of the file and return correct file path in the end.
*
* Altering the $image tag through this filter effectively short-circuits the default replacement logic using the preferred MIME type.
*
* @since 1.1.0
*
* @param string $image An <img> tag where the urls would be updated.
* @param int $attachment_id The ID of the attachment being modified.
* @param string $size The size name that would be used to create this image, out of the registered subsizes.
* @param string $target_mime The target mime in which the image should be created.
* @param string $context The context where this is function is being used.
*/
$filtered_image = (string) apply_filters( 'webp_uploads_pre_replace_additional_image_source', $image, $attachment_id, 'full', $target_mime, $context );

// If filtered image is same as the image, run our own replacement logic, otherwise rely on the filtered image.
if ( $filtered_image === $image ) {
$image = str_replace(
$basename,
$metadata['sources'][ $target_mime ]['file'],
$image
);
} else {
$image = $filtered_image;
}
// If filtered image is same as the image, run our own replacement logic, otherwise rely on the filtered image.
if ( $filtered_image === $image ) {
$basename = wp_basename( $metadata['file'] );
$image = str_replace(
$basename,
$metadata['sources'][ $target_mime ]['file'],
$image
);
} else {
$image = $filtered_image;
}
}

Expand All @@ -522,36 +500,33 @@ function webp_uploads_img_tag_update_mime_type( $image, $context, $attachment_id
continue;
}

if ( empty( $size_data['sources'][ $target_mime ]['file'] ) ) {
continue;
}
foreach ( $target_mimes as $target_mime ) {

if ( $size_data['file'] === $size_data['sources'][ $target_mime ]['file'] ) {
continue;
}
if ( $target_mime === $original_mime ) {
continue;
}

// Do not update image URL if the target image is larger than the original.
if (
$prefer_smaller_image_file &&
! empty( $size_data['sources'][ $target_mime ]['filesize'] ) &&
! empty( $size_data['sources'][ $original_mime ]['filesize'] ) &&
$size_data['sources'][ $original_mime ]['filesize'] < $size_data['sources'][ $target_mime ]['filesize']
) {
continue;
}
if ( ! isset( $size_data['sources'][ $target_mime ]['file'] ) ) {
continue;
}

/** This filter is documented in modules/images/webp-uploads/load.php */
$filtered_image = (string) apply_filters( 'webp_uploads_pre_replace_additional_image_source', $image, $attachment_id, $size, $target_mime, $context );
if ( $size_data['file'] === $size_data['sources'][ $target_mime ]['file'] ) {
continue;
}

// If filtered image is same as the image, run our own replacement logic, otherwise rely on the filtered image.
if ( $filtered_image === $image ) {
$image = str_replace(
$size_data['file'],
$size_data['sources'][ $target_mime ]['file'],
$image
);
} else {
$image = $filtered_image;
/** This filter is documented in modules/images/webp-uploads/load.php */
$filtered_image = (string) apply_filters( 'webp_uploads_pre_replace_additional_image_source', $image, $attachment_id, $size, $target_mime, $context );

// If filtered image is same as the image, run our own replacement logic, otherwise rely on the filtered image.
if ( $filtered_image === $image ) {
$image = str_replace(
$size_data['file'],
$size_data['sources'][ $target_mime ]['file'],
$image
);
} else {
$image = $filtered_image;
}
}
}

Expand Down
48 changes: 48 additions & 0 deletions tests/modules/images/webp-uploads/helper-tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -410,4 +410,52 @@ function () {
$this->assertIsArray( $transforms );
$this->assertSame( array( 'image/jpeg' => array( 'image/jpeg', 'image/webp' ) ), $transforms );
}

/**
* Tests the webp_uploads_discard_larger_generated_images filter.
*
* @dataProvider data_provider_image_filesize
*
* @test
*/
public function it_should_check_if_the_additional_image_is_larger_than_the_original_image( $original_filesize, $additional_filesize, $expected_status ) {
add_filter( 'webp_uploads_discard_larger_generated_images', '__return_true' );

$output = webp_uploads_should_discard_additional_image_file( $original_filesize, $additional_filesize );
$this->assertSame( $output, $expected_status );
}

public function data_provider_image_filesize() {
return array(
array(
array( 'filesize' => 120101 ),
array( 'filesize' => 100101 ),
false,
),
array(
array( 'filesize' => 100101 ),
array( 'filesize' => 120101 ),
true,
),
array(
array( 'filesize' => 10101 ),
array( 'filesize' => 10101 ),
true,
),
);
}

/**
* Check the disabled behaviour of the webp_uploads_discard_larger_generated_images filter.
*
* @dataProvider data_provider_image_filesize
*
* @test
*/
public function it_should_return_an_additional_image_if_it_is_bigger_than_original( $original_filesize, $additional_filesize ) {
add_filter( 'webp_uploads_discard_larger_generated_images', '__return_false' );

$output = webp_uploads_should_discard_additional_image_file( $original_filesize, $additional_filesize );
$this->assertSame( $output, false );
}
}
6 changes: 6 additions & 0 deletions tests/modules/images/webp-uploads/image-edit-tests.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

class WebP_Uploads_Image_Edit_Tests extends ImagesTestCase {

public function set_up() {
parent::set_up();

add_filter( 'webp_uploads_discard_larger_generated_images', '__return_false' );
}

/**
* Backup the sources structure alongside the full size
*
Expand Down
Loading