Skip to content

Commit 160bb6d

Browse files
authored
Merge pull request #227 from WordPress/feature/187-image-format-filters
Allow developers to tweak which image formats to generate on upload
2 parents f546557 + 1babcc9 commit 160bb6d

File tree

7 files changed

+434
-97
lines changed

7 files changed

+434
-97
lines changed

composer.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,10 @@
3434
"dealerdirect/phpcodesniffer-composer-installer": true,
3535
"composer/installers": true
3636
}
37+
},
38+
"autoload-dev": {
39+
"psr-4": {
40+
"PerformanceLab\\Tests\\": "tests/utils"
41+
}
3742
}
3843
}

modules/images/webp-uploads/load.php

Lines changed: 69 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
/**
1212
* Hook called by `wp_generate_attachment_metadata` to create the `sources` property for every image
1313
* size, the sources' property would create a new image size with all the mime types specified in
14-
* `webp_uploads_get_supported_image_mime_transforms`. If the original image is one of the mimes from
15-
* `webp_uploads_get_supported_image_mime_transforms` the image is just added to the `sources` property and not
14+
* `webp_uploads_get_upload_image_mime_transforms`. If the original image is one of the mimes from
15+
* `webp_uploads_get_upload_image_mime_transforms` the image is just added to the `sources` property and not
1616
* created again. If the uploaded attachment is not a supported mime by this function, the hook does not alter the
1717
* metadata of the attachment. In addition to every single size the `sources` property is added at the
1818
* top level of the image metadata to store the references for all the mime types for the `full` size image of the
@@ -21,15 +21,16 @@
2121
* @since 1.0.0
2222
*
2323
* @see wp_generate_attachment_metadata()
24-
* @see webp_uploads_get_supported_image_mime_transforms()
24+
* @see webp_uploads_get_upload_image_mime_transforms()
2525
*
2626
* @param array $metadata An array with the metadata from this attachment.
2727
* @param int $attachment_id The ID of the attachment where the hook was dispatched.
2828
* @return array An array with the updated structure for the metadata before is stored in the database.
2929
*/
3030
function webp_uploads_create_sources_property( array $metadata, $attachment_id ) {
3131
// This should take place only on the JPEG image.
32-
$valid_mime_transforms = webp_uploads_get_supported_image_mime_transforms();
32+
$valid_mime_transforms = webp_uploads_get_upload_image_mime_transforms();
33+
3334
// Not a supported mime type to create the sources property.
3435
$mime_type = get_post_mime_type( $attachment_id );
3536
if ( ! isset( $valid_mime_transforms[ $mime_type ] ) ) {
@@ -47,7 +48,10 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id )
4748
$metadata['sources'] = array();
4849
}
4950

50-
if ( empty( $metadata['sources'][ $mime_type ] ) ) {
51+
if (
52+
empty( $metadata['sources'][ $mime_type ] ) &&
53+
in_array( $mime_type, $valid_mime_transforms[ $mime_type ], true )
54+
) {
5155
$metadata['sources'][ $mime_type ] = array(
5256
'file' => wp_basename( $file ),
5357
'filesize' => filesize( $file ),
@@ -64,6 +68,7 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id )
6468
$original_directory = pathinfo( $file, PATHINFO_DIRNAME );
6569
$filename = pathinfo( $file, PATHINFO_FILENAME );
6670
$allowed_mimes = array_flip( wp_get_mime_types() );
71+
6772
// Create the sources for the full sized image.
6873
foreach ( $valid_mime_transforms[ $mime_type ] as $targeted_mime ) {
6974
// If this property exists no need to create the image again.
@@ -131,9 +136,7 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id )
131136
wp_update_attachment_metadata( $attachment_id, $metadata );
132137
}
133138

134-
$formats = isset( $valid_mime_transforms[ $current_mime ] ) ? $valid_mime_transforms[ $current_mime ] : array();
135-
136-
foreach ( $formats as $mime ) {
139+
foreach ( $valid_mime_transforms[ $mime_type ] as $mime ) {
137140
// If this property exists no need to create the image again.
138141
if ( ! empty( $properties['sources'][ $mime ] ) ) {
139142
continue;
@@ -154,9 +157,42 @@ function webp_uploads_create_sources_property( array $metadata, $attachment_id )
154157

155158
return $metadata;
156159
}
157-
158160
add_filter( 'wp_generate_attachment_metadata', 'webp_uploads_create_sources_property', 10, 2 );
159161

162+
/**
163+
* Filter the image editor default output format mapping to select the most appropriate
164+
* output format depending on desired output formats and supported mime types by the image
165+
* editor.
166+
*
167+
* @since n.e.x.t
168+
*
169+
* @param string $output_format The image editor default output format mapping.
170+
* @param string $filename Path to the image.
171+
* @param string $mime_type The source image mime type.
172+
* @return string The new output format mapping.
173+
*/
174+
function webp_uploads_filter_image_editor_output_format( $output_format, $filename, $mime_type ) {
175+
// Use the original mime type if this type is allowed.
176+
$valid_mime_transforms = webp_uploads_get_upload_image_mime_transforms();
177+
if (
178+
! isset( $valid_mime_transforms[ $mime_type ] ) ||
179+
in_array( $mime_type, $valid_mime_transforms[ $mime_type ], true )
180+
) {
181+
return $output_format;
182+
}
183+
184+
// Find the first supported mime type by the image editor to use it as the default one.
185+
foreach ( $valid_mime_transforms[ $mime_type ] as $target_mime ) {
186+
if ( wp_image_editor_supports( array( 'mime_type' => $target_mime ) ) ) {
187+
$output_format[ $mime_type ] = $target_mime;
188+
break;
189+
}
190+
}
191+
192+
return $output_format;
193+
}
194+
add_filter( 'image_editor_output_format', 'webp_uploads_filter_image_editor_output_format', 10, 3 );
195+
160196
/**
161197
* Creates a new image based of the specified attachment with a defined mime type
162198
* this image would be stored in the same place as the provided size name inside the
@@ -217,30 +253,40 @@ function webp_uploads_generate_image_size( $attachment_id, $size, $mime ) {
217253
*
218254
* @return array<string, array<string>> An array of valid mime types, where the key is the mime type and the value is the extension type.
219255
*/
220-
function webp_uploads_get_supported_image_mime_transforms() {
221-
$image_mime_transforms = array(
222-
'image/jpeg' => array( 'image/webp' ),
223-
'image/webp' => array( 'image/jpeg' ),
256+
function webp_uploads_get_upload_image_mime_transforms() {
257+
$default_transforms = array(
258+
'image/jpeg' => array( 'image/jpeg', 'image/webp' ),
259+
'image/webp' => array( 'image/webp', 'image/jpeg' ),
224260
);
225261

226-
$valid_transforms = array();
227262
/**
228263
* Filter to allow the definition of a custom mime types, in which a defined mime type
229264
* can be transformed and provide a wide range of mime types.
230265
*
266+
* The order of supported mime types matters. If the original mime type of the uploaded image
267+
* is not needed, then the first mime type in the list supported by the image editor will be
268+
* selected for the default subsizes.
269+
*
231270
* @since 1.0.0
232271
*
233-
* @param array $image_mime_transforms A map with the valid mime transforms.
272+
* @param array $default_transforms A map with the valid mime transforms.
234273
*/
235-
$transforms = (array) apply_filters( 'webp_uploads_supported_image_mime_transforms', $image_mime_transforms );
236-
// Remove any invalid transform, by making sure all the transform values are arrays.
237-
foreach ( $transforms as $mime => $list_transforms ) {
238-
if ( ! is_array( $list_transforms ) ) {
239-
continue;
274+
$transforms = (array) apply_filters( 'webp_uploads_upload_image_mime_transforms', $default_transforms );
275+
276+
// Return the default mime transforms if a non-array result is returned from the filter.
277+
if ( ! is_array( $transforms ) ) {
278+
return $default_transforms;
279+
}
280+
281+
// Ensure that all mime types have correct transforms. If a mime type has invalid transforms array,
282+
// then fallback to the original mime type to make sure that the correct subsizes are created.
283+
foreach ( $transforms as $mime_type => $transform_types ) {
284+
if ( ! is_array( $transform_types ) || empty( $transform_types ) ) {
285+
$transforms[ $mime_type ] = array( $mime_type );
240286
}
241-
$valid_transforms[ $mime ] = $list_transforms;
242287
}
243-
return $valid_transforms;
288+
289+
return $transforms;
244290
}
245291

246292
/**
@@ -416,7 +462,6 @@ function webp_uploads_remove_sources_files( $attachment_id ) {
416462
wp_delete_file_from_directory( $full_size_file, $intermediate_dir );
417463
}
418464
}
419-
420465
add_action( 'delete_attachment', 'webp_uploads_remove_sources_files', 10, 1 );
421466

422467
/**
@@ -463,7 +508,6 @@ function webp_uploads_wp_get_missing_image_subsizes( $missing_sizes, $image_meta
463508

464509
return array();
465510
}
466-
467511
add_filter( 'wp_get_missing_image_subsizes', 'webp_uploads_wp_get_missing_image_subsizes', 10, 3 );
468512

469513
/**
@@ -524,6 +568,7 @@ function webp_uploads_update_image_references( $content ) {
524568

525569
return $content;
526570
}
571+
add_filter( 'the_content', 'webp_uploads_update_image_references', 10 );
527572

528573
/**
529574
* Finds all the urls with *.jpg and *.jpeg extension and updates with *.webp version for the provided image
@@ -602,8 +647,6 @@ function webp_uploads_img_tag_update_mime_type( $image, $context, $attachment_id
602647
return $image;
603648
}
604649

605-
add_filter( 'the_content', 'webp_uploads_update_image_references', 10 );
606-
607650
/**
608651
* Updates the response for an attachment to include sources for additional mime types available the image.
609652
*
@@ -639,5 +682,4 @@ function webp_uploads_update_rest_attachment( WP_REST_Response $response, WP_Pos
639682

640683
return rest_ensure_response( $data );
641684
}
642-
643685
add_filter( 'rest_prepare_attachment', 'webp_uploads_update_rest_attachment', 10, 3 );

phpcs.xml.dist

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,20 @@
4646
<rule ref="Squiz.Commenting.FunctionCommentThrowTag.Missing">
4747
<exclude-pattern>tests/*</exclude-pattern>
4848
</rule>
49+
50+
<!-- Do not apply filename rules for unit tests -->
51+
<rule ref="WordPress.Files.FileName.NotHyphenatedLowercase">
52+
<exclude-pattern>tests/*</exclude-pattern>
53+
</rule>
54+
<rule ref="WordPress.Files.FileName.InvalidClassFileName">
55+
<exclude-pattern>tests/*</exclude-pattern>
56+
</rule>
57+
58+
<!-- Do not apply compatibility rules to allow using the modern PHPUnit functionality -->
59+
<rule ref="PHPCompatibility.FunctionDeclarations.NewReturnTypeDeclarations.stringFound">
60+
<exclude-pattern>tests/utils/*</exclude-pattern>
61+
</rule>
62+
<rule ref="PHPCompatibility.FunctionDeclarations.NewReturnTypeDeclarations.boolFound">
63+
<exclude-pattern>tests/utils/*</exclude-pattern>
64+
</rule>
4965
</ruleset>

0 commit comments

Comments
 (0)