wp_create_image_subsizes

The timeline below displays how wordpress function wp_create_image_subsizes has changed across different WordPress versions. If a version is not listed, refer to the next available version below.

WordPress Version: 6.3

/**
 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
 *
 * Intended for use after an image is uploaded. Saves/updates the image metadata after each
 * sub-size is created. If there was an error, it is added to the returned image metadata array.
 *
 * @since 5.3.0
 *
 * @param string $file          Full path to the image file.
 * @param int    $attachment_id Attachment ID to process.
 * @return array The image attachment meta data.
 */
function wp_create_image_subsizes($file, $attachment_id)
{
    $imagesize = wp_getimagesize($file);
    if (empty($imagesize)) {
        // File is not an image.
        return array();
    }
    // Default image meta.
    $image_meta = array('width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path($file), 'filesize' => wp_filesize($file), 'sizes' => array());
    // Fetch additional metadata from EXIF/IPTC.
    $exif_meta = wp_read_image_metadata($file);
    if ($exif_meta) {
        $image_meta['image_meta'] = $exif_meta;
    }
    // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
    if ('image/png' !== $imagesize['mime']) {
        /**
         * Filters the "BIG image" threshold value.
         *
         * If the original image width or height is above the threshold, it will be scaled down. The threshold is
         * used as max width and max height. The scaled down image will be used as the largest available size, including
         * the `_wp_attached_file` post meta value.
         *
         * Returning `false` from the filter callback will disable the scaling.
         *
         * @since 5.3.0
         *
         * @param int    $threshold     The threshold value in pixels. Default 2560.
         * @param array  $imagesize     {
         *     Indexed array of the image width and height in pixels.
         *
         *     @type int $0 The image width.
         *     @type int $1 The image height.
         * }
         * @param string $file          Full path to the uploaded image file.
         * @param int    $attachment_id Attachment post ID.
         */
        $threshold = (int) apply_filters('big_image_size_threshold', 2560, $imagesize, $file, $attachment_id);
        /*
         * If the original image's dimensions are over the threshold,
         * scale the image and use it as the "full" size.
         */
        if ($threshold && ($image_meta['width'] > $threshold || $image_meta['height'] > $threshold)) {
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Resize the image.
            $resized = $editor->resize($threshold, $threshold);
            $rotated = null;
            // If there is EXIF data, rotate according to EXIF Orientation.
            if (!is_wp_error($resized) && is_array($exif_meta)) {
                $resized = $editor->maybe_exif_rotate();
                $rotated = $resized;
            }
            if (!is_wp_error($resized)) {
                /*
                 * Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
                 * This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
                 */
                $saved = $editor->save($editor->generate_filename('scaled'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // If the image was rotated update the stored EXIF data.
                    if (true === $rotated && !empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            } else {
                // TODO: Log errors.
            }
        } elseif (!empty($exif_meta['orientation']) && 1 !== (int) $exif_meta['orientation']) {
            // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Rotate the image.
            $rotated = $editor->maybe_exif_rotate();
            if (true === $rotated) {
                // Append `-rotated` to the image file name.
                $saved = $editor->save($editor->generate_filename('rotated'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // Update the stored EXIF data.
                    if (!empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            }
        }
    }
    /*
     * Initial save of the new metadata.
     * At this point the file was uploaded and moved to the uploads directory
     * but the image sub-sizes haven't been created yet and the `sizes` array is empty.
     */
    wp_update_attachment_metadata($attachment_id, $image_meta);
    $new_sizes = wp_get_registered_image_subsizes();
    /**
     * Filters the image sizes automatically generated when uploading an image.
     *
     * @since 2.9.0
     * @since 4.4.0 Added the `$image_meta` argument.
     * @since 5.3.0 Added the `$attachment_id` argument.
     *
     * @param array $new_sizes     Associative array of image sizes to be created.
     * @param array $image_meta    The image meta data: width, height, file, sizes, etc.
     * @param int   $attachment_id The attachment post ID for the image.
     */
    $new_sizes = apply_filters('intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id);
    return _wp_make_subsizes($new_sizes, $file, $image_meta, $attachment_id);
}

WordPress Version: 6.1

/**
 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
 *
 * Intended for use after an image is uploaded. Saves/updates the image metadata after each
 * sub-size is created. If there was an error, it is added to the returned image metadata array.
 *
 * @since 5.3.0
 *
 * @param string $file          Full path to the image file.
 * @param int    $attachment_id Attachment ID to process.
 * @return array The image attachment meta data.
 */
function wp_create_image_subsizes($file, $attachment_id)
{
    $imagesize = wp_getimagesize($file);
    if (empty($imagesize)) {
        // File is not an image.
        return array();
    }
    // Default image meta.
    $image_meta = array('width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path($file), 'filesize' => wp_filesize($file), 'sizes' => array());
    // Fetch additional metadata from EXIF/IPTC.
    $exif_meta = wp_read_image_metadata($file);
    if ($exif_meta) {
        $image_meta['image_meta'] = $exif_meta;
    }
    // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
    if ('image/png' !== $imagesize['mime']) {
        /**
         * Filters the "BIG image" threshold value.
         *
         * If the original image width or height is above the threshold, it will be scaled down. The threshold is
         * used as max width and max height. The scaled down image will be used as the largest available size, including
         * the `_wp_attached_file` post meta value.
         *
         * Returning `false` from the filter callback will disable the scaling.
         *
         * @since 5.3.0
         *
         * @param int    $threshold     The threshold value in pixels. Default 2560.
         * @param array  $imagesize     {
         *     Indexed array of the image width and height in pixels.
         *
         *     @type int $0 The image width.
         *     @type int $1 The image height.
         * }
         * @param string $file          Full path to the uploaded image file.
         * @param int    $attachment_id Attachment post ID.
         */
        $threshold = (int) apply_filters('big_image_size_threshold', 2560, $imagesize, $file, $attachment_id);
        // If the original image's dimensions are over the threshold,
        // scale the image and use it as the "full" size.
        if ($threshold && ($image_meta['width'] > $threshold || $image_meta['height'] > $threshold)) {
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Resize the image.
            $resized = $editor->resize($threshold, $threshold);
            $rotated = null;
            // If there is EXIF data, rotate according to EXIF Orientation.
            if (!is_wp_error($resized) && is_array($exif_meta)) {
                $resized = $editor->maybe_exif_rotate();
                $rotated = $resized;
            }
            if (!is_wp_error($resized)) {
                // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
                // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
                $saved = $editor->save($editor->generate_filename('scaled'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // If the image was rotated update the stored EXIF data.
                    if (true === $rotated && !empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            } else {
                // TODO: Log errors.
            }
        } elseif (!empty($exif_meta['orientation']) && 1 !== (int) $exif_meta['orientation']) {
            // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Rotate the image.
            $rotated = $editor->maybe_exif_rotate();
            if (true === $rotated) {
                // Append `-rotated` to the image file name.
                $saved = $editor->save($editor->generate_filename('rotated'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // Update the stored EXIF data.
                    if (!empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            }
        }
    }
    /*
     * Initial save of the new metadata.
     * At this point the file was uploaded and moved to the uploads directory
     * but the image sub-sizes haven't been created yet and the `sizes` array is empty.
     */
    wp_update_attachment_metadata($attachment_id, $image_meta);
    $new_sizes = wp_get_registered_image_subsizes();
    /**
     * Filters the image sizes automatically generated when uploading an image.
     *
     * @since 2.9.0
     * @since 4.4.0 Added the `$image_meta` argument.
     * @since 5.3.0 Added the `$attachment_id` argument.
     *
     * @param array $new_sizes     Associative array of image sizes to be created.
     * @param array $image_meta    The image meta data: width, height, file, sizes, etc.
     * @param int   $attachment_id The attachment post ID for the image.
     */
    $new_sizes = apply_filters('intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id);
    return _wp_make_subsizes($new_sizes, $file, $image_meta, $attachment_id);
}

WordPress Version: 5.9

/**
 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
 *
 * Intended for use after an image is uploaded. Saves/updates the image metadata after each
 * sub-size is created. If there was an error, it is added to the returned image metadata array.
 *
 * @since 5.3.0
 *
 * @param string $file          Full path to the image file.
 * @param int    $attachment_id Attachment ID to process.
 * @return array The image attachment meta data.
 */
function wp_create_image_subsizes($file, $attachment_id)
{
    $imagesize = wp_getimagesize($file);
    if (empty($imagesize)) {
        // File is not an image.
        return array();
    }
    // Default image meta.
    $image_meta = array('width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path($file), 'sizes' => array());
    // Fetch additional metadata from EXIF/IPTC.
    $exif_meta = wp_read_image_metadata($file);
    if ($exif_meta) {
        $image_meta['image_meta'] = $exif_meta;
    }
    // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
    if ('image/png' !== $imagesize['mime']) {
        /**
         * Filters the "BIG image" threshold value.
         *
         * If the original image width or height is above the threshold, it will be scaled down. The threshold is
         * used as max width and max height. The scaled down image will be used as the largest available size, including
         * the `_wp_attached_file` post meta value.
         *
         * Returning `false` from the filter callback will disable the scaling.
         *
         * @since 5.3.0
         *
         * @param int    $threshold     The threshold value in pixels. Default 2560.
         * @param array  $imagesize     {
         *     Indexed array of the image width and height in pixels.
         *
         *     @type int $0 The image width.
         *     @type int $1 The image height.
         * }
         * @param string $file          Full path to the uploaded image file.
         * @param int    $attachment_id Attachment post ID.
         */
        $threshold = (int) apply_filters('big_image_size_threshold', 2560, $imagesize, $file, $attachment_id);
        // If the original image's dimensions are over the threshold,
        // scale the image and use it as the "full" size.
        if ($threshold && ($image_meta['width'] > $threshold || $image_meta['height'] > $threshold)) {
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Resize the image.
            $resized = $editor->resize($threshold, $threshold);
            $rotated = null;
            // If there is EXIF data, rotate according to EXIF Orientation.
            if (!is_wp_error($resized) && is_array($exif_meta)) {
                $resized = $editor->maybe_exif_rotate();
                $rotated = $resized;
            }
            if (!is_wp_error($resized)) {
                // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
                // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
                $saved = $editor->save($editor->generate_filename('scaled'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // If the image was rotated update the stored EXIF data.
                    if (true === $rotated && !empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            } else {
                // TODO: Log errors.
            }
        } elseif (!empty($exif_meta['orientation']) && 1 !== (int) $exif_meta['orientation']) {
            // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Rotate the image.
            $rotated = $editor->maybe_exif_rotate();
            if (true === $rotated) {
                // Append `-rotated` to the image file name.
                $saved = $editor->save($editor->generate_filename('rotated'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // Update the stored EXIF data.
                    if (!empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            }
        }
    }
    /*
     * Initial save of the new metadata.
     * At this point the file was uploaded and moved to the uploads directory
     * but the image sub-sizes haven't been created yet and the `sizes` array is empty.
     */
    wp_update_attachment_metadata($attachment_id, $image_meta);
    $new_sizes = wp_get_registered_image_subsizes();
    /**
     * Filters the image sizes automatically generated when uploading an image.
     *
     * @since 2.9.0
     * @since 4.4.0 Added the `$image_meta` argument.
     * @since 5.3.0 Added the `$attachment_id` argument.
     *
     * @param array $new_sizes     Associative array of image sizes to be created.
     * @param array $image_meta    The image meta data: width, height, file, sizes, etc.
     * @param int   $attachment_id The attachment post ID for the image.
     */
    $new_sizes = apply_filters('intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id);
    return _wp_make_subsizes($new_sizes, $file, $image_meta, $attachment_id);
}

WordPress Version: 5.7

/**
 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
 *
 * Intended for use after an image is uploaded. Saves/updates the image metadata after each
 * sub-size is created. If there was an error, it is added to the returned image metadata array.
 *
 * @since 5.3.0
 *
 * @param string $file          Full path to the image file.
 * @param int    $attachment_id Attachment Id to process.
 * @return array The image attachment meta data.
 */
function wp_create_image_subsizes($file, $attachment_id)
{
    $imagesize = wp_getimagesize($file);
    if (empty($imagesize)) {
        // File is not an image.
        return array();
    }
    // Default image meta.
    $image_meta = array('width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path($file), 'sizes' => array());
    // Fetch additional metadata from EXIF/IPTC.
    $exif_meta = wp_read_image_metadata($file);
    if ($exif_meta) {
        $image_meta['image_meta'] = $exif_meta;
    }
    // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
    if ('image/png' !== $imagesize['mime']) {
        /**
         * Filters the "BIG image" threshold value.
         *
         * If the original image width or height is above the threshold, it will be scaled down. The threshold is
         * used as max width and max height. The scaled down image will be used as the largest available size, including
         * the `_wp_attached_file` post meta value.
         *
         * Returning `false` from the filter callback will disable the scaling.
         *
         * @since 5.3.0
         *
         * @param int    $threshold     The threshold value in pixels. Default 2560.
         * @param array  $imagesize     {
         *     Indexed array of the image width and height in pixels.
         *
         *     @type int $0 The image width.
         *     @type int $1 The image height.
         * }
         * @param string $file          Full path to the uploaded image file.
         * @param int    $attachment_id Attachment post ID.
         */
        $threshold = (int) apply_filters('big_image_size_threshold', 2560, $imagesize, $file, $attachment_id);
        // If the original image's dimensions are over the threshold,
        // scale the image and use it as the "full" size.
        if ($threshold && ($image_meta['width'] > $threshold || $image_meta['height'] > $threshold)) {
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Resize the image.
            $resized = $editor->resize($threshold, $threshold);
            $rotated = null;
            // If there is EXIF data, rotate according to EXIF Orientation.
            if (!is_wp_error($resized) && is_array($exif_meta)) {
                $resized = $editor->maybe_exif_rotate();
                $rotated = $resized;
            }
            if (!is_wp_error($resized)) {
                // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
                // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
                $saved = $editor->save($editor->generate_filename('scaled'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // If the image was rotated update the stored EXIF data.
                    if (true === $rotated && !empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            } else {
                // TODO: Log errors.
            }
        } elseif (!empty($exif_meta['orientation']) && 1 !== (int) $exif_meta['orientation']) {
            // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Rotate the image.
            $rotated = $editor->maybe_exif_rotate();
            if (true === $rotated) {
                // Append `-rotated` to the image file name.
                $saved = $editor->save($editor->generate_filename('rotated'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // Update the stored EXIF data.
                    if (!empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            }
        }
    }
    /*
     * Initial save of the new metadata.
     * At this point the file was uploaded and moved to the uploads directory
     * but the image sub-sizes haven't been created yet and the `sizes` array is empty.
     */
    wp_update_attachment_metadata($attachment_id, $image_meta);
    $new_sizes = wp_get_registered_image_subsizes();
    /**
     * Filters the image sizes automatically generated when uploading an image.
     *
     * @since 2.9.0
     * @since 4.4.0 Added the `$image_meta` argument.
     * @since 5.3.0 Added the `$attachment_id` argument.
     *
     * @param array $new_sizes     Associative array of image sizes to be created.
     * @param array $image_meta    The image meta data: width, height, file, sizes, etc.
     * @param int   $attachment_id The attachment post ID for the image.
     */
    $new_sizes = apply_filters('intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id);
    return _wp_make_subsizes($new_sizes, $file, $image_meta, $attachment_id);
}

WordPress Version: 5.4

/**
 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
 *
 * Intended for use after an image is uploaded. Saves/updates the image metadata after each
 * sub-size is created. If there was an error, it is added to the returned image metadata array.
 *
 * @since 5.3.0
 *
 * @param string $file          Full path to the image file.
 * @param int    $attachment_id Attachment Id to process.
 * @return array The image attachment meta data.
 */
function wp_create_image_subsizes($file, $attachment_id)
{
    $imagesize = @getimagesize($file);
    if (empty($imagesize)) {
        // File is not an image.
        return array();
    }
    // Default image meta.
    $image_meta = array('width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path($file), 'sizes' => array());
    // Fetch additional metadata from EXIF/IPTC.
    $exif_meta = wp_read_image_metadata($file);
    if ($exif_meta) {
        $image_meta['image_meta'] = $exif_meta;
    }
    // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
    if ('image/png' !== $imagesize['mime']) {
        /**
         * Filters the "BIG image" threshold value.
         *
         * If the original image width or height is above the threshold, it will be scaled down. The threshold is
         * used as max width and max height. The scaled down image will be used as the largest available size, including
         * the `_wp_attached_file` post meta value.
         *
         * Returning `false` from the filter callback will disable the scaling.
         *
         * @since 5.3.0
         *
         * @param int    $threshold     The threshold value in pixels. Default 2560.
         * @param array  $imagesize     {
         *     Indexed array of the image width and height in pixels.
         *
         *     @type int $0 The image width.
         *     @type int $1 The image height.
         * }
         * @param string $file          Full path to the uploaded image file.
         * @param int    $attachment_id Attachment post ID.
         */
        $threshold = (int) apply_filters('big_image_size_threshold', 2560, $imagesize, $file, $attachment_id);
        // If the original image's dimensions are over the threshold,
        // scale the image and use it as the "full" size.
        if ($threshold && ($image_meta['width'] > $threshold || $image_meta['height'] > $threshold)) {
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Resize the image.
            $resized = $editor->resize($threshold, $threshold);
            $rotated = null;
            // If there is EXIF data, rotate according to EXIF Orientation.
            if (!is_wp_error($resized) && is_array($exif_meta)) {
                $resized = $editor->maybe_exif_rotate();
                $rotated = $resized;
            }
            if (!is_wp_error($resized)) {
                // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
                // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
                $saved = $editor->save($editor->generate_filename('scaled'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // If the image was rotated update the stored EXIF data.
                    if (true === $rotated && !empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            } else {
                // TODO: Log errors.
            }
        } elseif (!empty($exif_meta['orientation']) && 1 !== (int) $exif_meta['orientation']) {
            // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Rotate the image.
            $rotated = $editor->maybe_exif_rotate();
            if (true === $rotated) {
                // Append `-rotated` to the image file name.
                $saved = $editor->save($editor->generate_filename('rotated'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // Update the stored EXIF data.
                    if (!empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: Log errors.
                }
            }
        }
    }
    /*
     * Initial save of the new metadata.
     * At this point the file was uploaded and moved to the uploads directory
     * but the image sub-sizes haven't been created yet and the `sizes` array is empty.
     */
    wp_update_attachment_metadata($attachment_id, $image_meta);
    $new_sizes = wp_get_registered_image_subsizes();
    /**
     * Filters the image sizes automatically generated when uploading an image.
     *
     * @since 2.9.0
     * @since 4.4.0 Added the `$image_meta` argument.
     * @since 5.3.0 Added the `$attachment_id` argument.
     *
     * @param array $new_sizes     Associative array of image sizes to be created.
     * @param array $image_meta    The image meta data: width, height, file, sizes, etc.
     * @param int   $attachment_id The attachment post ID for the image.
     */
    $new_sizes = apply_filters('intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id);
    return _wp_make_subsizes($new_sizes, $file, $image_meta, $attachment_id);
}

WordPress Version: 3.1

/**
 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
 *
 * Intended for use after an image is uploaded. Saves/updates the image metadata after each
 * sub-size is created. If there was an error, it is added to the returned image metadata array.
 *
 * @since 5.3.0
 *
 * @param string $file          Full path to the image file.
 * @param int    $attachment_id Attachment Id to process.
 * @return array The image attachment meta data.
 */
function wp_create_image_subsizes($file, $attachment_id)
{
    $imagesize = @getimagesize($file);
    if (empty($imagesize)) {
        // File is not an image.
        return array();
    }
    // Default image meta
    $image_meta = array('width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path($file), 'sizes' => array());
    // Fetch additional metadata from EXIF/IPTC.
    $exif_meta = wp_read_image_metadata($file);
    if ($exif_meta) {
        $image_meta['image_meta'] = $exif_meta;
    }
    // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736.
    if ($imagesize['mime'] !== 'image/png') {
        /**
         * Filters the "BIG image" threshold value.
         *
         * If the original image width or height is above the threshold, it will be scaled down. The threshold is
         * used as max width and max height. The scaled down image will be used as the largest available size, including
         * the `_wp_attached_file` post meta value.
         *
         * Returning `false` from the filter callback will disable the scaling.
         *
         * @since 5.3.0
         *
         * @param int    $threshold     The threshold value in pixels. Default 2560.
         * @param array  $imagesize     {
         *     Indexed array of the image width and height in pixels.
         *
         *     @type int $0 The image width.
         *     @type int $1 The image height.
         * }
         * @param string $file          Full path to the uploaded image file.
         * @param int    $attachment_id Attachment post ID.
         */
        $threshold = (int) apply_filters('big_image_size_threshold', 2560, $imagesize, $file, $attachment_id);
        // If the original image's dimensions are over the threshold, scale the image
        // and use it as the "full" size.
        if ($threshold && ($image_meta['width'] > $threshold || $image_meta['height'] > $threshold)) {
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Resize the image
            $resized = $editor->resize($threshold, $threshold);
            $rotated = null;
            // If there is EXIF data, rotate according to EXIF Orientation.
            if (!is_wp_error($resized) && is_array($exif_meta)) {
                $resized = $editor->maybe_exif_rotate();
                $rotated = $resized;
            }
            if (!is_wp_error($resized)) {
                // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
                // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
                $saved = $editor->save($editor->generate_filename('scaled'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // If the image was rotated update the stored EXIF data.
                    if (true === $rotated && !empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: log errors.
                }
            } else {
                // TODO: log errors.
            }
        } elseif (!empty($exif_meta['orientation']) && (int) $exif_meta['orientation'] !== 1) {
            // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
            $editor = wp_get_image_editor($file);
            if (is_wp_error($editor)) {
                // This image cannot be edited.
                return $image_meta;
            }
            // Rotate the image
            $rotated = $editor->maybe_exif_rotate();
            if (true === $rotated) {
                // Append `-rotated` to the image file name.
                $saved = $editor->save($editor->generate_filename('rotated'));
                if (!is_wp_error($saved)) {
                    $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                    // Update the stored EXIF data.
                    if (!empty($image_meta['image_meta']['orientation'])) {
                        $image_meta['image_meta']['orientation'] = 1;
                    }
                } else {
                    // TODO: log errors.
                }
            }
        }
    }
    // Initial save of the new metadata.
    // At this point the file was uploaded and moved to the uploads directory
    // but the image sub-sizes haven't been created yet and the `sizes` array is empty.
    wp_update_attachment_metadata($attachment_id, $image_meta);
    $new_sizes = wp_get_registered_image_subsizes();
    /**
     * Filters the image sizes automatically generated when uploading an image.
     *
     * @since 2.9.0
     * @since 4.4.0 Added the `$image_meta` argument.
     * @since 5.3.0 Added the `$attachment_id` argument.
     *
     * @param array $new_sizes     Associative array of image sizes to be created.
     * @param array $image_meta    The image meta data: width, height, file, sizes, etc.
     * @param int   $attachment_id The attachment post ID for the image.
     */
    $new_sizes = apply_filters('intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id);
    return _wp_make_subsizes($new_sizes, $file, $image_meta, $attachment_id);
}

WordPress Version: 5.3

/**
 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.
 *
 * Intended for use after an image is uploaded. Saves/updates the image metadata after each
 * sub-size is created. If there was an error, it is added to the returned image metadata array.
 *
 * @since 5.3.0
 *
 * @param string $file          Full path to the image file.
 * @param int    $attachment_id Attachment Id to process.
 * @return array The image attachment meta data.
 */
function wp_create_image_subsizes($file, $attachment_id)
{
    $imagesize = @getimagesize($file);
    if (empty($imagesize)) {
        // File is not an image.
        return array();
    }
    // Default image meta
    $image_meta = array('width' => $imagesize[0], 'height' => $imagesize[1], 'file' => _wp_relative_upload_path($file), 'sizes' => array());
    // Fetch additional metadata from EXIF/IPTC.
    $exif_meta = wp_read_image_metadata($file);
    if ($exif_meta) {
        $image_meta['image_meta'] = $exif_meta;
    }
    /**
     * Filters the "BIG image" threshold value.
     *
     * If the original image width or height is above the threshold, it will be scaled down. The threshold is
     * used as max width and max height. The scaled down image will be used as the largest available size, including
     * the `_wp_attached_file` post meta value.
     *
     * Returning `false` from the filter callback will disable the scaling.
     *
     * @since 5.3.0
     *
     * @param int    $threshold     The threshold value in pixels. Default 2560.
     * @param array  $imagesize     Indexed array of the image width and height (in that order).
     * @param string $file          Full path to the uploaded image file.
     * @param int    $attachment_id Attachment post ID.
     */
    $threshold = (int) apply_filters('big_image_size_threshold', 2560, $imagesize, $file, $attachment_id);
    // If the original image's dimensions are over the threshold, scale the image
    // and use it as the "full" size.
    if ($threshold && ($image_meta['width'] > $threshold || $image_meta['height'] > $threshold)) {
        $editor = wp_get_image_editor($file);
        if (is_wp_error($editor)) {
            // This image cannot be edited.
            return $image_meta;
        }
        // Resize the image
        $resized = $editor->resize($threshold, $threshold);
        $rotated = null;
        // If there is EXIF data, rotate according to EXIF Orientation.
        if (!is_wp_error($resized) && is_array($exif_meta)) {
            $resized = $editor->maybe_exif_rotate();
            $rotated = $resized;
        }
        if (!is_wp_error($resized)) {
            // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg".
            // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality).
            $saved = $editor->save($editor->generate_filename('scaled'));
            if (!is_wp_error($saved)) {
                $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                // If the image was rotated update the stored EXIF data.
                if (true === $rotated && !empty($image_meta['image_meta']['orientation'])) {
                    $image_meta['image_meta']['orientation'] = 1;
                }
            } else {
                // TODO: log errors.
            }
        } else {
            // TODO: log errors.
        }
    } elseif (!empty($exif_meta['orientation']) && (int) $exif_meta['orientation'] !== 1) {
        // Rotate the whole original image if there is EXIF data and "orientation" is not 1.
        $editor = wp_get_image_editor($file);
        if (is_wp_error($editor)) {
            // This image cannot be edited.
            return $image_meta;
        }
        // Rotate the image
        $rotated = $editor->maybe_exif_rotate();
        if (true === $rotated) {
            // Append `-rotated` to the image file name.
            $saved = $editor->save($editor->generate_filename('rotated'));
            if (!is_wp_error($saved)) {
                $image_meta = _wp_image_meta_replace_original($saved, $file, $image_meta, $attachment_id);
                // Update the stored EXIF data.
                if (!empty($image_meta['image_meta']['orientation'])) {
                    $image_meta['image_meta']['orientation'] = 1;
                }
            } else {
                // TODO: log errors.
            }
        }
    }
    // Initial save of the new metadata.
    // At this point the file was uploaded and moved to the uploads directory
    // but the image sub-sizes haven't been created yet and the `sizes` array is empty.
    wp_update_attachment_metadata($attachment_id, $image_meta);
    $new_sizes = wp_get_registered_image_subsizes();
    /**
     * Filters the image sizes automatically generated when uploading an image.
     *
     * @since 2.9.0
     * @since 4.4.0 Added the `$image_meta` argument.
     * @since 5.3.0 Added the `$attachment_id` argument.
     *
     * @param array $new_sizes     Associative array of image sizes to be created.
     * @param array $image_meta    The image meta data: width, height, file, sizes, etc.
     * @param int   $attachment_id The attachment post ID for the image.
     */
    $new_sizes = apply_filters('intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id);
    return _wp_make_subsizes($new_sizes, $file, $image_meta, $attachment_id);
}