Ticket #55443: 55443.5.diff
File 55443.5.diff, 89.7 KB (added by , 2 years ago) |
---|
-
src/js/_enqueues/vendor/plupload/handlers.js
diff --git src/js/_enqueues/vendor/plupload/handlers.js src/js/_enqueues/vendor/plupload/handlers.js index fa602daf43..c7e3c253d3 100644
jQuery( document ).ready( function( $ ) { 486 486 487 487 times = tryAgainCount[ file.id ]; 488 488 489 if ( times && times > 4) {489 if ( times && times > 8 ) { 490 490 /* 491 491 * The file may have been uploaded and attachment post created, 492 492 * but post-processing and resizing failed... -
src/js/_enqueues/vendor/plupload/wp-plupload.js
diff --git src/js/_enqueues/vendor/plupload/wp-plupload.js src/js/_enqueues/vendor/plupload/wp-plupload.js index 0fdebf77d1..217b3c09e2 100644
window.wp = window.wp || {}; 138 138 139 139 times = tryAgainCount[ file.id ]; 140 140 141 if ( times && times > 4) {141 if ( times && times > 8 ) { 142 142 /* 143 143 * The file may have been uploaded and attachment post created, 144 144 * but post-processing and resizing failed... -
src/wp-admin/includes/image.php
diff --git src/wp-admin/includes/image.php src/wp-admin/includes/image.php index 1a9c9e2e9c..49563fa26a 100644
function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $s 77 77 * Registered sub-sizes that are larger than the image are skipped. 78 78 * 79 79 * @since 5.3.0 80 * @since 6.1.0 The $mime_type parameter was added. 80 81 * 81 * @param int $attachment_id The image attachment post ID. 82 * @param int $attachment_id The image attachment post ID. 83 * @param string $mime_type Optional. The mime type to check for missing sizes. Default is the primary image mime. 82 84 * @return array[] Associative array of arrays of image sub-size information for 83 85 * missing image sizes, keyed by image size name. 84 86 */ 85 function wp_get_missing_image_subsizes( $attachment_id ) {87 function wp_get_missing_image_subsizes( $attachment_id, $mime_type = '' ) { 86 88 if ( ! wp_attachment_is_image( $attachment_id ) ) { 87 89 return array(); 88 90 } 89 91 92 $primary_mime_type = get_post_mime_type( get_post( $attachment_id ) ); 93 if ( ! $mime_type ) { 94 $mime_type = $primary_mime_type; 95 } 96 90 97 $registered_sizes = wp_get_registered_image_subsizes(); 91 98 $image_meta = wp_get_attachment_metadata( $attachment_id ); 92 99 … … function wp_get_missing_image_subsizes( $attachment_id ) { 129 136 * However we keep the old sub-sizes with the previous dimensions 130 137 * as the image may have been used in an older post. 131 138 */ 132 $missing_sizes = array_diff_key( $possible_sizes, $image_meta['sizes'] ); 139 $missing_sizes = array(); 140 foreach ( $possible_sizes as $size_name => $size_data ) { 141 if ( ! isset( $image_meta['sizes'][ $size_name ] ) ) { 142 $missing_sizes[ $size_name ] = $size_data; 143 continue; 144 } 145 146 if ( ( isset( $size_data['mime-type'] ) && $size_data['mime-type'] === $mime_type ) || isset( $size_data['sources'][ $mime_type ] ) ) { 147 continue; 148 } 149 150 $missing_sizes[ $size_name ] = $size_data; 151 } 152 153 // Filter secondary mime types to those sizes that are enabled. 154 if ( $primary_mime_type !== $mime_type ) { 155 $missing_sizes = _wp_filter_image_sizes_additional_mime_type_support( $missing_sizes, $attachment_id ); 156 } 133 157 134 158 /** 135 159 * Filters the array of missing image sub-sizes for an uploaded image. 136 160 * 137 161 * @since 5.3.0 162 * @since 6.1.0 The $mime_type filter parameter was added. 138 163 * 139 164 * @param array[] $missing_sizes Associative array of arrays of image sub-size information for 140 165 * missing image sizes, keyed by image size name. 141 166 * @param array $image_meta The image meta data. 142 167 * @param int $attachment_id The image attachment post ID. 168 * @param string $mime_type The image mime type to get missing sizes for. 143 169 */ 144 return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id );170 return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id, $mime_type ); 145 171 } 146 172 147 173 /** … … function wp_get_missing_image_subsizes( $attachment_id ) { 149 175 * create them and update the image meta data. 150 176 * 151 177 * @since 5.3.0 178 * @since 6.1.0 Now supports additional mime types, creating the additional sub-sizes and 'full' sized images. 152 179 * 153 180 * @param int $attachment_id The image attachment post ID. 154 181 * @return array|WP_Error The updated image meta data array or WP_Error object … … function wp_update_image_subsizes( $attachment_id ) { 167 194 return new WP_Error( 'invalid_attachment', __( 'The attached file cannot be found.' ) ); 168 195 } 169 196 } else { 170 $missing_sizes = wp_get_missing_image_subsizes( $attachment_id ); 197 // Get the primary and additional mime types to generate. 198 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $image_file, $attachment_id ); 171 199 172 if ( empty( $missing_sizes ) ) { 173 return $image_meta; 200 // Generate missing 'full' image files for additional mime types. 201 if ( ! empty( $additional_mime_types ) ) { 202 if ( isset( $image_meta['sources'] ) ) { 203 $missing_mime_types = array_diff( $additional_mime_types, array_keys( $image_meta['sources'] ) ); 204 } else { 205 $missing_mime_types = $additional_mime_types; 206 } 207 if ( ! empty( $missing_mime_types ) ) { 208 $image_meta = _wp_make_additional_mime_types( $missing_mime_types, $image_file, $image_meta, $attachment_id ); 209 } 174 210 } 175 211 176 // This also updates the image meta. 177 $image_meta = _wp_make_subsizes( $missing_sizes, $image_file, $image_meta, $attachment_id ); 212 // Generate missing image sub-sizes for each mime type. 213 $all_mime_types = array_merge( array( $primary_mime_type ), $additional_mime_types ); 214 foreach ( $all_mime_types as $mime_type ) { 215 $missing_sizes = wp_get_missing_image_subsizes( $attachment_id, $mime_type ); 216 217 if ( empty( $missing_sizes ) ) { 218 continue; 219 } 220 221 // This also updates the image meta. 222 $image_meta = _wp_make_subsizes( $missing_sizes, $image_file, $image_meta, $attachment_id, $mime_type ); 223 } 178 224 } 179 225 180 226 /** This filter is documented in wp-admin/includes/image.php */ … … function _wp_image_meta_replace_original( $saved_data, $original_file, $image_me 222 268 } 223 269 224 270 /** 225 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata.271 * Creates image mime variations and sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata. 226 272 * 227 273 * Intended for use after an image is uploaded. Saves/updates the image metadata after each 228 274 * sub-size is created. If there was an error, it is added to the returned image metadata array. 229 275 * 230 276 * @since 5.3.0 277 * @since 6.1.0 Generates sub-sizes in alternate mime types based on the `wp_image_mime_transforms` filter. 231 278 * 232 279 * @param string $file Full path to the image file. 233 280 * @param int $attachment_id Attachment ID to process. … … function wp_create_image_subsizes( $file, $attachment_id ) { 248 295 'file' => _wp_relative_upload_path( $file ), 249 296 'filesize' => wp_filesize( $file ), 250 297 'sizes' => array(), 298 'sources' => array(), 251 299 ); 252 300 253 301 // Fetch additional metadata from EXIF/IPTC. … … function wp_create_image_subsizes( $file, $attachment_id ) { 257 305 $image_meta['image_meta'] = $exif_meta; 258 306 } 259 307 260 // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736. 261 if ( 'image/png' !== $imagesize['mime'] ) { 308 // Get the primary and additional mime types to generate. 309 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $file, $attachment_id ); 310 311 list( $editor, $resized, $rotated ) = _wp_maybe_scale_and_rotate_image( $file, $attachment_id, $imagesize, $exif_meta, $primary_mime_type ); 312 if ( is_wp_error( $editor ) ) { 313 return $image_meta; 314 } 315 $suffix = _wp_get_image_suffix( $resized, $rotated ); 316 317 // Save image only if either it was modified or if the primary mime type is different from the original. 318 if ( ! empty( $suffix ) || $primary_mime_type !== $imagesize['mime'] ) { 319 $saved = $editor->save( $editor->generate_filename( $suffix ) ); 320 321 if ( ! is_wp_error( $saved ) ) { 322 $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id ); 323 324 // If the image was rotated update the stored EXIF data. 325 if ( true === $rotated && ! empty( $image_meta['image_meta']['orientation'] ) ) { 326 $image_meta['image_meta']['orientation'] = 1; 327 } 328 } else { 329 // TODO: Log errors. 330 } 331 } 332 333 // Set 'sources' for the primary mime type. 334 $image_meta['sources'][ $primary_mime_type ] = _wp_get_sources_from_meta( $image_meta ); 262 335 336 /* 337 * Initial save of the new metadata. 338 * At this point the file was uploaded and moved to the uploads directory 339 * but the image sub-sizes haven't been created yet and the `sizes` array is empty. 340 */ 341 wp_update_attachment_metadata( $attachment_id, $image_meta ); 342 343 if ( ! empty( $additional_mime_types ) ) { 344 // Use the original file's exif_meta orientation information for secondary mime generation. 345 $saved_orientation = $image_meta['image_meta']['orientation']; 346 $image_meta['image_meta']['orientation'] = $exif_meta['orientation']; 347 $image_meta = _wp_make_additional_mime_types( $additional_mime_types, $file, $image_meta, $attachment_id ); 348 $image_meta['image_meta']['orientation'] = $saved_orientation; 349 350 } 351 352 $new_sizes = wp_get_registered_image_subsizes(); 353 354 /** 355 * Filters the image sizes automatically generated when uploading an image. 356 * 357 * @since 2.9.0 358 * @since 4.4.0 Added the `$image_meta` argument. 359 * @since 5.3.0 Added the `$attachment_id` argument. 360 * 361 * @param array $new_sizes Associative array of image sizes to be created. 362 * @param array $image_meta The image meta data: width, height, file, sizes, etc. 363 * @param int $attachment_id The attachment post ID for the image. 364 */ 365 $new_sizes = apply_filters( 'intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id ); 366 367 $image_meta = _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id, $primary_mime_type ); 368 369 // Filter secondary mime types to those sizes that are enabled. 370 $new_sizes = _wp_filter_image_sizes_additional_mime_type_support( $new_sizes, $attachment_id ); 371 372 foreach ( $additional_mime_types as $additional_mime_type ) { 373 $image_meta = _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id, $additional_mime_type ); 374 } 375 376 return $image_meta; 377 } 378 379 /** 380 * Returns a WP_Image_Editor instance where the image file has been scaled and rotated as necessary. 381 * 382 * @since 6.1.0 383 * @access private 384 * 385 * @param string $file Full path to the image file. 386 * @param int $attachment_id Attachment ID. 387 * @param array $imagesize { 388 * Indexed array of the image width and height in pixels. 389 * 390 * @type int $0 The image width. 391 * @type int $1 The image height. 392 * } 393 * @param array|null $exif_meta EXIF metadata if extracted from the image file. 394 * @param string $mime_type Output mime type. 395 * @return array Array with three entries: The WP_Image_Editor instance, whether the image was resized, and whether the 396 * image was rotated (booleans). Each entry can alternatively be a WP_Error in case something went wrong. 397 */ 398 function _wp_maybe_scale_and_rotate_image( $file, $attachment_id, $imagesize, $exif_meta, $mime_type ) { 399 $resized = false; 400 $rotated = false; 401 402 $editor = wp_get_image_editor( $file, array( 'mime_type' => $mime_type ) ); 403 if ( is_wp_error( $editor ) ) { 404 // This image cannot be edited. 405 return array( $editor, $resized, $rotated ); 406 } 407 408 if ( ! empty( $mime_type ) ) { 409 $editor->set_mime_type( $mime_type ); 410 } 411 412 // Do not scale (large) PNG images. May result in sub-sizes that have greater file size than the original. See #48736. 413 if ( 'image/png' !== $mime_type ) { 263 414 /** 264 415 * Filters the "BIG image" threshold value. 265 416 * … … function wp_create_image_subsizes( $file, $attachment_id ) { 285 436 286 437 // If the original image's dimensions are over the threshold, 287 438 // scale the image and use it as the "full" size. 288 if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) { 289 $editor = wp_get_image_editor( $file ); 290 291 if ( is_wp_error( $editor ) ) { 292 // This image cannot be edited. 293 return $image_meta; 294 } 295 439 if ( $threshold && ( $imagesize[0] > $threshold || $imagesize[1] > $threshold ) ) { 296 440 // Resize the image. 297 441 $resized = $editor->resize( $threshold, $threshold ); 298 $rotated = null;299 442 300 443 // If there is EXIF data, rotate according to EXIF Orientation. 301 444 if ( ! is_wp_error( $resized ) && is_array( $exif_meta ) ) { 302 $resized = $editor->maybe_exif_rotate(); 303 $rotated = $resized; 304 } 305 306 if ( ! is_wp_error( $resized ) ) { 307 // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg". 308 // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality). 309 $saved = $editor->save( $editor->generate_filename( 'scaled' ) ); 310 311 if ( ! is_wp_error( $saved ) ) { 312 $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id ); 313 314 // If the image was rotated update the stored EXIF data. 315 if ( true === $rotated && ! empty( $image_meta['image_meta']['orientation'] ) ) { 316 $image_meta['image_meta']['orientation'] = 1; 317 } 318 } else { 319 // TODO: Log errors. 320 } 321 } else { 322 // TODO: Log errors. 445 $rotated = $editor->maybe_exif_rotate(); 323 446 } 324 447 } elseif ( ! empty( $exif_meta['orientation'] ) && 1 !== (int) $exif_meta['orientation'] ) { 325 448 // Rotate the whole original image if there is EXIF data and "orientation" is not 1. 326 327 $editor = wp_get_image_editor( $file );328 329 if ( is_wp_error( $editor ) ) {330 // This image cannot be edited.331 return $image_meta;332 }333 334 // Rotate the image.335 449 $rotated = $editor->maybe_exif_rotate(); 336 337 if ( true === $rotated ) {338 // Append `-rotated` to the image file name.339 $saved = $editor->save( $editor->generate_filename( 'rotated' ) );340 341 if ( ! is_wp_error( $saved ) ) {342 $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id );343 344 // Update the stored EXIF data.345 if ( ! empty( $image_meta['image_meta']['orientation'] ) ) {346 $image_meta['image_meta']['orientation'] = 1;347 }348 } else {349 // TODO: Log errors.350 }351 }352 450 } 353 451 } 354 452 355 /* 356 * Initial save of the new metadata. 357 * At this point the file was uploaded and moved to the uploads directory 358 * but the image sub-sizes haven't been created yet and the `sizes` array is empty. 359 */ 360 wp_update_attachment_metadata( $attachment_id, $image_meta ); 453 return array( $editor, $resized, $rotated ); 454 } 361 455 362 $new_sizes = wp_get_registered_image_subsizes(); 456 /** 457 * Gets the suffix to use for image files based on resizing and rotating. 458 * 459 * @since 6.1.0 460 * @access private 461 * 462 * @param bool|WP_Error Whether the image was resized, or an error if resizing failed. 463 * @param bool|WP_Error Whether the image was rotated, or an error if rotating failed. 464 * @return string The suffix to use for the file name, or empty string if none. 465 */ 466 function _wp_get_image_suffix( $resized, $rotated ) { 467 if ( $resized && ! is_wp_error( $resized ) ) { 468 // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg". 469 // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality). 470 return 'scaled'; 471 } 363 472 364 /** 365 * Filters the image sizes automatically generated when uploading an image. 366 * 367 * @since 2.9.0 368 * @since 4.4.0 Added the `$image_meta` argument. 369 * @since 5.3.0 Added the `$attachment_id` argument. 370 * 371 * @param array $new_sizes Associative array of image sizes to be created. 372 * @param array $image_meta The image meta data: width, height, file, sizes, etc. 373 * @param int $attachment_id The attachment post ID for the image. 374 */ 375 $new_sizes = apply_filters( 'intermediate_image_sizes_advanced', $new_sizes, $image_meta, $attachment_id ); 473 if ( true === $rotated ) { 474 // Append `-rotated` to the image file name. 475 return 'rotated'; 476 } 477 478 if ( is_wp_error( $resized ) || is_wp_error( $rotated ) ) { 479 // TODO: Log errors. 480 } 481 return ''; 482 } 376 483 377 return _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ); 484 /** 485 * Gets a sources array element from a meta. 486 * 487 * @since 6.1.0 488 * @access private 489 * 490 * @param array $meta The meta to get the source from. 491 * @return array The source array element. 492 */ 493 function _wp_get_sources_from_meta( $meta ) { 494 return array( 495 'file' => isset( $meta['file'] ) ? wp_basename( $meta['file'] ) : '', 496 'filesize' => isset( $meta['filesize'] ) ? $meta['filesize'] : wp_filesize( $meta['path'] ), 497 ); 378 498 } 379 499 380 500 /** … … function wp_create_image_subsizes( $file, $attachment_id ) { 384 504 * Errors are stored in the returned image metadata array. 385 505 * 386 506 * @since 5.3.0 507 * @since 6.1.0 The $mime_type parameter was added. 387 508 * @access private 388 509 * 389 * @param array $new_sizes Array defining what sizes to create. 390 * @param string $file Full path to the image file. 391 * @param array $image_meta The attachment meta data array. 392 * @param int $attachment_id Attachment ID to process. 510 * @param array $new_sizes Array defining what sizes to create. 511 * @param string $file Full path to the image file. 512 * @param array $image_meta The attachment meta data array. 513 * @param int $attachment_id Attachment ID to process. 514 * @param string $mime_type Optional. The mime type to check for missing sizes. Default is the image mime of $file. 393 515 * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing. 394 516 */ 395 function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) {517 function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id, $mime_type = '' ) { 396 518 if ( empty( $image_meta ) || ! is_array( $image_meta ) ) { 397 519 // Not an image attachment. 398 520 return array(); 399 521 } 400 522 523 $sizes = array(); 524 525 $original_mime_type = wp_get_image_mime( $file ); 526 if ( ! $mime_type ) { 527 $mime_type = $original_mime_type; 528 } 529 401 530 // Check if any of the new sizes already exist. 402 if ( isset( $ image_meta['sizes'] ) && is_array( $image_meta['sizes']) ) {403 foreach ( $ image_meta['sizes']as $size_name => $size_meta ) {531 if ( isset( $sizes ) && is_array( $sizes ) ) { 532 foreach ( $sizes as $size_name => $size_meta ) { 404 533 /* 405 534 * Only checks "size name" so we don't override existing images even if the dimensions 406 535 * don't match the currently defined size with the same name. 407 536 * To change the behavior, unset changed/mismatched sizes in the `sizes` array in image meta. 408 537 */ 409 538 if ( array_key_exists( $size_name, $new_sizes ) ) { 410 unset( $new_sizes[ $size_name ] ); 539 // Unset the size if it is either the required mime type already exists either as main mime type or 540 // within sources. 541 if ( $size_meta['mime-type'] === $mime_type || isset( $size_meta['sources'][ $mime_type ] ) ) { 542 unset( $new_sizes[ $size_name ] ); 543 } 411 544 } 412 545 } 413 546 } else { … … function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { 433 566 434 567 $new_sizes = array_filter( array_merge( $priority, $new_sizes ) ); 435 568 436 $editor = wp_get_image_editor( $file );569 $editor = wp_get_image_editor( $file, array( 'mime_type' => $mime_type ) ); 437 570 438 571 if ( is_wp_error( $editor ) ) { 439 572 // The image cannot be edited. 440 573 return $image_meta; 441 574 } 442 575 576 $editor->set_mime_type( $mime_type ); 577 443 578 // If stored EXIF data exists, rotate the source image before creating sub-sizes. 444 579 if ( ! empty( $image_meta['image_meta'] ) ) { 445 580 $rotated = $editor->maybe_exif_rotate(); … … function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { 457 592 // TODO: Log errors. 458 593 } else { 459 594 // Save the size meta value. 460 $image_meta['sizes'][ $new_size_name ] = $new_size_meta; 595 if ( ! isset( $image_meta['sizes'][ $new_size_name ] ) ) { 596 $image_meta['sizes'][ $new_size_name ] = $new_size_meta; 597 } else { 598 // Remove any newly generated images that are larger than the primary mime type. 599 $new_size = isset( $new_size_meta['filesize'] ) ? $new_size_meta['filesize'] : 0; 600 $primary_size = isset( $image_meta['sizes'][ $new_size_name ]['filesize'] ) ? $image_meta['sizes'][ $new_size_name ]['filesize'] : 0; 601 602 if ( $new_size && $primary_size && $new_size >= $primary_size ) { 603 wp_delete_file( dirname( $file ) . '/' . $new_size_meta['file'] ); 604 continue; 605 } 606 } 607 if ( ! isset( $image_meta['sizes'][ $new_size_name ]['sources'] ) ) { 608 $image_meta['sizes'][ $new_size_name ]['sources'] = array(); 609 } 610 $image_meta['sizes'][ $new_size_name ]['sources'][ $mime_type ] = _wp_get_sources_from_meta( $new_size_meta ); 461 611 wp_update_attachment_metadata( $attachment_id, $image_meta ); 462 612 } 463 613 } … … function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { 466 616 $created_sizes = $editor->multi_resize( $new_sizes ); 467 617 468 618 if ( ! empty( $created_sizes ) ) { 469 $image_meta['sizes'] = array_merge( $image_meta['sizes'], $created_sizes ); 619 foreach ( $created_sizes as $created_size_name => $created_size_meta ) { 620 621 // Primary mime type is set in 'sizes' array. 622 if ( ! isset( $image_meta['sizes'][ $created_size_name ] ) ) { 623 $image_meta['sizes'][ $created_size_name ] = $created_size_meta; 624 } else { 625 // Remove any newly generated images that are larger than the primary mime type. 626 $new_size = isset( $created_size_meta['filesize'] ) ? $created_size_meta['filesize'] : 0; 627 $primary_size = isset( $image_meta['sizes'][ $created_size_name ]['filesize'] ) ? $image_meta['sizes'][ $created_size_name ]['filesize'] : 0; 628 629 if ( $new_size && $primary_size && $new_size >= $primary_size ) { 630 wp_delete_file( dirname( $file ) . '/' . $created_size_meta['file'] ); 631 continue; 632 } 633 } 634 if ( ! isset( $image_meta['sizes'][ $created_size_name ]['sources'] ) ) { 635 $image_meta['sizes'][ $created_size_name ]['sources'] = array(); 636 } 637 $image_meta['sizes'][ $created_size_name ]['sources'][ $mime_type ] = _wp_get_sources_from_meta( $new_size_meta ); 638 } 470 639 wp_update_attachment_metadata( $attachment_id, $image_meta ); 471 640 } 472 641 } … … function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { 474 643 return $image_meta; 475 644 } 476 645 646 /** 647 * Filters the list of image size objects that support secondary mime type output. 648 * 649 * @since 6.1.0 650 * 651 * @param array $sizes Array of image sizes to filter 652 * @param int $attachment_id Attachment ID. 653 * @return array $sizes Array of size objects that support secondary mime type output. 654 */ 655 function _wp_filter_image_sizes_additional_mime_type_support( $sizes, $attachment_id ) { 656 657 // Include only the core sizes that do not rely on add_image_size(). Additional image sizes are opt-in. 658 $enabled_sizes = array( 659 'thumbnail' => true, 660 'medium' => true, 661 'medium_large' => true, 662 'large' => true, 663 'post-thumbnail' => true, 664 ); 665 666 /** 667 * Filter the sizes that support secondary mime type output. Developers can use this 668 * to control the output of additional mime type sub-sized images. 669 * 670 * @since 6.1.0 671 * 672 * @param array $enabled_sizes Map of size names and whether they support secondary mime type output. 673 * @param int $attachment_id Attachment ID. 674 */ 675 $enabled_sizes = apply_filters( 'wp_image_sizes_with_additional_mime_type_support', $enabled_sizes, $attachment_id ); 676 677 // Filter supported sizes to only include enabled sizes. 678 return array_intersect_key( $sizes, array_filter( $enabled_sizes ) ); 679 } 680 681 /** 682 * Low-level function to create full-size images in additional mime types. 683 * 684 * Updates the image meta after each mime type image is created. 685 * 686 * @since 6.1.0 687 * @access private 688 * 689 * @param array $new_mime_types Array defining what mime types to create. 690 * @param string $file Full path to the image file. 691 * @param array $image_meta The attachment meta data array. 692 * @param int $attachment_id Attachment ID to process. 693 * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing. 694 */ 695 function _wp_make_additional_mime_types( $new_mime_types, $file, $image_meta, $attachment_id ) { 696 $imagesize = array( 697 $image_meta['width'], 698 $image_meta['height'], 699 ); 700 $exif_meta = isset( $image_meta['image_meta'] ) ? $image_meta['image_meta'] : null; 701 $original_file_size = isset( $image_meta['filesize'] ) ? $image_meta['filesize'] : wp_filesize( $file ); 702 703 foreach ( $new_mime_types as $mime_type ) { 704 list( $editor, $resized, $rotated ) = _wp_maybe_scale_and_rotate_image( $file, $attachment_id, $imagesize, $exif_meta, $mime_type ); 705 if ( is_wp_error( $editor ) ) { 706 // The image cannot be edited. 707 continue; 708 } 709 710 $suffix = _wp_get_image_suffix( $resized, $rotated ); 711 $extension = wp_get_default_extension_for_mime_type( $mime_type ); 712 713 $saved = $editor->save( $editor->generate_filename( $suffix, null, $extension ) ); 714 715 if ( is_wp_error( $saved ) ) { 716 // TODO: Log errors. 717 } else { 718 // If the saved image is larger than the original, discard it. 719 $filesize = isset( $saved['filesize'] ) ? $saved['filesize'] : wp_filesize( $saved['path'] ); 720 if ( $filesize && $original_file_size && $filesize > $original_file_size ) { 721 wp_delete_file( $saved['path'] ); 722 continue; 723 } 724 $image_meta['sources'][ $mime_type ] = _wp_get_sources_from_meta( $saved ); 725 wp_update_attachment_metadata( $attachment_id, $image_meta ); 726 } 727 } 728 729 return $image_meta; 730 } 731 732 733 /** 734 * Check if an image belongs to an attachment. 735 * 736 * @since 6.1.0 737 * @access private 738 * 739 * @param string $filename Full path to the image file. 740 * @param int $attachment_id Attachment ID to check. 741 * @return bool True if the image belongs to the attachment, false otherwise. 742 */ 743 function _wp_image_belongs_to_attachment( $filename, $attachment_id ) { 744 $meta_data = wp_get_attachment_metadata( $attachment_id ); 745 746 if ( ! isset( $image_meta['sizes'] ) ) { 747 return false; 748 } 749 $sizes = $image_meta['sizes']; 750 foreach ( $sizes as $size ) { 751 if ( $size['file'] === $filename ) { 752 return true; 753 } 754 if ( isset( $size['sources'] ) && is_array( $size['sources'] ) ) { 755 foreach ( $size['sources'] as $source ) { 756 if ( $source['file'] === $filename ) { 757 return true; 758 } 759 } 760 } 761 } 762 return false; 763 } 764 477 765 /** 478 766 * Generate attachment meta data and create image sub-sizes for images. 479 767 * … … function wp_generate_attachment_metadata( $attachment_id, $file ) { 630 918 wp_update_attachment_metadata( $attachment_id, $metadata ); 631 919 632 920 // Create sub-sizes saving the image meta after each. 633 $metadata = _wp_make_subsizes( $merged_sizes, $image_file, $metadata, $attachment_id );921 $metadata = _wp_make_subsizes( $merged_sizes, $image_file, $metadata, $attachment_id, '' ); 634 922 } 635 923 } 636 924 } … … function _copy_image_file( $attachment_id ) { 1157 1445 1158 1446 return $dst_file; 1159 1447 } 1448 1449 /** 1450 * Returns an array with the list of valid mime types that a specific mime type should be converted into. 1451 * For example an `image/jpeg` should be converted into an `image/jpeg` and `image/webp`. The first type 1452 * is considered the primary output type for this image. 1453 * 1454 * Called for each uploaded image to determine the list of mime types that should be converted into. Then, 1455 * called again for each image size as they are generated to check if the image should be converted into the mime type 1456 * for that size. 1457 * 1458 * @since 6.1.0 1459 * 1460 * @param int $attachment_id The attachment ID. 1461 * @param string $image_size The image size name. False when called on the image and target size is unavailable. 1462 * @return array An array of valid mime types, where the key is the source file mime type and the list of mime types to 1463 * generate. 1464 */ 1465 function wp_upload_image_mime_transforms( $attachment_id, $image_size ) { 1466 $default_image_mime_transforms = array( 1467 'image/jpeg' => array( 'image/jpeg', 'image/webp' ), 1468 'image/webp' => array( 'image/webp', 'image/jpeg' ), 1469 ); 1470 $image_mime_transforms = $default_image_mime_transforms; 1471 1472 /** 1473 * Filter the output mime types for a given input mime type and image size. 1474 * 1475 * @since 6.1.0 1476 * 1477 * @param array $image_mime_transforms A map with the valid mime transforms where the key is the source file mime type 1478 * and the value is one or more mime file types to generate. 1479 * @param int $attachment_id The ID of the attachment where the hook was dispatched. 1480 * @param string $image_size The image size name. Optional. 1481 */ 1482 $image_mime_transforms = apply_filters( 'wp_upload_image_mime_transforms', $image_mime_transforms, $attachment_id, $image_size ); 1483 1484 if ( ! is_array( $image_mime_transforms ) ) { 1485 return $default_image_mime_transforms; 1486 } 1487 1488 return array_map( 1489 function( $transforms_list ) { 1490 return (array) $transforms_list; 1491 }, 1492 $image_mime_transforms 1493 ); 1494 } 1495 1496 /** 1497 * Extract the primary and additional mime output types for an image from the $image_mime_transforms. 1498 * 1499 * @since 6.1.0 1500 * @access private 1501 * 1502 * @param string $file Full path to the image file. 1503 * @param int $attachment_id Attachment ID to process. 1504 * @return array An array with two entries, the primary mime type and the list of additional mime types. 1505 */ 1506 function _wp_get_primary_and_additional_mime_types( $file, $attachment_id ) { 1507 $image_mime_transforms = wp_upload_image_mime_transforms( $attachment_id, false ); 1508 $original_mime_type = wp_get_image_mime( $file ); 1509 $output_mime_types = isset( $image_mime_transforms[ $original_mime_type ] ) ? $image_mime_transforms[ $original_mime_type ] : array( $original_mime_type ); 1510 1511 // Exclude any output mime types that the system doesn't support. 1512 $output_mime_types = array_values( 1513 array_filter( 1514 $output_mime_types, 1515 function( $mime_type ) { 1516 return wp_image_editor_supports( 1517 array( 1518 'mime_type' => $mime_type, 1519 ) 1520 ); 1521 } 1522 ) 1523 ); 1524 1525 // Handle an empty value for $output_mime_types: only output the original type. 1526 if ( empty( $output_mime_types ) ) { 1527 return array( $original_mime_type, array() ); 1528 } 1529 1530 // Use original mime type as primary mime type, or alternatively the first one. 1531 $primary_mime_type_key = array_search( $original_mime_type, $output_mime_types, true ); 1532 if ( false === $primary_mime_type_key ) { 1533 $primary_mime_type_key = 0; 1534 } 1535 // Split output mime types into primary mime type and additional mime types. 1536 $additional_mime_types = $output_mime_types; 1537 list( $primary_mime_type ) = array_splice( $additional_mime_types, $primary_mime_type_key, 1 ); 1538 1539 return array( 1540 $primary_mime_type, 1541 $additional_mime_types, 1542 ); 1543 } -
src/wp-includes/class-wp-image-editor.php
diff --git src/wp-includes/class-wp-image-editor.php src/wp-includes/class-wp-image-editor.php index caa3092d36..a2aff4d415 100644
abstract class WP_Image_Editor { 15 15 protected $file = null; 16 16 protected $size = null; 17 17 protected $mime_type = null; 18 protected $mime_type_set = false; 18 19 protected $output_mime_type = null; 19 20 protected $default_mime_type = 'image/jpeg'; 20 21 protected $quality = false; … … abstract class WP_Image_Editor { 334 335 protected function get_output_format( $filename = null, $mime_type = null ) { 335 336 $new_ext = null; 336 337 338 if ( ! $mime_type && $this->mime_type_set ) { 339 $mime_type = $this->mime_type; 340 } 341 337 342 // By default, assume specified type takes priority. 338 343 if ( $mime_type ) { 339 344 $new_ext = $this->get_extension( $mime_type ); … … abstract class WP_Image_Editor { 345 350 } else { 346 351 // If no file specified, grab editor's current extension and mime-type. 347 352 $file_ext = strtolower( pathinfo( $this->file, PATHINFO_EXTENSION ) ); 348 $file_mime = $this->mime_type;353 $file_mime = ! $this->mime_type_set ? $this->mime_type : $this->get_mime_type( $file_ext ); 349 354 } 350 355 351 356 // Check to see if specified mime-type is the same as type implied by … … abstract class WP_Image_Editor { 428 433 * Builds an output filename based on current file, and adding proper suffix 429 434 * 430 435 * @since 3.5.0 436 * @since 6.1.0 Skips adding a suffix when set to an empty string. 431 437 * 432 * @param string $suffix 438 * @param string $suffix Optional. Suffix to add to the filename. Passing null 439 * will result in a 'widthxheight' suffix. Passing 440 * an empty string will result in no suffix. 433 441 * @param string $dest_path 434 442 * @param string $extension 435 443 * @return string filename 436 444 */ 437 445 public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) { 438 446 // $suffix will be appended to the destination filename, just before the extension. 439 if ( !$suffix ) {447 if ( null === $suffix ) { 440 448 $suffix = $this->get_suffix(); 441 449 } 442 450 … … abstract class WP_Image_Editor { 457 465 } 458 466 } 459 467 460 return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}"; 468 if ( empty( $suffix ) ) { 469 $suffix = ''; 470 } else { 471 $suffix = "-{$suffix}"; 472 } 473 474 // When the mime type being generated is different from the source, add the extension to the suffix to ensure uniqueness. 475 if ( ! empty( $extension ) && $extension !== $ext ) { 476 $suffix .= "-{$ext}"; 477 } 478 479 return trailingslashit( $dir ) . "{$name}{$suffix}.{$new_ext}"; 461 480 } 462 481 463 482 /** … … abstract class WP_Image_Editor { 476 495 } 477 496 478 497 /** 479 * Check if a JPEGimage has EXIF Orientation tag and rotate it if needed.498 * Check if an image has EXIF Orientation tag and rotate it if needed. 480 499 * 481 500 * @since 5.3.0 482 501 * … … abstract class WP_Image_Editor { 486 505 public function maybe_exif_rotate() { 487 506 $orientation = null; 488 507 489 if ( is_callable( 'exif_read_data' ) && 'image/jpeg' === $this->mime_type) {508 if ( is_callable( 'exif_read_data' ) ) { 490 509 $exif_data = @exif_read_data( $this->file ); 491 510 492 511 if ( ! empty( $exif_data['Orientation'] ) ) { … … abstract class WP_Image_Editor { 637 656 638 657 return wp_get_default_extension_for_mime_type( $mime_type ); 639 658 } 640 }641 659 660 /** 661 * Set the editor mime type, useful when outputting alternate mime types. 662 * 663 * Track that the mime type is set with the mime type set flag. 664 * 665 * @since 6.1.0 666 * 667 * @param string $mime_type The mime type to set. 668 */ 669 public function set_mime_type( $mime_type ) { 670 $this->mime_type = $mime_type; 671 $this->mime_type_set = true; 672 } 673 674 /** 675 * Reset the mime type to the original file mime type. 676 * 677 * Reset the mime type set flag. 678 * 679 * @since 6.1.0 680 */ 681 public function reset_mime_type() { 682 $this->mime_type = wp_get_image_mime( $this->file ); 683 $this->mime_type_set = false; 684 } 685 } -
src/wp-includes/media.php
diff --git src/wp-includes/media.php src/wp-includes/media.php index aaf811d2d0..51c49f83d2 100644
function wp_filter_content_tags( $content, $context = null ) { 1852 1852 $filtered_image = wp_img_tag_add_decoding_attr( $filtered_image, $context ); 1853 1853 } 1854 1854 1855 // Use alternate mime types when specified and available. 1856 if ( $attachment_id > 0 && _wp_in_front_end_context() ) { 1857 $filtered_image = wp_image_use_alternate_mime_types( $filtered_image, $context, $attachment_id ); 1858 } 1859 1855 1860 /** 1856 1861 * Filters an img tag within the content for a given context. 1857 1862 * … … function wp_filter_content_tags( $content, $context = null ) { 1898 1903 return $content; 1899 1904 } 1900 1905 1906 /** 1907 * Use alternate mime type images in the front end content output when available. 1908 * 1909 * @since 6.1.0 1910 * 1911 * @param string $image The HTML `img` tag where the attribute should be added. 1912 * @param string $context Additional context to pass to the filters. 1913 * @param int $attachment_id The attachment ID. 1914 * @return string Converted `img` tag with `loading` attribute added. 1915 */ 1916 function wp_image_use_alternate_mime_types( $image, $context, $attachment_id ) { 1917 $metadata = wp_get_attachment_metadata( $attachment_id ); 1918 if ( empty( $metadata['file'] ) ) { 1919 return $image; 1920 } 1921 1922 // Only alter images with a `sources` attribute 1923 if ( empty( $metadata['sources'] ) ) { 1924 return $image; 1925 }; 1926 1927 $target_mimes = array( 'image/webp', 'image/jpeg' ); 1928 1929 /** 1930 * Filter the content image mime type output selection and order. 1931 * 1932 * When outputting images in the content, the first mime type available will be used. 1933 * 1934 * @since 6.1.0 1935 * 1936 * @param array $target_mimes The image output mime type and order. Default is array( 'image/webp', 'image/jpeg' ). 1937 * @param int $attachment_id The attachment ID. 1938 * @param string $context Additional context to pass to the filters. 1939 * @return array The filtered output mime type and order. Return an empty array to skip mime type substitution. 1940 */ 1941 $target_mimes = apply_filters( 'wp_content_image_mimes', $target_mimes, $attachment_id, $context ); 1942 1943 if ( false === $target_mimes ) { 1944 return $image; 1945 } 1946 1947 // Find the appropriate size for the provided URL in the first available mime type. 1948 foreach ( $target_mimes as $target_mime ) { 1949 // Handle full size image replacement. 1950 if ( ! empty( $metadata['sources'][ $target_mime ]['file'] ) ) { 1951 $src_filename = wp_basename( $metadata['file'] ); 1952 1953 // This is the same MIME type as the original, so the entire $target_mime can be skipped. 1954 // Since it is already the preferred MIME type, the entire loop can be cancelled. 1955 if ( $metadata['sources'][ $target_mime ]['file'] === $src_filename ) { 1956 break; 1957 } 1958 1959 $image = str_replace( $src_filename, $metadata['sources'][ $target_mime ]['file'], $image ); 1960 1961 // The full size was replaced, so unset this entirely here so that in the next iteration it is no longer 1962 // considered, simply for a small performance optimization. 1963 unset( $metadata['sources'] ); 1964 } 1965 1966 // Go through each image size and replace with the first available mime type version. 1967 foreach ( $metadata['sizes'] as $name => $size_data ) { 1968 // Check if size has an original file. 1969 if ( empty( $size_data['file'] ) ) { 1970 continue; 1971 } 1972 1973 // Check if size has a source in the desired mime type. 1974 if ( empty( $size_data['sources'][ $target_mime ]['file'] ) ) { 1975 continue; 1976 } 1977 1978 $src_filename = wp_basename( $size_data['file'] ); 1979 1980 // This is the same MIME type as the original, so the entire $target_mime can be skipped. 1981 // Since it is already the preferred MIME type, the entire loop can be cancelled. 1982 if ( $size_data['sources'][ $target_mime ]['file'] === $src_filename ) { 1983 break 2; 1984 } 1985 1986 // Found a match, replace with the new filename. 1987 $image = str_replace( $src_filename, $size_data['sources'][ $target_mime ]['file'], $image ); 1988 1989 // This size was replaced, so unset this entirely here so that in the next iteration it is no longer 1990 // considered, simply for a small performance optimization. 1991 unset( $metadata['sizes'][ $name ] ); 1992 } 1993 } 1994 return $image; 1995 } 1996 1997 /** 1998 * Check if execution is currently in the front end content context, outside of <head>. 1999 * 2000 * @since 6.1.0 2001 * @access private 2002 * 2003 * @return bool True if in the front end content context, false otherwise. 2004 */ 2005 function _wp_in_front_end_context() { 2006 global $wp_query; 2007 2008 // Check if this request is generally outside (or before) any frontend context. 2009 if ( ! isset( $wp_query ) || defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || is_feed() ) { 2010 return false; 2011 } 2012 2013 // Check if we're anywhere before the 'wp_head' action has completed. 2014 return did_action( 'template_redirect' ) && ! doing_action( 'wp_head' ); 2015 } 2016 1901 2017 /** 1902 2018 * Adds `loading` attribute to an `img` HTML tag. 1903 2019 * -
src/wp-includes/post.php
diff --git src/wp-includes/post.php src/wp-includes/post.php index b20dfc603f..4e221e726f 100644
function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) { 6459 6459 $intermediate_dir = path_join( $uploadpath['basedir'], dirname( $file ) ); 6460 6460 6461 6461 foreach ( $meta['sizes'] as $size => $sizeinfo ) { 6462 $intermediate_file = str_replace( wp_basename( $file ), $sizeinfo['file'], $file );6463 6462 6464 if ( ! empty( $intermediate_file ) ) { 6465 $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); 6463 // Check for alternate size mime types in the sizeinfo['sources'] array to delete. 6464 if ( isset( $sizeinfo['sources'] ) && is_array( $sizeinfo['sources'] ) ) { 6465 foreach ( $sizeinfo['sources'] as $mime => $properties ) { 6466 $intermediate_file = str_replace( wp_basename( $file ), $properties['file'], $file ); 6467 if ( ! empty( $intermediate_file ) ) { 6468 $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); 6469 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6470 $deleted = false; 6471 } 6472 } 6473 } 6474 } else { 6475 // Otherwise, delete files from the sizeinfo data. 6476 $intermediate_file = str_replace( wp_basename( $file ), $sizeinfo['file'], $file ); 6466 6477 6467 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6468 $deleted = false; 6478 if ( ! empty( $intermediate_file ) ) { 6479 $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); 6480 6481 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6482 $deleted = false; 6483 } 6469 6484 } 6470 6485 } 6471 6486 } … … function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) { 6487 6502 } 6488 6503 } 6489 6504 6505 // Delete the full size images from 'sources' if available, or the root file. 6506 if ( isset( $meta['sources'] ) && is_array( $meta['sources'] ) ) { 6507 $sources = $meta['sources']; 6508 $intermediate_dir = path_join( $uploadpath['basedir'], dirname( $file ) ); 6509 foreach ( $sources as $mime => $properties ) { 6510 if ( ! is_array( $properties ) || empty( $properties['file'] ) ) { 6511 continue; 6512 } 6513 $intermediate_file = str_replace( wp_basename( $file ), $properties['file'], $file ); 6514 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6515 $deleted = false; 6516 } 6517 } 6518 } else { 6519 if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) { 6520 $deleted = false; 6521 } 6522 } 6523 6490 6524 if ( is_array( $backup_sizes ) ) { 6491 $del_dir = path_join( $uploadpath['basedir'], dirname( $meta['file'] ) );6492 6525 6526 $del_dir = path_join( $uploadpath['basedir'], dirname( $meta['file'] ) ); 6527 // Delete the root (edited) file which was not deleted above. 6528 if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) { 6529 $deleted = false; 6530 } 6493 6531 foreach ( $backup_sizes as $size ) { 6494 $del_file = path_join( dirname( $meta['file'] ), $size['file'] ); 6495 6496 if ( ! empty( $del_file ) ) { 6497 $del_file = path_join( $uploadpath['basedir'], $del_file ); 6532 // Delete files from 'sources' data if available, otherwise from 'sizes' data. 6533 if ( isset( $meta['sources'] ) && is_array( $meta['sources'] ) ) { 6534 // Delete any backup images stored in the 'sources' array. 6535 if ( isset( $size['sources'] ) && is_array( $size['sources'] ) ) { 6536 foreach ( $size['sources'] as $mime => $properties ) { 6537 $del_file = path_join( dirname( $meta['file'] ), $properties['file'] ); 6538 if ( ! empty( $del_file ) ) { 6539 $del_file = path_join( $uploadpath['basedir'], $del_file ); 6540 if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { 6541 $deleted = false; 6542 } 6543 } 6544 } 6545 } 6546 } else { 6547 $del_file = path_join( dirname( $meta['file'] ), $size['file'] ); 6498 6548 6499 if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { 6500 $deleted = false; 6549 if ( ! empty( $del_file ) ) { 6550 $del_file = path_join( $uploadpath['basedir'], $del_file ); 6551 if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { 6552 $deleted = false; 6553 } 6501 6554 } 6502 6555 } 6503 6556 } 6504 6557 } 6505 6558 6506 if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) {6507 $deleted = false;6508 }6509 6510 6559 return $deleted; 6511 6560 } 6512 6561 -
tests/phpunit/tests/image/editor.php
diff --git tests/phpunit/data/images/test-image-rotated-90ccw.jpg tests/phpunit/data/images/test-image-rotated-90ccw.jpg new file mode 100644 index 0000000000..b579b7f9ab Binary files /dev/null and tests/phpunit/data/images/test-image-rotated-90ccw.jpg differ diff --git tests/phpunit/data/images/test-image-rotated-90cw.webp tests/phpunit/data/images/test-image-rotated-90cw.webp new file mode 100644 index 0000000000..82e77bed08 Binary files /dev/null and tests/phpunit/data/images/test-image-rotated-90cw.webp differ diff --git tests/phpunit/data/images/test-image.jpeg tests/phpunit/data/images/test-image.jpeg new file mode 100644 index 0000000000..534aac1d6b Binary files /dev/null and tests/phpunit/data/images/test-image.jpeg differ diff --git tests/phpunit/tests/image/editor.php tests/phpunit/tests/image/editor.php index 487dad0664..742a78adfb 100644
class Tests_Image_Editor extends WP_Image_UnitTestCase { 226 226 $this->assertSame( trailingslashit( realpath( get_temp_dir() ) ), trailingslashit( realpath( dirname( $editor->generate_filename( null, get_temp_dir() ) ) ) ) ); 227 227 228 228 // Test with a suffix only. 229 $this->assertSame( 'canola-100x50 .png', wp_basename( $editor->generate_filename( null, null, 'png' ) ) );229 $this->assertSame( 'canola-100x50-jpg.png', wp_basename( $editor->generate_filename( null, null, 'png' ) ) ); 230 230 231 231 // Combo! 232 $this->assertSame( trailingslashit( realpath( get_temp_dir() ) ) . 'canola-new .png', $editor->generate_filename( 'new', realpath( get_temp_dir() ), 'png' ) );232 $this->assertSame( trailingslashit( realpath( get_temp_dir() ) ) . 'canola-new-jpg.png', $editor->generate_filename( 'new', realpath( get_temp_dir() ), 'png' ) ); 233 233 234 234 // Test with a stream destination. 235 235 $this->assertSame( 'file://testing/path/canola-100x50.jpg', $editor->generate_filename( null, 'file://testing/path' ) ); … … class Tests_Image_Editor extends WP_Image_UnitTestCase { 361 361 ), 362 362 ); 363 363 } 364 /** 365 * Create the original image mime type when the image is uploaded 366 * 367 * @dataProvider provider_image_with_default_behaviors_during_upload 368 * 369 * @since 6.0.0 370 */ 371 public function it_should_create_the_original_image_mime_type_when_the_image_is_uploaded( $file_location, $expected_mime, $targeted_mime ) { 372 $attachment_id = $this->factory->attachment->create_upload_object( $file_location ); 373 374 $metadata = wp_get_attachment_metadata( $attachment_id ); 375 376 $this->assertIsArray( $metadata ); 377 foreach ( $metadata['sizes'] as $size_name => $properties ) { 378 $this->assertArrayHasKey( 'sources', $properties ); 379 $this->assertIsArray( $properties['sources'] ); 380 $this->assertArrayHasKey( $expected_mime, $properties['sources'] ); 381 $this->assertArrayHasKey( 'filesize', $properties['sources'][ $expected_mime ] ); 382 $this->assertArrayHasKey( 'file', $properties['sources'][ $expected_mime ] ); 383 $this->assertArrayHasKey( $targeted_mime, $properties['sources'] ); 384 $this->assertArrayHasKey( 'filesize', $properties['sources'][ $targeted_mime ] ); 385 $this->assertArrayHasKey( 'file', $properties['sources'][ $targeted_mime ] ); 386 } 387 } 388 389 public function provider_image_with_default_behaviors_during_upload() { 390 yield 'JPEG image' => array( 391 DIR_TESTDATA . '/images/test-image.jpg', 392 'image/jpeg', 393 'image/webp', 394 ); 395 396 yield 'WebP image' => array( 397 DIR_TESTDATA . '/images/webp-lossy.webp', 398 'image/webp', 399 'image/jpeg', 400 ); 401 } 402 403 /** 404 * Not create the sources property if no transform is provided 405 * 406 * @since 6.1.0 407 */ 408 public function it_should_not_create_the_sources_property_if_no_transform_is_provided() { 409 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 410 411 $attachment_id = $this->factory->attachment->create_upload_object( 412 DIR_TESTDATA . '/images/test-image.jpg' 413 ); 414 415 $metadata = wp_get_attachment_metadata( $attachment_id ); 416 417 $this->assertIsArray( $metadata ); 418 foreach ( $metadata['sizes'] as $size_name => $properties ) { 419 $this->assertArrayNotHasKey( 'sources', $properties ); 420 } 421 } 422 423 /** 424 * Create the sources property when no transform is available 425 * 426 * @since 6.1.0 427 */ 428 public function it_should_create_the_sources_property_when_no_transform_is_available() { 429 add_filter( 430 'wp_upload_image_mime_transforms', 431 function () { 432 return array( 'image/jpeg' => array() ); 433 } 434 ); 435 436 $attachment_id = $this->factory->attachment->create_upload_object( 437 DIR_TESTDATA . '/images/test-image.jpg' 438 ); 439 440 $metadata = wp_get_attachment_metadata( $attachment_id ); 441 442 $this->assertIsArray( $metadata ); 443 foreach ( $metadata['sizes'] as $size_name => $properties ) { 444 $this->assertArrayHasKey( 'sources', $properties ); 445 $this->assertIsArray( $properties['sources'] ); 446 $this->assertArrayHasKey( 'image/jpeg', $properties['sources'] ); 447 $this->assertArrayHasKey( 'filesize', $properties['sources']['image/jpeg'] ); 448 $this->assertArrayHasKey( 'file', $properties['sources']['image/jpeg'] ); 449 $this->assertArrayNotHasKey( 'image/webp', $properties['sources'] ); 450 } 451 } 452 453 /** 454 * Not create the sources property if the mime is not specified on the transforms images 455 * 456 * @since 6.1.0 457 */ 458 public function it_should_not_create_the_sources_property_if_the_mime_is_not_specified_on_the_transforms_images() { 459 add_filter( 460 'wp_upload_image_mime_transforms', 461 function () { 462 return array( 'image/jpeg' => array() ); 463 } 464 ); 465 466 $attachment_id = $this->factory->attachment->create_upload_object( 467 DIR_TESTDATA . '/images/webp-lossy.webp' 468 ); 469 470 $metadata = wp_get_attachment_metadata( $attachment_id ); 471 472 $this->assertIsArray( $metadata ); 473 foreach ( $metadata['sizes'] as $size_name => $properties ) { 474 $this->assertArrayNotHasKey( 'sources', $properties ); 475 } 476 } 477 478 /** 479 * Do not create the sources property when opting out by size. 480 * @since 6.1.0 481 */ 482 public function it_should_not_create_the_sources_property_when_opting_out_by_size() { 483 // Exclude the large image from mime transforms. 484 add_filter( 485 'wp_upload_image_mime_transforms', 486 function ( $transforms, $attachment_id, $size_name ) { 487 if ( 'large' === $size_name ) { 488 return array(); 489 } 490 return $transforms; 491 }, 492 10, 493 3 494 ); 495 496 $attachment_id = $this->factory->attachment->create_upload_object( 497 DIR_TESTDATA . '/images/test-image.jpg' 498 ); 499 500 $metadata = wp_get_attachment_metadata( $attachment_id ); 501 502 $this->assertIsArray( $metadata ); 503 // Expect sources data for every size except the large size. 504 foreach ( $metadata['sizes'] as $size_name => $properties ) { 505 if ( 'large' === $size_name ) { 506 $this->assertArrayNotHasKey( 'sources', $properties ); 507 } else { 508 $this->assertArrayHasKey( 'sources', $properties ); 509 510 } 511 } 512 } 513 514 515 516 /** 517 * Create a WebP version with all the required properties 518 * 519 * @since 6.0.0 520 */ 521 public function it_should_create_a_webp_version_with_all_the_required_properties() { 522 $attachment_id = $this->factory->attachment->create_upload_object( 523 DIR_TESTDATA . '/images/test-image.jpg' 524 ); 525 526 $metadata = wp_get_attachment_metadata( $attachment_id ); 527 $this->assertArrayHasKey( 'sources', $metadata['sizes']['thumbnail'] ); 528 $this->assertArrayHasKey( 'image/jpeg', $metadata['sizes']['thumbnail']['sources'] ); 529 $this->assertArrayHasKey( 'filesize', $metadata['sizes']['thumbnail']['sources']['image/jpeg'] ); 530 $this->assertArrayHasKey( 'file', $metadata['sizes']['thumbnail']['sources']['image/jpeg'] ); 531 $this->assertArrayHasKey( 'image/webp', $metadata['sizes']['thumbnail']['sources'] ); 532 $this->assertArrayHasKey( 'filesize', $metadata['sizes']['thumbnail']['sources']['image/webp'] ); 533 $this->assertArrayHasKey( 'file', $metadata['sizes']['thumbnail']['sources']['image/webp'] ); 534 $this->assertStringEndsNotWith( '.jpeg', $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ); 535 $this->assertStringEndsWith( '.webp', $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ); 536 } 537 538 /** 539 * Remove `scaled` suffix from the generated filename 540 * 541 * @since 6.0.0 542 */ 543 public function it_should_remove_scaled_suffix_from_the_generated_filename() { 544 // The leafs image is 1080 pixels wide with this filter we ensure a -scaled version is created. 545 add_filter( 546 'big_image_size_threshold', 547 function () { 548 return 850; 549 } 550 ); 551 552 $attachment_id = $this->factory->attachment->create_upload_object( 553 DIR_TESTDATA . '/images/test-image.jpg' 554 ); 555 $metadata = wp_get_attachment_metadata( $attachment_id ); 556 $this->assertStringEndsWith( '-scaled.jpg', get_attached_file( $attachment_id ) ); 557 $this->assertArrayHasKey( 'image/webp', $metadata['sizes']['medium']['sources'] ); 558 $this->assertStringEndsNotWith( '-scaled.webp', $metadata['sizes']['medium']['sources']['image/webp']['file'] ); 559 $this->assertStringEndsWith( '-300x200.webp', $metadata['sizes']['medium']['sources']['image/webp']['file'] ); 560 } 561 562 /** 563 * Remove the generated webp images when the attachment is deleted 564 * 565 * @since 6.0.0 566 */ 567 public function it_should_remove_the_generated_webp_images_when_the_attachment_is_deleted() { 568 // Make sure no editor is available. 569 $attachment_id = $this->factory->attachment->create_upload_object( 570 DIR_TESTDATA . '/images/test-image.jpg' 571 ); 572 573 $file = get_attached_file( $attachment_id, true ); 574 $dirname = pathinfo( $file, PATHINFO_DIRNAME ); 575 576 $this->assertIsString( $file ); 577 $this->assertFileExists( $file ); 578 579 $metadata = wp_get_attachment_metadata( $attachment_id ); 580 $sizes = array( 'thumbnail', 'medium' ); 581 582 foreach ( $sizes as $size_name ) { 583 $this->assertArrayHasKey( 'image/webp', $metadata['sizes'][ $size_name ]['sources'] ); 584 $this->assertArrayHasKey( 'file', $metadata['sizes'][ $size_name ]['sources']['image/webp'] ); 585 $this->assertFileExists( 586 path_join( $dirname, $metadata['sizes'][ $size_name ]['sources']['image/webp']['file'] ) 587 ); 588 } 589 590 wp_delete_attachment( $attachment_id ); 591 592 foreach ( $sizes as $size_name ) { 593 $this->assertFileDoesNotExist( 594 path_join( $dirname, $metadata['sizes'][ $size_name ]['sources']['image/webp']['file'] ) 595 ); 596 } 597 } 598 599 /** 600 * Remove the attached WebP version if the attachment is force deleted but empty trash day is not defined 601 * 602 * @since 6.0.0 603 */ 604 public function it_should_remove_the_attached_webp_version_if_the_attachment_is_force_deleted_but_empty_trash_day_is_not_defined() { 605 // Make sure no editor is available. 606 $attachment_id = $this->factory->attachment->create_upload_object( 607 DIR_TESTDATA . '/images/test-image.jpg' 608 ); 609 610 $file = get_attached_file( $attachment_id, true ); 611 $dirname = pathinfo( $file, PATHINFO_DIRNAME ); 612 613 $this->assertIsString( $file ); 614 $this->assertFileExists( $file ); 615 616 $metadata = wp_get_attachment_metadata( $attachment_id ); 617 618 $this->assertFileExists( 619 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 620 ); 621 622 wp_delete_attachment( $attachment_id, true ); 623 624 $this->assertFileDoesNotExist( 625 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 626 ); 627 } 628 629 /** 630 * Remove the WebP version of the image if the image is force deleted and empty trash days is set to zero 631 * 632 * @since 6.0.0 633 */ 634 public function it_should_remove_the_webp_version_of_the_image_if_the_image_is_force_deleted_and_empty_trash_days_is_set_to_zero() { 635 // Make sure no editor is available. 636 $attachment_id = $this->factory->attachment->create_upload_object( 637 DIR_TESTDATA . '/images/test-image.jpg' 638 ); 639 640 $file = get_attached_file( $attachment_id, true ); 641 $dirname = pathinfo( $file, PATHINFO_DIRNAME ); 642 643 $this->assertIsString( $file ); 644 $this->assertFileExists( $file ); 645 646 $metadata = wp_get_attachment_metadata( $attachment_id ); 647 648 $this->assertFileExists( 649 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 650 ); 651 652 define( 'EMPTY_TRASH_DAYS', 0 ); 653 654 wp_delete_attachment( $attachment_id, true ); 655 656 $this->assertFileDoesNotExist( 657 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 658 ); 659 } 660 661 /** 662 * Avoid the change of URLs of images that are not part of the media library 663 * 664 * @group webp_uploads_update_image_references 665 * 666 * @since 6.0.0 667 */ 668 public function it_should_avoid_the_change_of_urls_of_images_that_are_not_part_of_the_media_library() { 669 $paragraph = '<p>Donec accumsan, sapien et <img src="https://ia600200.us.archive.org/16/items/SPD-SLRSY-1867/hubblesite_2001_06.jpg">, id commodo nisi sapien et est. Mauris nisl odio, iaculis vitae pellentesque nec.</p>'; 670 671 $this->assertSame( $paragraph, webp_uploads_update_image_references( $paragraph ) ); 672 } 673 674 /** 675 * Avoid replacing not existing attachment IDs 676 * 677 * @group webp_uploads_update_image_references 678 * 679 * @since 6.0.0 680 */ 681 public function it_should_avoid_replacing_not_existing_attachment_i_ds() { 682 $paragraph = '<p>Donec accumsan, sapien et <img class="wp-image-0" src="https://ia600200.us.archive.org/16/items/SPD-SLRSY-1867/hubblesite_2001_06.jpg">, id commodo nisi sapien et est. Mauris nisl odio, iaculis vitae pellentesque nec.</p>'; 683 684 $this->assertSame( $paragraph, webp_uploads_update_image_references( $paragraph ) ); 685 } 686 687 /** 688 * Prevent replacing a WebP image 689 * 690 * @group webp_uploads_update_image_references 691 * 692 * @since 6.0.0 693 */ 694 public function it_should_prevent_replacing_a_webp_image() { 695 $attachment_id = $this->factory->attachment->create_upload_object( 696 DIR_TESTDATA . '/images/webp-lossy.webp' 697 ); 698 699 $tag = wp_get_attachment_image( $attachment_id, 'medium', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 700 701 $this->assertSame( $tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 702 } 703 704 /** 705 * Prevent replacing a jpg image if the image does not have the target class name 706 * 707 * @since 6.0.0 708 */ 709 public function it_should_prevent_replacing_a_jpg_image_if_the_image_does_not_have_the_target_class_name() { 710 $attachment_id = $this->factory->attachment->create_upload_object( 711 DIR_TESTDATA . '/images/test-image.jpg' 712 ); 713 714 $tag = wp_get_attachment_image( $attachment_id, 'medium' ); 715 716 $this->assertSame( $tag, webp_uploads_update_image_references( $tag ) ); 717 } 718 719 /** 720 * Replace the references to a JPG image to a WebP version 721 * 722 * @dataProvider provider_replace_images_with_different_extensions 723 * @group webp_uploads_update_image_references 724 * 725 * @since 6.0.0 726 */ 727 public function it_should_replace_the_references_to_a_jpg_image_to_a_webp_version( $image_path ) { 728 $attachment_id = $this->factory->attachment->create_upload_object( $image_path ); 729 730 $tag = wp_get_attachment_image( $attachment_id, 'medium', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 731 $expected_tag = $tag; 732 $metadata = wp_get_attachment_metadata( $attachment_id ); 733 foreach ( $metadata['sizes'] as $size => $properties ) { 734 $expected_tag = str_replace( $properties['sources']['image/jpeg']['file'], $properties['sources']['image/webp']['file'], $expected_tag ); 735 } 736 737 $this->assertNotEmpty( $expected_tag ); 738 $this->assertNotSame( $tag, $expected_tag ); 739 $this->assertSame( $expected_tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 740 } 741 742 public function provider_replace_images_with_different_extensions() { 743 yield 'An image with a .jpg extension' => array( DIR_TESTDATA . '/images/test-image.jpg' ); 744 yield 'An image with a .jpeg extension' => array( DIR_TESTDATA . '/images/test-image.jpeg' ); 745 } 746 747 /** 748 * Contain the full image size from the original mime 749 * 750 * @group webp_uploads_update_image_references 751 * 752 * @since 6.0.0 753 */ 754 public function it_should_contain_the_full_image_size_from_the_original_mime() { 755 $attachment_id = $this->factory->attachment->create_upload_object( 756 DIR_TESTDATA . '/images/test-image.jpg' 757 ); 758 759 $tag = wp_get_attachment_image( $attachment_id, 'full', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 760 761 $expected = array( 762 'ext' => 'jpg', 763 'type' => 'image/jpeg', 764 ); 765 $this->assertSame( $expected, wp_check_filetype( get_attached_file( $attachment_id ) ) ); 766 $this->assertContains( wp_basename( get_attached_file( $attachment_id ) ), webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 767 } 768 769 /** 770 * Prevent replacing an image with no available sources 771 * 772 * @group webp_uploads_update_image_references 773 * 774 * @since 6.0.0 775 */ 776 public function it_should_prevent_replacing_an_image_with_no_available_sources() { 777 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 778 779 $attachment_id = $this->factory->attachment->create_upload_object( DIR_TESTDATA . '/images/test-image.jpg' ); 780 781 $tag = wp_get_attachment_image( $attachment_id, 'full', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 782 $this->assertSame( $tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 783 } 784 785 /** 786 * Prevent update not supported images with no available sources 787 * 788 * @dataProvider data_provider_not_supported_webp_images 789 * @group webp_uploads_update_image_references 790 * 791 * @since 6.0.0 792 */ 793 public function it_should_prevent_update_not_supported_images_with_no_available_sources( $image_path ) { 794 $attachment_id = $this->factory->attachment->create_upload_object( $image_path ); 795 796 $this->assertIsNumeric( $attachment_id ); 797 $tag = wp_get_attachment_image( $attachment_id, 'full', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 798 799 $this->assertSame( $tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 800 } 801 802 public function data_provider_not_supported_webp_images() { 803 yield 'PNG image' => array( DIR_TESTDATA . '/images/test-image.png' ); 804 yield 'GIFT image' => array( DIR_TESTDATA . '/images/test-image.gif' ); 805 } 806 807 364 808 365 809 } -
tests/phpunit/tests/image/functions.php
diff --git tests/phpunit/tests/image/functions.php tests/phpunit/tests/image/functions.php index 86d559145e..57650e7a0b 100644
class Tests_Image_Functions extends WP_UnitTestCase { 639 639 $this->markTestSkipped( 'Rendering PDFs is not supported on this system.' ); 640 640 } 641 641 642 // Use legacy JPEG output. 643 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 644 642 645 $orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf'; 643 646 $test_file = get_temp_dir() . 'wordpress-gsoc-flyer.pdf'; 644 647 copy( $orig_file, $test_file ); … … class Tests_Image_Functions extends WP_UnitTestCase { 659 662 $this->assertNotEmpty( $attachment_id ); 660 663 661 664 $temp_dir = get_temp_dir(); 662 663 665 $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); 664 666 665 667 $expected = array( … … class Tests_Image_Functions extends WP_UnitTestCase { 677 679 'height' => 300, 678 680 'mime-type' => 'image/jpeg', 679 681 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-232x300.jpg' ), 682 'sources' => array( 683 'image/jpeg' => array( 684 'file' => 'wordpress-gsoc-flyer-pdf-232x300.jpg', 685 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-232x300.jpg' ), 686 ), 687 ), 680 688 ), 681 689 'large' => array( 682 690 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', … … class Tests_Image_Functions extends WP_UnitTestCase { 684 692 'height' => 1024, 685 693 'mime-type' => 'image/jpeg', 686 694 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 695 'sources' => array( 696 'image/jpeg' => array( 697 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', 698 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 699 ), 700 ), 687 701 ), 688 702 'thumbnail' => array( 689 703 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', … … class Tests_Image_Functions extends WP_UnitTestCase { 691 705 'height' => 150, 692 706 'mime-type' => 'image/jpeg', 693 707 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 708 'sources' => array( 709 'image/jpeg' => array( 710 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', 711 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 712 ), 713 ), 694 714 ), 695 715 ), 696 716 'filesize' => wp_filesize( $test_file ), … … class Tests_Image_Functions extends WP_UnitTestCase { 702 722 foreach ( $metadata['sizes'] as $size ) { 703 723 unlink( $temp_dir . $size['file'] ); 704 724 } 725 remove_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 705 726 } 706 727 707 728 /** … … class Tests_Image_Functions extends WP_UnitTestCase { 716 737 717 738 update_option( 'medium_crop', 1 ); 718 739 740 // Use legacy JPEG output. 741 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 742 719 743 $orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf'; 720 744 $test_file = get_temp_dir() . 'wordpress-gsoc-flyer.pdf'; 721 745 copy( $orig_file, $test_file ); … … class Tests_Image_Functions extends WP_UnitTestCase { 754 778 'height' => 300, 755 779 'mime-type' => 'image/jpeg', 756 780 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-300x300.jpg' ), 781 'sources' => array( 782 'image/jpeg' => array( 783 'file' => 'wordpress-gsoc-flyer-pdf-300x300.jpg', 784 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-300x300.jpg' ), 785 ), 786 ), 757 787 ), 758 788 'large' => array( 759 789 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', … … class Tests_Image_Functions extends WP_UnitTestCase { 761 791 'height' => 1024, 762 792 'mime-type' => 'image/jpeg', 763 793 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 794 'sources' => array( 795 'image/jpeg' => array( 796 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', 797 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 798 ), 799 ), 800 764 801 ), 765 802 'thumbnail' => array( 766 803 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', … … class Tests_Image_Functions extends WP_UnitTestCase { 768 805 'height' => 150, 769 806 'mime-type' => 'image/jpeg', 770 807 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 808 'sources' => array( 809 'image/jpeg' => array( 810 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', 811 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 812 ), 813 ), 771 814 ), 772 815 ), 773 816 'filesize' => wp_filesize( $test_file ), … … class Tests_Image_Functions extends WP_UnitTestCase { 779 822 foreach ( $metadata['sizes'] as $size ) { 780 823 unlink( $temp_dir . $size['file'] ); 781 824 } 825 remove_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 826 782 827 } 783 828 784 829 /** … … class Tests_Image_Functions extends WP_UnitTestCase { 789 834 $this->markTestSkipped( 'Rendering PDFs is not supported on this system.' ); 790 835 } 791 836 837 // Use legacy JPEG output. 838 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 839 792 840 $orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf'; 793 841 $test_file = get_temp_dir() . 'wordpress-gsoc-flyer.pdf'; 794 842 copy( $orig_file, $test_file ); … … class Tests_Image_Functions extends WP_UnitTestCase { 821 869 'height' => 100, 822 870 'mime-type' => 'image/jpeg', 823 871 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-77x100.jpg' ), 872 'sources' => array( 873 'image/jpeg' => array( 874 'file' => 'wordpress-gsoc-flyer-pdf-77x100.jpg', 875 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-77x100.jpg' ), 876 ), 877 ), 824 878 ); 825 879 826 880 // Different environments produce slightly different filesize results. … … class Tests_Image_Functions extends WP_UnitTestCase { 836 890 foreach ( $metadata['sizes'] as $size ) { 837 891 unlink( $temp_dir . $size['file'] ); 838 892 } 893 remove_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 839 894 } 840 895 841 896 public function filter_fallback_intermediate_image_sizes( $fallback_sizes, $metadata ) { … … class Tests_Image_Functions extends WP_UnitTestCase { 1026 1081 ), 1027 1082 ); 1028 1083 } 1084 1085 /** 1086 * @ticket 55443 1087 */ 1088 public function test_wp_upload_image_mime_transforms_generates_webp_and_jpeg_for_both_by_default() { 1089 $result = wp_upload_image_mime_transforms( 42, 'large' ); 1090 $this->assertArrayHasKey( 'image/jpeg', $result ); 1091 $this->assertArrayHasKey( 'image/webp', $result ); 1092 $this->assertSameSets( array( 'image/jpeg', 'image/webp' ), $result['image/jpeg'] ); 1093 $this->assertSameSets( array( 'image/jpeg', 'image/webp' ), $result['image/webp'] ); 1094 } 1095 1096 /** 1097 * @ticket 55443 1098 */ 1099 public function test_wp_upload_image_mime_transforms_filter_always_use_webp_instead_of_jpeg() { 1100 add_filter( 1101 'wp_upload_image_mime_transforms', 1102 function( $transforms ) { 1103 // Ensure JPG only results in WebP files. 1104 $transforms['image/jpeg'] = array( 'image/webp' ); 1105 // Unset WebP since it does not need any transformation in that case. 1106 unset( $transforms['image/webp'] ); 1107 return $transforms; 1108 } 1109 ); 1110 1111 $result = wp_upload_image_mime_transforms( 42, 'large' ); 1112 $this->assertArrayHasKey( 'image/jpeg', $result ); 1113 $this->assertArrayNotHasKey( 'image/webp', $result ); 1114 $this->assertSameSets( array( 'image/webp' ), $result['image/jpeg'] ); 1115 } 1116 1117 /** 1118 * @ticket 55443 1119 */ 1120 public function test_wp_upload_image_mime_transforms_filter_receives_parameters() { 1121 $attachment_id = null; 1122 $image_size = null; 1123 add_filter( 1124 'wp_upload_image_mime_transforms', 1125 function( $transforms, $param1, $param2 ) use ( &$attachment_id, &$image_size ) { 1126 $attachment_id = $param1; 1127 $image_size = $param2; 1128 return $transforms; 1129 }, 1130 10, 1131 3 1132 ); 1133 1134 wp_upload_image_mime_transforms( 23, 'medium' ); 1135 $this->assertSame( 23, $attachment_id ); 1136 $this->assertSame( 'medium', $image_size ); 1137 } 1138 1139 /** 1140 * @ticket 55443 1141 */ 1142 public function test_wp_upload_image_mime_transforms_filter_with_empty_array() { 1143 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 1144 $result = wp_upload_image_mime_transforms( 42, 'large' ); 1145 $this->assertSame( array(), $result ); 1146 } 1147 1148 /** 1149 * @ticket 55443 1150 */ 1151 public function test_wp_upload_image_mime_transforms_filter_with_invalid_usage() { 1152 $default = wp_upload_image_mime_transforms( 42, 'large' ); 1153 1154 add_filter( 'wp_upload_image_mime_transforms', '__return_false' ); 1155 $result = wp_upload_image_mime_transforms( 42, 'large' ); 1156 $this->assertSame( $default, $result ); 1157 } 1158 1159 /** 1160 * @ticket 55443 1161 */ 1162 public function test__wp_get_primary_and_additional_mime_types_default() { 1163 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1164 1165 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1166 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1167 1168 // WebP may not be supported by the server, in which case it will be stripped from the results. 1169 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1170 $this->assertSame( array( 'image/webp' ), $additional_mime_types ); 1171 } else { 1172 $this->assertSame( array(), $additional_mime_types ); 1173 } 1174 } 1175 1176 /** 1177 * @ticket 55443 1178 */ 1179 public function test__wp_get_primary_and_additional_mime_types_prefer_original_mime() { 1180 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1181 1182 // Set 'image/jpeg' only as secondary output MIME type. 1183 // Still, because it is the original, it should be chosen as primary over 'image/webp'. 1184 add_filter( 1185 'wp_upload_image_mime_transforms', 1186 function( $transforms ) { 1187 $transforms['image/jpeg'] = array( 'image/webp', 'image/jpeg' ); 1188 return $transforms; 1189 } 1190 ); 1191 1192 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1193 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1194 1195 // WebP may not be supported by the server, in which case it will be stripped from the results. 1196 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1197 $this->assertSame( array( 'image/webp' ), $additional_mime_types ); 1198 } else { 1199 $this->assertSame( array(), $additional_mime_types ); 1200 } 1201 } 1202 1203 /** 1204 * @ticket 55443 1205 */ 1206 public function test__wp_get_primary_and_additional_mime_types_use_original_mime_when_no_transformation_rules() { 1207 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1208 1209 // Strip all transformation rules. 1210 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 1211 1212 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1213 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1214 $this->assertSame( array(), $additional_mime_types ); 1215 } 1216 1217 /** 1218 * @ticket 55443 1219 */ 1220 public function test__wp_get_primary_and_additional_mime_types_different_output_mime() { 1221 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1222 1223 // Set 'image/webp' as the only output MIME type. 1224 // In that case, JPEG is not generated at all, so WebP becomes the primary MIME type. 1225 add_filter( 1226 'wp_upload_image_mime_transforms', 1227 function( $transforms ) { 1228 $transforms['image/jpeg'] = array( 'image/webp' ); 1229 return $transforms; 1230 } 1231 ); 1232 1233 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1234 1235 // WebP may not be supported by the server, in which case it will fall back to the original MIME type. 1236 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1237 $this->assertSame( 'image/webp', $primary_mime_type ); 1238 } else { 1239 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1240 } 1241 1242 $this->assertSame( array(), $additional_mime_types ); 1243 } 1244 1245 /** 1246 * @ticket 55443 1247 */ 1248 public function test__wp_get_primary_and_additional_mime_types_different_output_mimes() { 1249 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1250 1251 // Set 'image/webp' and 'image/avif' as output MIME types. 1252 // In that case, JPEG is not generated at all, with WebP being the primary MIME type and AVIF the secondary. 1253 add_filter( 1254 'wp_upload_image_mime_transforms', 1255 function( $transforms ) { 1256 $transforms['image/jpeg'] = array( 'image/webp', 'image/avif' ); 1257 return $transforms; 1258 } 1259 ); 1260 1261 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1262 1263 // WebP may not be supported by the server, in which case it will fall back to the original MIME type. 1264 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1265 $this->assertSame( 'image/webp', $primary_mime_type ); 1266 } else { 1267 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1268 } 1269 1270 // AVIF may not be supported by the server, in which case it will be stripped from the results. 1271 if ( wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) { 1272 $this->assertSame( array( 'image/avif' ), $additional_mime_types ); 1273 } else { 1274 $this->assertSame( array(), $additional_mime_types ); 1275 } 1276 } 1277 1278 /** 1279 * Test the `_wp_maybe_scale_and_rotate_image()` function. 1280 * 1281 * @dataProvider data_test__wp_maybe_scale_and_rotate_image 1282 * 1283 * @ticket 55443 1284 */ 1285 public function test__wp_maybe_scale_and_rotate_image( $file, $imagesize, $mime_type, $expected ) { 1286 if ( ! wp_image_editor_supports( array( 'mime_type' => $mime_type ) ) ) { 1287 $this->markTestSkipped( sprintf( 'This test requires %s support.', $mime_type ) ); 1288 } 1289 1290 $attributes = array( 'post_mime_type' => $mime_type ); 1291 $attachment_id = $this->factory->attachment->create_object( $file, 0, $attributes ); 1292 $exif_meta = wp_read_image_metadata( $file ); 1293 1294 list( $editor, $resized, $rotated ) = _wp_maybe_scale_and_rotate_image( $file, $attachment_id, $imagesize, $exif_meta, $mime_type ); 1295 if ( is_wp_error( $editor ) ) { 1296 $this->markTestSkipped( sprintf( 'Editor not supported for: %s.', $editor->get_error_data() ) ); 1297 } 1298 $this->assertSame( $expected['rotated'], $rotated ); 1299 $this->assertSame( $expected['resized'], $resized ); 1300 $this->assertSame( $expected['size'], $editor->get_size() ); 1301 } 1302 1303 /** 1304 * Data provider for the `test__wp_maybe_scale_and_rotate_image()` test. 1305 * 1306 * @return array 1307 */ 1308 public function data_test__wp_maybe_scale_and_rotate_image() { 1309 return array( 1310 1311 // Image that will be scaled. 1312 array( 1313 DIR_TESTDATA . '/images/test-image-large.jpg', 1314 array( 3000, 2250 ), 1315 'image/jpeg', 1316 array( 1317 'rotated' => false, 1318 'resized' => true, 1319 'size' => array( 1320 'width' => 2560, 1321 'height' => 1920, 1322 ), 1323 ), 1324 ), 1325 1326 // Image that will not be scaled. 1327 array( 1328 DIR_TESTDATA . '/images/canola.jpg', 1329 array( 640, 480 ), 1330 'image/jpeg', 1331 array( 1332 'rotated' => false, 1333 'resized' => false, 1334 'size' => array( 1335 'width' => 640, 1336 'height' => 480, 1337 ), 1338 ), 1339 ), 1340 1341 // Image that will be flipped. 1342 array( 1343 DIR_TESTDATA . '/images/test-image-upside-down.jpg', 1344 array( 600, 450 ), 1345 'image/jpeg', 1346 array( 1347 'rotated' => true, 1348 'resized' => false, 1349 'size' => array( 1350 'width' => 600, 1351 'height' => 450, 1352 ), 1353 ), 1354 ), 1355 1356 // Image that will be rotated. 1357 array( 1358 DIR_TESTDATA . '/images/test-image-rotated-90ccw.jpg', 1359 array( 1200, 1800 ), 1360 'image/jpeg', 1361 array( 1362 'rotated' => true, 1363 'resized' => false, 1364 'size' => array( 1365 'width' => 1800, 1366 'height' => 1200, 1367 ), 1368 ), 1369 ), 1370 1371 // Image that will not be rotated - WebP Exif is not supported in PHP. 1372 array( 1373 DIR_TESTDATA . '/images/test-image-rotated-90cw.webp', 1374 array( 1024, 768 ), 1375 'image/jpeg', 1376 array( 1377 'rotated' => false, 1378 'resized' => false, 1379 'size' => array( 1380 'width' => 1024, 1381 'height' => 768, 1382 ), 1383 ), 1384 ), 1385 1386 ); 1387 } 1388 1389 /** 1390 * Test the `_wp_get_image_suffix()` function. 1391 * @dataProvider data_test__wp_get_image_suffix 1392 * 1393 * @ticket 55443 1394 */ 1395 public function test__wp_get_image_suffix( $resized, $rotated, $expected ) { 1396 $this->assertSame( $expected, _wp_get_image_suffix( $resized, $rotated ) ); 1397 } 1398 1399 /** 1400 * Data provider for the `test__wp_get_image_suffix()` test. 1401 */ 1402 public function data_test__wp_get_image_suffix() { 1403 return array( 1404 array( false, false, '' ), 1405 array( true, false, 'scaled' ), 1406 array( false, true, 'rotated' ), 1407 array( true, true, 'scaled' ), 1408 ); 1409 } 1029 1410 } -
tests/phpunit/tests/media.php
diff --git tests/phpunit/tests/media.php tests/phpunit/tests/media.php index 0341170721..592b19e328 100644
EOF; 2251 2251 // Do not add width, height, and loading. 2252 2252 add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); 2253 2253 add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); 2254 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2254 2255 2255 2256 $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) ); 2256 2257 2257 2258 remove_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); 2258 2259 remove_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); 2260 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2261 2259 2262 } 2260 2263 2261 2264 /** … … EOF; 2289 2292 $img = wp_img_tag_add_loading_attr( $img, 'test' ); 2290 2293 $img = wp_img_tag_add_decoding_attr( $img, 'the_content' ); 2291 2294 $img = preg_replace( '|<img ([^>]+) />|', '<img $1 ' . 'srcset="image2x.jpg 2x" />', $img ); 2295 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2292 2296 2293 2297 // The content filter should return the image unchanged. 2294 2298 $this->assertSame( $img, wp_filter_content_tags( $img ) ); 2299 2300 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2295 2301 } 2296 2302 2297 2303 /** … … EOF; 2361 2367 add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); 2362 2368 add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 2363 2369 add_filter( 'wp_img_tag_add_decoding_attr', '__return_false' ); 2370 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2364 2371 2365 2372 add_filter( 2366 2373 'wp_content_img_tag', … … EOF; 2423 2430 * @requires function imagejpeg 2424 2431 */ 2425 2432 public function test_wp_filter_content_tags_schemes() { 2433 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2426 2434 $image_meta = wp_get_attachment_metadata( self::$large_id ); 2427 2435 $size_array = $this->get_image_size_array_from_meta( $image_meta, 'medium' ); 2428 2436 … … EOF; 2468 2476 $actual = wp_filter_content_tags( $unfiltered ); 2469 2477 2470 2478 $this->assertSame( $expected, $actual ); 2479 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2471 2480 } 2472 2481 2473 2482 /** … … EOF; 2961 2970 // Do not add loading, srcset, and sizes. 2962 2971 add_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); 2963 2972 add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 2973 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2964 2974 2965 2975 $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) ); 2966 2976 2967 2977 remove_filter( 'wp_img_tag_add_loading_attr', '__return_false' ); 2968 2978 remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 2979 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2969 2980 } 2970 2981 2971 2982 /** … … EOF; 3041 3052 // Do not add width, height, srcset, and sizes. 3042 3053 add_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); 3043 3054 add_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 3055 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3044 3056 3045 3057 $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) ); 3046 3058 3047 3059 remove_filter( 'wp_img_tag_add_width_and_height_attr', '__return_false' ); 3048 3060 remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 3061 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3049 3062 } 3050 3063 3051 3064 /** … … EOF; 3074 3087 // Enable globally for all tags. 3075 3088 add_filter( 'wp_lazy_loading_enabled', '__return_true' ); 3076 3089 3090 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3091 3077 3092 $this->assertSame( $content_filtered, wp_filter_content_tags( $content_unfiltered ) ); 3078 3093 remove_filter( 'wp_lazy_loading_enabled', '__return_true' ); 3079 3094 remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 3095 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3096 3080 3097 } 3081 3098 3082 3099 /** … … EOF; 3101 3118 // Disable globally for all tags. 3102 3119 add_filter( 'wp_lazy_loading_enabled', '__return_false' ); 3103 3120 3121 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3122 3104 3123 $this->assertSame( $content, wp_filter_content_tags( $content ) ); 3105 3124 remove_filter( 'wp_lazy_loading_enabled', '__return_false' ); 3106 3125 remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 3126 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3107 3127 } 3108 3128 3109 3129 /** … … EOF; 3529 3549 */ 3530 3550 function test_wp_filter_content_tags_with_wp_get_loading_attr_default() { 3531 3551 global $wp_query, $wp_the_query; 3552 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3532 3553 3533 3554 $img1 = get_image_tag( self::$large_id, '', '', '', 'large' ); 3534 3555 $iframe1 = '<iframe src="https://www.example.com" width="640" height="360"></iframe>'; … … EOF; 3564 3585 $content_filtered = wp_filter_content_tags( $content_unfiltered, 'the_content' ); 3565 3586 remove_filter( 'wp_img_tag_add_srcset_and_sizes_attr', '__return_false' ); 3566 3587 } 3588 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3567 3589 3568 3590 // After filtering, the first image should not be lazy-loaded while the other ones should be. 3569 3591 $this->assertSame( $content_expected, $content_filtered ); … … EOF; 3613 3635 // Clean up the above filter. 3614 3636 remove_filter( 'wp_omit_loading_attr_threshold', '__return_null', 100 ); 3615 3637 } 3638 3639 /** 3640 * @ticket 55443 3641 */ 3642 public function test_wp_image_use_alternate_mime_types_replaces_jpg_with_webp_where_available() { 3643 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 3644 $this->markTestSkipped( 'This test requires WebP support.' ); 3645 } 3646 3647 // The attachment $large_id is a JPEG image, so it gets WebP files generated by default. 3648 $tag = wp_get_attachment_image( self::$large_id, 'full' ); 3649 $expected_tag = $tag; 3650 3651 $metadata = wp_get_attachment_metadata( self::$large_id ); 3652 foreach ( $metadata['sizes'] as $size => $properties ) { 3653 // Some sizes may not have WebP if the WebP file is larger than the JPEG for the size. 3654 if ( ! isset( $properties['sources']['image/webp'] ) ) { 3655 continue; 3656 } 3657 $expected_tag = str_replace( $properties['sources']['image/jpeg']['file'], $properties['sources']['image/webp']['file'], $expected_tag ); 3658 } 3659 // Same applies to the full size. 3660 if ( isset( $metadata['sources']['image/webp'] ) ) { 3661 $expected_tag = str_replace( $metadata['sources']['image/jpeg']['file'], $metadata['sources']['image/webp']['file'], $expected_tag ); 3662 } 3663 3664 $this->assertNotSame( $tag, $expected_tag ); 3665 $this->assertSame( $expected_tag, wp_image_use_alternate_mime_types( $tag, 'the_content', self::$large_id ) ); 3666 } 3667 3668 /** 3669 * @ticket 55443 3670 */ 3671 public function test_wp_image_use_alternate_mime_types_does_not_replace_jpg_when_webp_is_not_available() { 3672 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 3673 $this->markTestSkipped( 'This test requires WebP support.' ); 3674 } 3675 3676 // The attachment $large_id is a JPEG image, so it gets WebP files generated by default. 3677 $tag = wp_get_attachment_image( self::$large_id, 'full' ); 3678 3679 // Update attachment metadata as if the image had no WebP available for any sub-sizes and the full size. 3680 $metadata = wp_get_attachment_metadata( self::$large_id ); 3681 foreach ( $metadata['sizes'] as $size => $properties ) { 3682 unset( $metadata['sizes'][ $size ]['sources']['image/webp'] ); 3683 } 3684 unset( $metadata['sources']['image/webp'] ); 3685 wp_update_attachment_metadata( self::$large_id, $metadata ); 3686 3687 $this->assertSame( $tag, wp_image_use_alternate_mime_types( $tag, 'the_content', self::$large_id ) ); 3688 } 3689 3690 /** 3691 * @ticket 55443 3692 */ 3693 public function test_wp_image_use_alternate_mime_types_still_replaces_jpg_subsizes_when_webp_is_not_available_for_full_size() { 3694 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 3695 $this->markTestSkipped( 'This test requires WebP support.' ); 3696 } 3697 3698 // The attachment $large_id is a JPEG image, so it gets WebP files generated by default. 3699 $tag = wp_get_attachment_image( self::$large_id, 'full' ); 3700 $expected_tag = $tag; 3701 3702 // Update attachment metadata as if the image had no WebP available for the full size. 3703 $metadata = wp_get_attachment_metadata( self::$large_id ); 3704 unset( $metadata['sources']['image/webp'] ); 3705 wp_update_attachment_metadata( self::$large_id, $metadata ); 3706 3707 foreach ( $metadata['sizes'] as $size => $properties ) { 3708 // Some sizes may not have WebP if the WebP file is larger than the JPEG for the size. 3709 if ( ! isset( $properties['sources']['image/webp'] ) ) { 3710 continue; 3711 } 3712 $expected_tag = str_replace( $properties['sources']['image/jpeg']['file'], $properties['sources']['image/webp']['file'], $expected_tag ); 3713 } 3714 3715 $this->assertNotSame( $tag, $expected_tag ); 3716 $this->assertSame( $expected_tag, wp_image_use_alternate_mime_types( $tag, 'the_content', self::$large_id ) ); 3717 } 3718 3719 /** 3720 * @ticket 55443 3721 */ 3722 public function test_wp_image_use_alternate_mime_types_respects_wp_content_image_mimes_filter() { 3723 if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 3724 $this->markTestSkipped( 'This test requires WebP support.' ); 3725 } 3726 3727 // The attachment $large_id is a JPEG image, so it gets WebP files generated by default. 3728 $tag = wp_get_attachment_image( self::$large_id, 'full' ); 3729 3730 // Invalid filter value results in no changes to content. 3731 add_filter( 'wp_content_image_mimes', '__return_false' ); 3732 $this->assertSame( $tag, wp_image_use_alternate_mime_types( $tag, 'the_content', self::$large_id ) ); 3733 3734 // Empty array results in no changes to content. 3735 add_filter( 'wp_content_image_mimes', '__return_empty_array' ); 3736 $this->assertSame( $tag, wp_image_use_alternate_mime_types( $tag, 'the_content', self::$large_id ) ); 3737 3738 // Preferring JPEG over WebP results in no changes to content. 3739 add_filter( 3740 'wp_content_image_mimes', 3741 function() { 3742 return array( 'image/jpeg', 'image/webp' ); 3743 } 3744 ); 3745 $this->assertSame( $tag, wp_image_use_alternate_mime_types( $tag, 'the_content', self::$large_id ) ); 3746 } 3747 3748 /** 3749 * @ticket 55443 3750 */ 3751 public function test__wp_in_front_end_context_without_wp_query() { 3752 unset( $GLOBALS['wp_query'] ); 3753 3754 $this->assertFalse( _wp_in_front_end_context() ); 3755 } 3756 3757 /** 3758 * @ticket 55443 3759 */ 3760 public function test__wp_in_front_end_context_with_feed() { 3761 remove_all_actions( 'template_redirect' ); 3762 do_action( 'template_redirect' ); 3763 $GLOBALS['wp_query']->is_feed = true; 3764 3765 $this->assertFalse( _wp_in_front_end_context() ); 3766 } 3767 3768 /** 3769 * @ticket 55443 3770 */ 3771 public function test__wp_in_front_end_context_before_and_after_template_redirect() { 3772 $result = _wp_in_front_end_context(); 3773 3774 remove_all_actions( 'template_redirect' ); 3775 do_action( 'template_redirect' ); 3776 3777 $this->assertFalse( $result ); 3778 $this->assertTrue( _wp_in_front_end_context() ); 3779 } 3780 3781 /** 3782 * @ticket 55443 3783 */ 3784 public function test__wp_in_front_end_context_within_wp_head() { 3785 remove_all_actions( 'template_redirect' ); 3786 do_action( 'template_redirect' ); 3787 3788 // Call function within a 'wp_head' callback. 3789 remove_all_actions( 'wp_head' ); 3790 $result = null; 3791 add_action( 3792 'wp_head', 3793 function() use ( &$result ) { 3794 $result = _wp_in_front_end_context(); 3795 } 3796 ); 3797 do_action( 'wp_head' ); 3798 3799 $this->assertFalse( $result ); 3800 } 3616 3801 } 3617 3802 3618 3803 /**