diff --git a/src/wp-admin/includes/image.php b/src/wp-admin/includes/image.php index 2ad8b43180c2c..5cce0f2fbcac4 100644 --- a/src/wp-admin/includes/image.php +++ b/src/wp-admin/includes/image.php @@ -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. @@ -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. * @@ -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 ); } /** @@ -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 ); diff --git a/src/wp-content/themes/twentyeleven/functions.php b/src/wp-content/themes/twentyeleven/functions.php index 12593aaddfeb5..ee95afd96b5f9 100644 --- a/src/wp-content/themes/twentyeleven/functions.php +++ b/src/wp-content/themes/twentyeleven/functions.php @@ -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( diff --git a/src/wp-content/themes/twentyfourteen/functions.php b/src/wp-content/themes/twentyfourteen/functions.php index 0695bcce6dccb..0896f84410066 100644 --- a/src/wp-content/themes/twentyfourteen/functions.php +++ b/src/wp-content/themes/twentyfourteen/functions.php @@ -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( diff --git a/src/wp-content/themes/twentyseventeen/functions.php b/src/wp-content/themes/twentyseventeen/functions.php index 3d933989c2b61..d8b95b8568e47 100644 --- a/src/wp-content/themes/twentyseventeen/functions.php +++ b/src/wp-content/themes/twentyseventeen/functions.php @@ -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; diff --git a/src/wp-content/themes/twentytwenty/functions.php b/src/wp-content/themes/twentytwenty/functions.php index c8944e03c1e14..21a561fdaf820 100644 --- a/src/wp-content/themes/twentytwenty/functions.php +++ b/src/wp-content/themes/twentytwenty/functions.php @@ -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; diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index 74bae684fcdaa..19c27585ec443 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -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. * @@ -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 ); } /** @@ -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. @@ -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 ); } /** diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index 56c8ba53b3dee..58397eeee8aaf 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -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 */