Skip to content
46 changes: 37 additions & 9 deletions src/wp-admin/includes/image.php
Original file line number Diff line number Diff line change
Expand Up @@ -505,13 +505,20 @@ function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id, $mim
return array();
}

$original_mime_type = wp_get_image_mime( $file );

if ( ! $mime_type ) {
$mime_type = wp_get_image_mime( $file );
$mime_type = $original_mime_type;
}

// Check if any of the new sizes already exist.
if ( isset( $image_meta['sizes'] ) && is_array( $image_meta['sizes'] ) ) {
foreach ( $image_meta['sizes'] as $size_name => $size_meta ) {
// Check if the output mime is enabled for this image size.
if ( ! _wp_mime_type_available_for_image_size( $attachment_id, $size_name, $original_mime_type, $mime_type ) ) {
continue;
}

/*
* Only checks "size name" so we don't override existing images even if the dimensions
* don't match the currently defined size with the same name.
Expand Down Expand Up @@ -605,6 +612,21 @@ function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id, $mim
return $image_meta;
}

/**
* Check whether mime type output is available for a given size and mime type.
*
* @since 6.1.0
*
* @param int $attachment_id Attachment ID.
* @param string $size_name Size name to check.
* @return bool Whether the size is available for the given mime type.
*/
function _wp_mime_type_available_for_image_size( $attachment_id, $size_name, $source_mime, $destination_mime ) {
$image_mime_transforms = wp_upload_image_mime_transforms( $attachment_id, $size_name );

return isset( $image_mime_transforms[ $source_mime ] [ $destination_mime ] ) && image_size_supports_mime( $size_name, $destination_mime );
}

/**
* Low-level function to create full-size images in additional mime types.
*
Expand Down Expand Up @@ -1336,28 +1358,34 @@ function _copy_image_file( $attachment_id ) {
* For example an `image/jpeg` should be converted into an `image/jpeg` and `image/webp`. The first type
* is considered the primary output type for this image.
*
* Called for each uploaded image to determine the list of mime types that should be converted into. Then,
* called again for each target image size as they are generated to see if the image should be converted into the mime type
* for that size.
*
* @since 6.1.0
*
* @param $attachment_id int The attachment ID.
* @param int $attachment_id The attachment ID.
* @param string $image_size The image size name. False when called on the image and target size is unavailable.
* @return array An array of valid mime types, where the key is the source file mime type and the list of mime types to
* generate.
*/
function wp_upload_image_mime_transforms( $attachment_id ) {
function wp_upload_image_mime_transforms( $attachment_id, $image_size ) {
$image_mime_transforms = array(
'image/jpeg' => array( 'image/jpeg', 'image/webp' ),
'image/webp' => array( 'image/webp', 'image/jpeg' ),
);

/**
* Filter to the output mime types for a given input mime type.
* Filter to the output mime types for a given input mime type and image size.
*
* @since 6.1.0
*
* @param array $image_mime_transforms A map with the valid mime transforms where the key is the source file mime type
* and the value is one or more mime file types to generate.
* @param int $attachment_id The ID of the attachment where the hook was dispatched.
* @param array $image_mime_transforms A map with the valid mime transforms where the key is the source file mime type
* and the value is one or more mime file types to generate.
* @param int $attachment_id The ID of the attachment where the hook was dispatched.
* @param string $image_size The image size name. Optional.
*/
return (array) apply_filters( 'wp_upload_image_mime_transforms', $image_mime_transforms, $attachment_id );
return (array) apply_filters( 'wp_upload_image_mime_transforms', $image_mime_transforms, $attachment_id, $image_size );
}

/**
Expand All @@ -1371,7 +1399,7 @@ function wp_upload_image_mime_transforms( $attachment_id ) {
* @return array An array with two entries, the primary mime type and the list of additional mime types.
*/
function _wp_get_primary_and_additional_mime_types( $file, $attachment_id ) {
$image_mime_transforms = wp_upload_image_mime_transforms( $attachment_id );
$image_mime_transforms = wp_upload_image_mime_transforms( $attachment_id, false );
$original_mime_type = wp_get_image_mime( $file );
$output_mime_types = isset( $image_mime_transforms[ $original_mime_type ] ) ? $image_mime_transforms[ $original_mime_type ] : array( $original_mime_type );

Expand Down
4 changes: 2 additions & 2 deletions src/wp-content/themes/twentyeleven/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,9 @@ function twentyeleven_setup() {
* Add Twenty Eleven's custom image sizes.
* Used for large feature (header) images.
*/
add_image_size( 'large-feature', $custom_header_support['width'], $custom_header_support['height'], true );
add_image_size( 'large-feature', $custom_header_support['width'], $custom_header_support['height'], true, true );
// Used for featured posts if a large-feature doesn't exist.
add_image_size( 'small-feature', 500, 300 );
add_image_size( 'small-feature', 500, 300, false, true );

// Default custom headers packaged with the theme. %s is a placeholder for the theme template directory URI.
register_default_headers(
Expand Down
2 changes: 1 addition & 1 deletion src/wp-content/themes/twentyfourteen/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ function twentyfourteen_setup() {
// Enable support for Post Thumbnails, and declare two sizes.
add_theme_support( 'post-thumbnails' );
set_post_thumbnail_size( 672, 372, true );
add_image_size( 'twentyfourteen-full-width', 1038, 576, true );
add_image_size( 'twentyfourteen-full-width', 1038, 576, true, true );

// This theme uses wp_nav_menu() in two locations.
register_nav_menus(
Expand Down
4 changes: 2 additions & 2 deletions src/wp-content/themes/twentyseventeen/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ function twentyseventeen_setup() {
*/
add_theme_support( 'post-thumbnails' );

add_image_size( 'twentyseventeen-featured-image', 2000, 1200, true );
add_image_size( 'twentyseventeen-featured-image', 2000, 1200, true, true );

add_image_size( 'twentyseventeen-thumbnail-avatar', 100, 100, true );
add_image_size( 'twentyseventeen-thumbnail-avatar', 100, 100, true, true );

// Set the default content width.
$GLOBALS['content_width'] = 525;
Expand Down
2 changes: 1 addition & 1 deletion src/wp-content/themes/twentytwenty/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function twentytwenty_theme_support() {
set_post_thumbnail_size( 1200, 9999 );

// Add custom image size used in Cover Template.
add_image_size( 'twentytwenty-fullscreen', 1980, 9999 );
add_image_size( 'twentytwenty-fullscreen', 1980, 9999, false, true );

// Custom logo.
$logo_width = 120;
Expand Down
72 changes: 51 additions & 21 deletions src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -275,29 +275,55 @@ function image_downsize( $id, $size = 'medium' ) {
* Register a new image size.
*
* @since 2.9.0
* @since 6.1.0 Add the $output_mimes parameter.
*
* @global array $_wp_additional_image_sizes Associative array of additional image sizes.
*
* @param string $name Image size identifier.
* @param int $width Optional. Image width in pixels. Default 0.
* @param int $height Optional. Image height in pixels. Default 0.
* @param bool|array $crop Optional. Image cropping behavior. If false, the image will be scaled (default),
* If true, image will be cropped to the specified dimensions using center positions.
* If an array, the image will be cropped using the array to specify the crop location.
* Array values must be in the format: array( x_crop_position, y_crop_position ) where:
* - x_crop_position accepts: 'left', 'center', or 'right'.
* - y_crop_position accepts: 'top', 'center', or 'bottom'.
* @param string $name Image size identifier.
* @param int $width Optional. Image width in pixels. Default 0.
* @param int $height Optional. Image height in pixels. Default 0.
* @param bool|array $crop Optional. Image cropping behavior. If false, the image will be scaled (default),
* If true, image will be cropped to the specified dimensions using center positions.
* If an array, the image will be cropped using the array to specify the crop location.
* Array values must be in the format: array( x_crop_position, y_crop_position ) where:
* - x_crop_position accepts: 'left', 'center', or 'right'.
* - y_crop_position accepts: 'top', 'center', or 'bottom'.
* @param bool $output_mimes Whether to output secondary mimes for this image size. Default is null which will
* throw a doing_it_wrong warning to warn developers they should set this value.
* Default will be true in 6.2.
*/
function add_image_size( $name, $width = 0, $height = 0, $crop = false ) {
function add_image_size( $name, $width = 0, $height = 0, $crop = false, $output_mimes = null ) {
global $_wp_additional_image_sizes;

// For 6.1.x, warn developers about setting a value for $output_mimes.
if ( null === $output_mimes ) {
_doing_it_wrong( __FUNCTION__, __( 'Passing the $output_mimes parameter to add_image_size is recommended.' ), '6.1.0' );
}

$_wp_additional_image_sizes[ $name ] = array(
'width' => absint( $width ),
'height' => absint( $height ),
'crop' => $crop,
'width' => absint( $width ),
'height' => absint( $height ),
'crop' => $crop,
'output_mimes' => $output_mimes,
);
}

/**
* Check if an image size supports output in a specific mime type.
*
* @since 6.1.0
*
* @uses wp_get_additional_image_sizes()
*
* @param string $name Image size identifier.
* @param string $mime_type The mime type to check.
* @return bool Whether the size supports the mime type for output.
*/
function image_size_supports_mime( $name, $mime_type ) {
$sizes = wp_get_additional_image_sizes();
return isset( $sizes[ $name ]['output_mimes'] ) && $sizes[ $name ]['output_mimes'];
}

/**
* Check if an image size exists.
*
Expand Down Expand Up @@ -345,7 +371,7 @@ function remove_image_size( $name ) {
* An array can specify positioning of the crop area. Default false.
*/
function set_post_thumbnail_size( $width = 0, $height = 0, $crop = false ) {
add_image_size( 'post-thumbnail', $width, $height, $crop );
add_image_size( 'post-thumbnail', $width, $height, $crop, true );
}

/**
Expand Down Expand Up @@ -890,11 +916,15 @@ function wp_get_registered_image_subsizes() {
$all_sizes = array();

foreach ( get_intermediate_image_sizes() as $size_name ) {
$size_data = array(
'width' => 0,
'height' => 0,
'crop' => false,
);
$default_sizes = array( 'thumbnail', 'medium', 'medium_large', 'large' );
foreach ( get_intermediate_image_sizes() as $size_name ) {
$size_data = array(
'width' => 0,
'height' => 0,
'crop' => false,
'output_mimes' => in_array( $size_name, $default_sizes, true ),
);
}

if ( isset( $additional_sizes[ $size_name ]['width'] ) ) {
// For sizes added by plugins and themes.
Expand Down Expand Up @@ -5292,9 +5322,9 @@ function wp_media_personal_data_exporter( $email_address, $page = 1 ) {
*/
function _wp_add_additional_image_sizes() {
// 2x medium_large size.
add_image_size( '1536x1536', 1536, 1536 );
add_image_size( '1536x1536', 1536, 1536, false, true );
// 2x large size.
add_image_size( '2048x2048', 2048, 2048 );
add_image_size( '2048x2048', 2048, 2048, false, true );
}

/**
Expand Down
15 changes: 15 additions & 0 deletions tests/phpunit/tests/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,21 @@ public function test_has_image_size() {
remove_image_size( 'test-size' );
}

/**
* @ticket 55443
*/
public function test_image_size_supports_mime() {
add_image_size( 'test-size', 200, 600, true, false );
$this->assertSame( false, image_size_supports_mime( 'test-size', 'image/webp' ) );
remove_image_size( 'test-size' );

add_image_size( 'test-size', 200, 600, true, true );
$this->assertSame( true, image_size_supports_mime( 'test-size', 'image/webp' ) );

// Clean up.
remove_image_size( 'test-size' );
}

/**
* @ticket 30346
*/
Expand Down