Changeset 53751
- Timestamp:
- 07/21/2022 06:01:01 PM (2 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/js/_enqueues/vendor/plupload/handlers.js
r51947 r53751 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, -
trunk/src/js/_enqueues/vendor/plupload/wp-plupload.js
r51227 r53751 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, -
trunk/src/wp-admin/includes/image.php
r53547 r53751 78 78 * 79 79 * @since 5.3.0 80 * 81 * @param int $attachment_id The image attachment post ID. 80 * @since 6.1.0 The $mime_type parameter was added. 81 * 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(); 90 } 91 92 $primary_mime_type = get_post_mime_type( get_post( $attachment_id ) ); 93 if ( ! $mime_type ) { 94 $mime_type = $primary_mime_type; 88 95 } 89 96 … … 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 /** … … 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 … … 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 … … 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. … … 168 195 } 169 196 } else { 170 $missing_sizes = wp_get_missing_image_subsizes( $attachment_id ); 171 172 if ( empty( $missing_sizes ) ) { 173 return $image_meta; 174 } 175 176 // This also updates the image meta. 177 $image_meta = _wp_make_subsizes( $missing_sizes, $image_file, $image_meta, $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 ); 199 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 } 210 } 211 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 … … 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 … … 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. … … 249 296 'filesize' => wp_filesize( $file ), 250 297 'sizes' => array(), 298 'sources' => array(), 251 299 ); 252 300 … … 258 306 } 259 307 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 ); 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_output_mime_type( $mime_type ); 410 } 411 260 412 // 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'] ) { 262 413 if ( 'image/png' !== $mime_type ) { 263 414 /** 264 415 * Filters the "BIG image" threshold value. … … 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 } 353 } 354 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 ); 361 362 $new_sizes = wp_get_registered_image_subsizes(); 363 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 ); 376 377 return _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ); 450 } 451 } 452 453 return array( $editor, $resized, $rotated ); 454 } 455 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 } 472 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 } 483 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 … … 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(); 521 } 522 523 if ( ! $mime_type ) { 524 $mime_type = wp_get_image_mime( $file ); 399 525 } 400 526 … … 408 534 */ 409 535 if ( array_key_exists( $size_name, $new_sizes ) ) { 410 unset( $new_sizes[ $size_name ] ); 536 // Unset the size if it is either the required mime type already exists either as main mime type or 537 // within sources. 538 if ( $size_meta['mime-type'] === $mime_type || isset( $size_meta['sources'][ $mime_type ] ) ) { 539 unset( $new_sizes[ $size_name ] ); 540 } 411 541 } 412 542 } … … 434 564 $new_sizes = array_filter( array_merge( $priority, $new_sizes ) ); 435 565 436 $editor = wp_get_image_editor( $file );566 $editor = wp_get_image_editor( $file, array( 'mime_type' => $mime_type ) ); 437 567 438 568 if ( is_wp_error( $editor ) ) { … … 440 570 return $image_meta; 441 571 } 572 573 $editor->set_output_mime_type( $mime_type ); 442 574 443 575 // If stored EXIF data exists, rotate the source image before creating sub-sizes. … … 458 590 } else { 459 591 // Save the size meta value. 460 $image_meta['sizes'][ $new_size_name ] = $new_size_meta; 592 if ( ! isset( $image_meta['sizes'][ $new_size_name ] ) ) { 593 $image_meta['sizes'][ $new_size_name ] = $new_size_meta; 594 } else { 595 // Remove any newly generated images that are larger than the primary mime type. 596 $new_size = isset( $new_size_meta['filesize'] ) ? $new_size_meta['filesize'] : 0; 597 $primary_size = isset( $image_meta['sizes'][ $new_size_name ]['filesize'] ) ? $image_meta['sizes'][ $new_size_name ]['filesize'] : 0; 598 599 if ( $new_size && $primary_size && $new_size >= $primary_size ) { 600 wp_delete_file( dirname( $file ) . '/' . $new_size_meta['file'] ); 601 continue; 602 } 603 } 604 if ( ! isset( $image_meta['sizes'][ $new_size_name ]['sources'] ) ) { 605 $image_meta['sizes'][ $new_size_name ]['sources'] = array(); 606 } 607 $image_meta['sizes'][ $new_size_name ]['sources'][ $mime_type ] = _wp_get_sources_from_meta( $new_size_meta ); 461 608 wp_update_attachment_metadata( $attachment_id, $image_meta ); 462 609 } … … 467 614 468 615 if ( ! empty( $created_sizes ) ) { 469 $image_meta['sizes'] = array_merge( $image_meta['sizes'], $created_sizes ); 616 foreach ( $created_sizes as $created_size_name => $created_size_meta ) { 617 618 // Primary mime type is set in 'sizes' array. 619 if ( ! isset( $image_meta['sizes'][ $created_size_name ] ) ) { 620 $image_meta['sizes'][ $created_size_name ] = $created_size_meta; 621 } else { 622 // Remove any newly generated images that are larger than the primary mime type. 623 $new_size = isset( $created_size_meta['filesize'] ) ? $created_size_meta['filesize'] : 0; 624 $primary_size = isset( $image_meta['sizes'][ $created_size_name ]['filesize'] ) ? $image_meta['sizes'][ $created_size_name ]['filesize'] : 0; 625 626 if ( $new_size && $primary_size && $new_size >= $primary_size ) { 627 wp_delete_file( dirname( $file ) . '/' . $created_size_meta['file'] ); 628 continue; 629 } 630 } 631 if ( ! isset( $image_meta['sizes'][ $created_size_name ]['sources'] ) ) { 632 $image_meta['sizes'][ $created_size_name ]['sources'] = array(); 633 } 634 $image_meta['sizes'][ $created_size_name ]['sources'][ $mime_type ] = _wp_get_sources_from_meta( $new_size_meta ); 635 } 470 636 wp_update_attachment_metadata( $attachment_id, $image_meta ); 471 637 } … … 473 639 474 640 return $image_meta; 641 } 642 643 /** 644 * Filters the list of image size objects that support secondary mime type output. 645 * 646 * @since 6.1.0 647 * 648 * @param array $sizes Associative array of image sizes. 649 * @param int $attachment_id Attachment ID. 650 * @return array $sizes Filtered $sizes with only those that support secondary mime type output. 651 */ 652 function _wp_filter_image_sizes_additional_mime_type_support( $sizes, $attachment_id ) { 653 654 // Include only the core sizes that do not rely on add_image_size(). Additional image sizes are opt-in. 655 $enabled_sizes = array( 656 'thumbnail' => true, 657 'medium' => true, 658 'medium_large' => true, 659 'large' => true, 660 'post-thumbnail' => true, 661 ); 662 663 /** 664 * Filter the sizes that support secondary mime type output. Developers can use this 665 * to control the output of additional mime type sub-sized images. 666 * 667 * @since 6.1.0 668 * 669 * @param array $enabled_sizes Map of size names and whether they support secondary mime type output. 670 * @param int $attachment_id Attachment ID. 671 */ 672 $enabled_sizes = apply_filters( 'wp_image_sizes_with_additional_mime_type_support', $enabled_sizes, $attachment_id ); 673 674 // Filter supported sizes to only include enabled sizes. 675 return array_intersect_key( $sizes, array_filter( $enabled_sizes ) ); 676 } 677 678 /** 679 * Low-level function to create full-size images in additional mime types. 680 * 681 * Updates the image meta after each mime type image is created. 682 * 683 * @since 6.1.0 684 * @access private 685 * 686 * @param array $new_mime_types Array defining what mime types to create. 687 * @param string $file Full path to the image file. 688 * @param array $image_meta The attachment meta data array. 689 * @param int $attachment_id Attachment ID to process. 690 * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing. 691 */ 692 function _wp_make_additional_mime_types( $new_mime_types, $file, $image_meta, $attachment_id ) { 693 $imagesize = array( 694 $image_meta['width'], 695 $image_meta['height'], 696 ); 697 $exif_meta = isset( $image_meta['image_meta'] ) ? $image_meta['image_meta'] : null; 698 $original_file_size = isset( $image_meta['filesize'] ) ? $image_meta['filesize'] : wp_filesize( $file ); 699 700 foreach ( $new_mime_types as $mime_type ) { 701 list( $editor, $resized, $rotated ) = _wp_maybe_scale_and_rotate_image( $file, $attachment_id, $imagesize, $exif_meta, $mime_type ); 702 if ( is_wp_error( $editor ) ) { 703 // The image cannot be edited. 704 continue; 705 } 706 707 $suffix = _wp_get_image_suffix( $resized, $rotated ); 708 $extension = wp_get_default_extension_for_mime_type( $mime_type ); 709 710 $saved = $editor->save( $editor->generate_filename( $suffix, null, $extension ) ); 711 712 if ( is_wp_error( $saved ) ) { 713 // TODO: Log errors. 714 } else { 715 // If the saved image is larger than the original, discard it. 716 $filesize = isset( $saved['filesize'] ) ? $saved['filesize'] : wp_filesize( $saved['path'] ); 717 if ( $filesize && $original_file_size && $filesize > $original_file_size ) { 718 wp_delete_file( $saved['path'] ); 719 continue; 720 } 721 $image_meta['sources'][ $mime_type ] = _wp_get_sources_from_meta( $saved ); 722 wp_update_attachment_metadata( $attachment_id, $image_meta ); 723 } 724 } 725 726 return $image_meta; 727 } 728 729 730 /** 731 * Check if an image belongs to an attachment. 732 * 733 * @since 6.1.0 734 * @access private 735 * 736 * @param string $filename Full path to the image file. 737 * @param int $attachment_id Attachment ID to check. 738 * @return bool True if the image belongs to the attachment, false otherwise. 739 */ 740 function _wp_image_belongs_to_attachment( $filename, $attachment_id ) { 741 $meta_data = wp_get_attachment_metadata( $attachment_id ); 742 743 if ( ! isset( $image_meta['sizes'] ) ) { 744 return false; 745 } 746 $sizes = $image_meta['sizes']; 747 foreach ( $sizes as $size ) { 748 if ( $size['file'] === $filename ) { 749 return true; 750 } 751 if ( isset( $size['sources'] ) && is_array( $size['sources'] ) ) { 752 foreach ( $size['sources'] as $source ) { 753 if ( $source['file'] === $filename ) { 754 return true; 755 } 756 } 757 } 758 } 759 return false; 475 760 } 476 761 … … 631 916 632 917 // Create sub-sizes saving the image meta after each. 633 $metadata = _wp_make_subsizes( $merged_sizes, $image_file, $metadata, $attachment_id );918 $metadata = _wp_make_subsizes( $merged_sizes, $image_file, $metadata, $attachment_id, '' ); 634 919 } 635 920 } … … 1158 1443 return $dst_file; 1159 1444 } 1445 1446 /** 1447 * Returns an array with the list of valid mime types that a specific mime type should be converted into. 1448 * For example an `image/jpeg` should be converted into an `image/jpeg` and `image/webp`. The first type 1449 * is considered the primary output type for this image. 1450 * 1451 * Called for each uploaded image to determine the list of mime types that should be converted into. Then, 1452 * called again for each image size as they are generated to check if the image should be converted into the mime type 1453 * for that size. 1454 * 1455 * @since 6.1.0 1456 * 1457 * @param int $attachment_id The attachment ID. 1458 * @return array An array of valid mime types, where the key is the source file mime type and the list of mime types to 1459 * generate. 1460 */ 1461 function wp_upload_image_mime_transforms( $attachment_id ) { 1462 $default_image_mime_transforms = array( 1463 'image/jpeg' => array( 'image/jpeg', 'image/webp' ), 1464 'image/webp' => array( 'image/webp', 'image/jpeg' ), 1465 ); 1466 $image_mime_transforms = $default_image_mime_transforms; 1467 1468 /** 1469 * Filter the output mime types for a given input mime type and image size. 1470 * 1471 * @since 6.1.0 1472 * 1473 * @param array $image_mime_transforms A map with the valid mime transforms where the key is the source file mime type 1474 * and the value is one or more mime file types to generate. 1475 * @param int $attachment_id The ID of the attachment where the hook was dispatched. 1476 */ 1477 $image_mime_transforms = apply_filters( 'wp_upload_image_mime_transforms', $image_mime_transforms, $attachment_id ); 1478 1479 if ( ! is_array( $image_mime_transforms ) ) { 1480 return $default_image_mime_transforms; 1481 } 1482 1483 return array_map( 1484 function( $transforms_list ) { 1485 return (array) $transforms_list; 1486 }, 1487 $image_mime_transforms 1488 ); 1489 } 1490 1491 /** 1492 * Extract the primary and additional mime output types for an image from the $image_mime_transforms. 1493 * 1494 * @since 6.1.0 1495 * @access private 1496 * 1497 * @param string $file Full path to the image file. 1498 * @param int $attachment_id Attachment ID to process. 1499 * @return array An array with two entries, the primary mime type and the list of additional mime types. 1500 */ 1501 function _wp_get_primary_and_additional_mime_types( $file, $attachment_id ) { 1502 $image_mime_transforms = wp_upload_image_mime_transforms( $attachment_id ); 1503 $original_mime_type = wp_get_image_mime( $file ); 1504 $output_mime_types = isset( $image_mime_transforms[ $original_mime_type ] ) ? $image_mime_transforms[ $original_mime_type ] : array( $original_mime_type ); 1505 1506 // Exclude any output mime types that the system doesn't support. 1507 $output_mime_types = array_values( 1508 array_filter( 1509 $output_mime_types, 1510 function( $mime_type ) { 1511 return wp_image_editor_supports( 1512 array( 1513 'mime_type' => $mime_type, 1514 ) 1515 ); 1516 } 1517 ) 1518 ); 1519 1520 // Handle an empty value for $output_mime_types: only output the original type. 1521 if ( empty( $output_mime_types ) ) { 1522 return array( $original_mime_type, array() ); 1523 } 1524 1525 // Use original mime type as primary mime type, or alternatively the first one. 1526 $primary_mime_type_key = array_search( $original_mime_type, $output_mime_types, true ); 1527 if ( false === $primary_mime_type_key ) { 1528 $primary_mime_type_key = 0; 1529 } 1530 // Split output mime types into primary mime type and additional mime types. 1531 $additional_mime_types = $output_mime_types; 1532 list( $primary_mime_type ) = array_splice( $additional_mime_types, $primary_mime_type_key, 1 ); 1533 1534 return array( 1535 $primary_mime_type, 1536 $additional_mime_types, 1537 ); 1538 } -
trunk/src/wp-includes/class-wp-image-editor.php
r53547 r53751 334 334 protected function get_output_format( $filename = null, $mime_type = null ) { 335 335 $new_ext = null; 336 337 // If no mime type is passed but output mime type is set, use that. 338 if ( ! $mime_type && ! empty( $this->output_mime_type ) ) { 339 $mime_type = $this->output_mime_type; 340 } 336 341 337 342 // By default, assume specified type takes priority. … … 426 431 427 432 /** 428 * Builds an output filename based on current file, and adding proper suffix 429 * 430 * @since 3.5.0 431 * 432 * @param string $suffix 433 * @param string $dest_path 434 * @param string $extension 435 * @return string filename 433 * Builds an output filename based on current file, and adding proper suffix. 434 * 435 * @since 3.5.0 436 * @since 6.1.0 Skips adding a suffix when set to an empty string. When the 437 * file extension being generated doesn't match the image file extension, 438 * add the extension to the suffix 439 * 440 * @param string $suffix Optional. Suffix to add to the filename. The default null 441 * will result in a 'widthxheight' suffix. Passing 442 * an empty string will result in no suffix. 443 * @param string $dest_path Optional. The path to save the file to. The default null 444 * will use the image file path. 445 * @param string $extension Optional. The file extension to use. The default null 446 * will use the image file extension. 447 * @return string filename The generated file name. 436 448 */ 437 449 public function generate_filename( $suffix = null, $dest_path = null, $extension = null ) { 438 450 // $suffix will be appended to the destination filename, just before the extension. 439 if ( !$suffix ) {451 if ( null === $suffix ) { 440 452 $suffix = $this->get_suffix(); 441 453 } … … 458 470 } 459 471 460 return trailingslashit( $dir ) . "{$name}-{$suffix}.{$new_ext}"; 472 if ( empty( $suffix ) ) { 473 $suffix = ''; 474 } else { 475 $suffix = "-{$suffix}"; 476 } 477 478 // When the file extension being generated doesn't match the image file extension, 479 // add the extension to the suffix to ensure a unique file name. Prevents 480 // name conflicts when a single image type can have multiple extensions, 481 // eg. .jpg, .jpeg and .jpe are all valid JPEG extensions. 482 if ( ! empty( $extension ) && $extension !== $ext ) { 483 $suffix .= "-{$ext}"; 484 } 485 486 return trailingslashit( $dir ) . "{$name}{$suffix}.{$new_ext}"; 461 487 } 462 488 … … 638 664 return wp_get_default_extension_for_mime_type( $mime_type ); 639 665 } 666 667 /** 668 * Set the editor output mime type, useful when outputting alternate mime types. 669 * 670 * Track that the mime type is set with the mime type set flag. 671 * 672 * @since 6.1.0 673 * 674 * @param string $output_mime_type The mime type to set. 675 */ 676 public function set_output_mime_type( $output_mime_type ) { 677 $this->output_mime_type = $output_mime_type; 678 } 679 680 /** 681 * Reset the mime type to the original file mime type. 682 * 683 * Reset the mime type set flag. 684 * 685 * @since 6.1.0 686 */ 687 public function reset_output_mime_type() { 688 $this->output_mime_type = $this->mime_type; 689 } 640 690 } 641 -
trunk/src/wp-includes/media.php
r53715 r53751 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. … … 1897 1902 1898 1903 return $content; 1904 } 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' ); 1899 2015 } 1900 2016 -
trunk/src/wp-includes/post.php
r53723 r53751 6482 6482 6483 6483 foreach ( $meta['sizes'] as $size => $sizeinfo ) { 6484 $intermediate_file = str_replace( wp_basename( $file ), $sizeinfo['file'], $file ); 6485 6486 if ( ! empty( $intermediate_file ) ) { 6487 $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); 6488 6489 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6490 $deleted = false; 6484 6485 // Check for alternate size mime types in the sizeinfo['sources'] array to delete. 6486 if ( isset( $sizeinfo['sources'] ) && is_array( $sizeinfo['sources'] ) ) { 6487 foreach ( $sizeinfo['sources'] as $mime => $properties ) { 6488 $intermediate_file = str_replace( wp_basename( $file ), $properties['file'], $file ); 6489 if ( ! empty( $intermediate_file ) ) { 6490 $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); 6491 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6492 $deleted = false; 6493 } 6494 } 6495 } 6496 } else { 6497 // Otherwise, delete files from the sizeinfo data. 6498 $intermediate_file = str_replace( wp_basename( $file ), $sizeinfo['file'], $file ); 6499 6500 if ( ! empty( $intermediate_file ) ) { 6501 $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); 6502 6503 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6504 $deleted = false; 6505 } 6491 6506 } 6492 6507 } … … 6510 6525 } 6511 6526 6527 // Delete the full size images from 'sources' if available, or the root file. 6528 if ( isset( $meta['sources'] ) && is_array( $meta['sources'] ) ) { 6529 $sources = $meta['sources']; 6530 $intermediate_dir = path_join( $uploadpath['basedir'], dirname( $file ) ); 6531 foreach ( $sources as $mime => $properties ) { 6532 if ( ! is_array( $properties ) || empty( $properties['file'] ) ) { 6533 continue; 6534 } 6535 $intermediate_file = str_replace( wp_basename( $file ), $properties['file'], $file ); 6536 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6537 $deleted = false; 6538 } 6539 } 6540 } else { 6541 if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) { 6542 $deleted = false; 6543 } 6544 } 6545 6512 6546 if ( is_array( $backup_sizes ) ) { 6547 6513 6548 $del_dir = path_join( $uploadpath['basedir'], dirname( $meta['file'] ) ); 6514 6549 // Delete the root (edited) file which was not deleted above. 6550 if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) { 6551 $deleted = false; 6552 } 6515 6553 foreach ( $backup_sizes as $size ) { 6516 $del_file = path_join( dirname( $meta['file'] ), $size['file'] ); 6517 6518 if ( ! empty( $del_file ) ) { 6519 $del_file = path_join( $uploadpath['basedir'], $del_file ); 6520 6521 if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { 6522 $deleted = false; 6554 // Delete files from 'sources' data if available, otherwise from 'sizes' data. 6555 if ( isset( $meta['sources'] ) && is_array( $meta['sources'] ) ) { 6556 // Delete any backup images stored in the 'sources' array. 6557 if ( isset( $size['sources'] ) && is_array( $size['sources'] ) ) { 6558 foreach ( $size['sources'] as $mime => $properties ) { 6559 $del_file = path_join( dirname( $meta['file'] ), $properties['file'] ); 6560 if ( ! empty( $del_file ) ) { 6561 $del_file = path_join( $uploadpath['basedir'], $del_file ); 6562 if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { 6563 $deleted = false; 6564 } 6565 } 6566 } 6567 } 6568 } else { 6569 $del_file = path_join( dirname( $meta['file'] ), $size['file'] ); 6570 6571 if ( ! empty( $del_file ) ) { 6572 $del_file = path_join( $uploadpath['basedir'], $del_file ); 6573 if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { 6574 $deleted = false; 6575 } 6523 6576 } 6524 6577 } 6525 6578 } 6526 }6527 6528 if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) {6529 $deleted = false;6530 6579 } 6531 6580 -
trunk/tests/phpunit/tests/image/editor.php
r52248 r53751 132 132 133 133 // Removing PNG to WEBP conversion on save. Quality setting should reset to the default. 134 $editor->reset_output_mime_type(); 134 135 remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_formats' ) ); 135 136 $editor->save(); … … 155 156 156 157 // After removing the conversion the quality setting should reset to the filtered value for the original image type, JPEG. 158 $editor->reset_output_mime_type(); 157 159 remove_filter( 'image_editor_output_format', array( $this, 'image_editor_output_formats' ) ); 158 160 $editor->save(); … … 227 229 228 230 // Test with a suffix only. 229 $this->assertSame( 'canola-100x50 .png', wp_basename( $editor->generate_filename( null, null, 'png' ) ) );231 $this->assertSame( 'canola-100x50-jpg.png', wp_basename( $editor->generate_filename( null, null, 'png' ) ) ); 230 232 231 233 // Combo! 232 $this->assertSame( trailingslashit( realpath( get_temp_dir() ) ) . 'canola-new .png', $editor->generate_filename( 'new', realpath( get_temp_dir() ), 'png' ) );234 $this->assertSame( trailingslashit( realpath( get_temp_dir() ) ) . 'canola-new-jpg.png', $editor->generate_filename( 'new', realpath( get_temp_dir() ), 'png' ) ); 233 235 234 236 // Test with a stream destination. … … 363 365 } 364 366 367 /** 368 * Test creating the original image mime type when the image is uploaded. 369 * 370 * @ticket 55443 371 * 372 * @dataProvider provider_image_with_default_behaviors_during_upload 373 */ 374 public function it_should_create_the_original_image_mime_type_when_the_image_is_uploaded( $file_location, $expected_mime, $targeted_mime ) { 375 $attachment_id = $this->factory->attachment->create_upload_object( $file_location ); 376 377 $metadata = wp_get_attachment_metadata( $attachment_id ); 378 379 $this->assertIsArray( $metadata ); 380 foreach ( $metadata['sizes'] as $size_name => $properties ) { 381 $this->assertArrayHasKey( 'sources', $properties ); 382 $this->assertIsArray( $properties['sources'] ); 383 $this->assertArrayHasKey( $expected_mime, $properties['sources'] ); 384 $this->assertArrayHasKey( 'filesize', $properties['sources'][ $expected_mime ] ); 385 $this->assertArrayHasKey( 'file', $properties['sources'][ $expected_mime ] ); 386 $this->assertArrayHasKey( $targeted_mime, $properties['sources'] ); 387 $this->assertArrayHasKey( 'filesize', $properties['sources'][ $targeted_mime ] ); 388 $this->assertArrayHasKey( 'file', $properties['sources'][ $targeted_mime ] ); 389 } 390 } 391 392 /** 393 * Data provider for it_should_create_the_original_image_mime_type_when_the_image_is_uploaded. 394 */ 395 public function provider_image_with_default_behaviors_during_upload() { 396 yield 'JPEG image' => array( 397 DIR_TESTDATA . '/images/test-image.jpg', 398 'image/jpeg', 399 'image/webp', 400 ); 401 402 yield 'WebP image' => array( 403 DIR_TESTDATA . '/images/webp-lossy.webp', 404 'image/webp', 405 'image/jpeg', 406 ); 407 } 408 409 /** 410 * Test Do not create the sources property if no transform is provided. 411 * 412 * @ticket 55443 413 */ 414 public function it_should_not_create_the_sources_property_if_no_transform_is_provided() { 415 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 416 417 $attachment_id = $this->factory->attachment->create_upload_object( 418 DIR_TESTDATA . '/images/test-image.jpg' 419 ); 420 421 $metadata = wp_get_attachment_metadata( $attachment_id ); 422 423 $this->assertIsArray( $metadata ); 424 foreach ( $metadata['sizes'] as $size_name => $properties ) { 425 $this->assertArrayNotHasKey( 'sources', $properties ); 426 } 427 } 428 429 /** 430 * Test creating the sources property when no transform is available. 431 * 432 * @ticket 55443 433 */ 434 public function it_should_create_the_sources_property_when_no_transform_is_available() { 435 add_filter( 436 'wp_upload_image_mime_transforms', 437 function () { 438 return array( 'image/jpeg' => array() ); 439 } 440 ); 441 442 $attachment_id = $this->factory->attachment->create_upload_object( 443 DIR_TESTDATA . '/images/test-image.jpg' 444 ); 445 446 $metadata = wp_get_attachment_metadata( $attachment_id ); 447 448 $this->assertIsArray( $metadata ); 449 foreach ( $metadata['sizes'] as $size_name => $properties ) { 450 $this->assertArrayHasKey( 'sources', $properties ); 451 $this->assertIsArray( $properties['sources'] ); 452 $this->assertArrayHasKey( 'image/jpeg', $properties['sources'] ); 453 $this->assertArrayHasKey( 'filesize', $properties['sources']['image/jpeg'] ); 454 $this->assertArrayHasKey( 'file', $properties['sources']['image/jpeg'] ); 455 $this->assertArrayNotHasKey( 'image/webp', $properties['sources'] ); 456 } 457 } 458 459 /** 460 * Test not creating the sources property if the mime is not specified on the transforms images. 461 * 462 * @ticket 55443 463 */ 464 public function it_should_not_create_the_sources_property_if_the_mime_is_not_specified_on_the_transforms_images() { 465 add_filter( 466 'wp_upload_image_mime_transforms', 467 function () { 468 return array( 'image/jpeg' => array() ); 469 } 470 ); 471 472 $attachment_id = $this->factory->attachment->create_upload_object( 473 DIR_TESTDATA . '/images/webp-lossy.webp' 474 ); 475 476 $metadata = wp_get_attachment_metadata( $attachment_id ); 477 478 $this->assertIsArray( $metadata ); 479 foreach ( $metadata['sizes'] as $size_name => $properties ) { 480 $this->assertArrayNotHasKey( 'sources', $properties ); 481 } 482 } 483 484 485 /** 486 * Test creating a WebP version with all the required properties. 487 * 488 * @ticket 55443 489 */ 490 public function it_should_create_a_webp_version_with_all_the_required_properties() { 491 $attachment_id = $this->factory->attachment->create_upload_object( 492 DIR_TESTDATA . '/images/test-image.jpg' 493 ); 494 495 $metadata = wp_get_attachment_metadata( $attachment_id ); 496 $this->assertArrayHasKey( 'sources', $metadata['sizes']['thumbnail'] ); 497 $this->assertArrayHasKey( 'image/jpeg', $metadata['sizes']['thumbnail']['sources'] ); 498 $this->assertArrayHasKey( 'filesize', $metadata['sizes']['thumbnail']['sources']['image/jpeg'] ); 499 $this->assertArrayHasKey( 'file', $metadata['sizes']['thumbnail']['sources']['image/jpeg'] ); 500 $this->assertArrayHasKey( 'image/webp', $metadata['sizes']['thumbnail']['sources'] ); 501 $this->assertArrayHasKey( 'filesize', $metadata['sizes']['thumbnail']['sources']['image/webp'] ); 502 $this->assertArrayHasKey( 'file', $metadata['sizes']['thumbnail']['sources']['image/webp'] ); 503 $this->assertStringEndsNotWith( '.jpeg', $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ); 504 $this->assertStringEndsWith( '.webp', $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ); 505 } 506 507 /** 508 * Test removing `scaled` suffix from the generated filename. 509 * 510 * @ticket 55443 511 */ 512 public function it_should_remove_scaled_suffix_from_the_generated_filename() { 513 // The leafs image is 1080 pixels wide with this filter we ensure a -scaled version is created. 514 add_filter( 515 'big_image_size_threshold', 516 function () { 517 return 850; 518 } 519 ); 520 521 $attachment_id = $this->factory->attachment->create_upload_object( 522 DIR_TESTDATA . '/images/test-image.jpg' 523 ); 524 $metadata = wp_get_attachment_metadata( $attachment_id ); 525 $this->assertStringEndsWith( '-scaled.jpg', get_attached_file( $attachment_id ) ); 526 $this->assertArrayHasKey( 'image/webp', $metadata['sizes']['medium']['sources'] ); 527 $this->assertStringEndsNotWith( '-scaled.webp', $metadata['sizes']['medium']['sources']['image/webp']['file'] ); 528 $this->assertStringEndsWith( '-300x200.webp', $metadata['sizes']['medium']['sources']['image/webp']['file'] ); 529 } 530 531 /** 532 * Test removing the generated webp images when the attachment is deleted. 533 * 534 * @ticket 55443 535 */ 536 public function it_should_remove_the_generated_webp_images_when_the_attachment_is_deleted() { 537 // Make sure no editor is available. 538 $attachment_id = $this->factory->attachment->create_upload_object( 539 DIR_TESTDATA . '/images/test-image.jpg' 540 ); 541 542 $file = get_attached_file( $attachment_id, true ); 543 $dirname = pathinfo( $file, PATHINFO_DIRNAME ); 544 545 $this->assertIsString( $file ); 546 $this->assertFileExists( $file ); 547 548 $metadata = wp_get_attachment_metadata( $attachment_id ); 549 $sizes = array( 'thumbnail', 'medium' ); 550 551 foreach ( $sizes as $size_name ) { 552 $this->assertArrayHasKey( 'image/webp', $metadata['sizes'][ $size_name ]['sources'] ); 553 $this->assertArrayHasKey( 'file', $metadata['sizes'][ $size_name ]['sources']['image/webp'] ); 554 $this->assertFileExists( 555 path_join( $dirname, $metadata['sizes'][ $size_name ]['sources']['image/webp']['file'] ) 556 ); 557 } 558 559 wp_delete_attachment( $attachment_id ); 560 561 foreach ( $sizes as $size_name ) { 562 $this->assertFileDoesNotExist( 563 path_join( $dirname, $metadata['sizes'][ $size_name ]['sources']['image/webp']['file'] ) 564 ); 565 } 566 } 567 568 /** 569 * Test removing the attached WebP version if the attachment is force deleted but empty trash day is not defined. 570 * 571 * @ticket 55443 572 */ 573 public function it_should_remove_the_attached_webp_version_if_the_attachment_is_force_deleted_but_empty_trash_day_is_not_defined() { 574 // Make sure no editor is available. 575 $attachment_id = $this->factory->attachment->create_upload_object( 576 DIR_TESTDATA . '/images/test-image.jpg' 577 ); 578 579 $file = get_attached_file( $attachment_id, true ); 580 $dirname = pathinfo( $file, PATHINFO_DIRNAME ); 581 582 $this->assertIsString( $file ); 583 $this->assertFileExists( $file ); 584 585 $metadata = wp_get_attachment_metadata( $attachment_id ); 586 587 $this->assertFileExists( 588 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 589 ); 590 591 wp_delete_attachment( $attachment_id, true ); 592 593 $this->assertFileDoesNotExist( 594 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 595 ); 596 } 597 598 /** 599 * Test removing the WebP version of the image if the image is force deleted and empty trash days is set to zero. 600 * 601 * @ticket 55443 602 */ 603 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() { 604 // Make sure no editor is available. 605 $attachment_id = $this->factory->attachment->create_upload_object( 606 DIR_TESTDATA . '/images/test-image.jpg' 607 ); 608 609 $file = get_attached_file( $attachment_id, true ); 610 $dirname = pathinfo( $file, PATHINFO_DIRNAME ); 611 612 $this->assertIsString( $file ); 613 $this->assertFileExists( $file ); 614 615 $metadata = wp_get_attachment_metadata( $attachment_id ); 616 617 $this->assertFileExists( 618 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 619 ); 620 621 define( 'EMPTY_TRASH_DAYS', 0 ); 622 623 wp_delete_attachment( $attachment_id, true ); 624 625 $this->assertFileDoesNotExist( 626 path_join( $dirname, $metadata['sizes']['thumbnail']['sources']['image/webp']['file'] ) 627 ); 628 } 629 630 /** 631 * Test avoiding the change of URLs of images that are not part of the media library. 632 * 633 * @ticket 55443 634 */ 635 public function it_should_avoid_the_change_of_urls_of_images_that_are_not_part_of_the_media_library() { 636 $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>'; 637 638 $this->assertSame( $paragraph, webp_uploads_update_image_references( $paragraph ) ); 639 } 640 641 /** 642 * Test avoiding replacing not existing attachment IDs. 643 * 644 * @ticket 55443 645 */ 646 public function it_should_avoid_replacing_not_existing_attachment_i_ds() { 647 $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>'; 648 649 $this->assertSame( $paragraph, webp_uploads_update_image_references( $paragraph ) ); 650 } 651 652 /** 653 * Test preventing replacing a WebP image. 654 * 655 * @ticket 55443 656 */ 657 public function it_should_test_preventing_replacing_a_webp_image() { 658 $attachment_id = $this->factory->attachment->create_upload_object( 659 DIR_TESTDATA . '/images/webp-lossy.webp' 660 ); 661 662 $tag = wp_get_attachment_image( $attachment_id, 'medium', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 663 664 $this->assertSame( $tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 665 } 666 667 /** 668 * Test preventing replacing a jpg image if the image does not have the target class name. 669 * 670 * @ticket 55443 671 */ 672 public function it_should_test_preventing_replacing_a_jpg_image_if_the_image_does_not_have_the_target_class_name() { 673 $attachment_id = $this->factory->attachment->create_upload_object( 674 DIR_TESTDATA . '/images/test-image.jpg' 675 ); 676 677 $tag = wp_get_attachment_image( $attachment_id, 'medium' ); 678 679 $this->assertSame( $tag, webp_uploads_update_image_references( $tag ) ); 680 } 681 682 /** 683 * Test replacing the references to a JPG image to a WebP version. 684 * 685 * @dataProvider provider_replace_images_with_different_extensions 686 * 687 * @ticket 55443 688 */ 689 public function it_should_replace_the_references_to_a_jpg_image_to_a_webp_version( $image_path ) { 690 $attachment_id = $this->factory->attachment->create_upload_object( $image_path ); 691 692 $tag = wp_get_attachment_image( $attachment_id, 'medium', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 693 $expected_tag = $tag; 694 $metadata = wp_get_attachment_metadata( $attachment_id ); 695 foreach ( $metadata['sizes'] as $size => $properties ) { 696 $expected_tag = str_replace( $properties['sources']['image/jpeg']['file'], $properties['sources']['image/webp']['file'], $expected_tag ); 697 } 698 699 $this->assertNotEmpty( $expected_tag ); 700 $this->assertNotSame( $tag, $expected_tag ); 701 $this->assertSame( $expected_tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 702 } 703 704 public function provider_replace_images_with_different_extensions() { 705 yield 'An image with a .jpg extension' => array( DIR_TESTDATA . '/images/test-image.jpg' ); 706 yield 'An image with a .jpeg extension' => array( DIR_TESTDATA . '/images/test-image.jpeg' ); 707 } 708 709 /** 710 * Test the full image size from the original mime type. 711 * 712 * @ticket 55443 713 */ 714 public function it_should_contain_the_full_image_size_from_the_original_mime() { 715 $attachment_id = $this->factory->attachment->create_upload_object( 716 DIR_TESTDATA . '/images/test-image.jpg' 717 ); 718 719 $tag = wp_get_attachment_image( $attachment_id, 'full', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 720 721 $expected = array( 722 'ext' => 'jpg', 723 'type' => 'image/jpeg', 724 ); 725 $this->assertSame( $expected, wp_check_filetype( get_attached_file( $attachment_id ) ) ); 726 $this->assertContains( wp_basename( get_attached_file( $attachment_id ) ), webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 727 } 728 729 /** 730 * Test preventing replacing an image with no available sources. 731 * 732 * @ticket 55443 733 */ 734 public function it_should_prevent_replacing_an_image_with_no_available_sources() { 735 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 736 737 $attachment_id = $this->factory->attachment->create_upload_object( DIR_TESTDATA . '/images/test-image.jpg' ); 738 739 $tag = wp_get_attachment_image( $attachment_id, 'full', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 740 $this->assertSame( $tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 741 } 742 743 /** 744 * Test preventing update not supported images with no available sources. 745 * 746 * @dataProvider provider_it_should_prevent_update_not_supported_images_with_no_available_sources 747 * 748 * @ticket 55443 749 */ 750 public function it_should_prevent_update_not_supported_images_with_no_available_sources( $image_path ) { 751 $attachment_id = $this->factory->attachment->create_upload_object( $image_path ); 752 753 $this->assertIsNumeric( $attachment_id ); 754 $tag = wp_get_attachment_image( $attachment_id, 'full', false, array( 'class' => "wp-image-{$attachment_id}" ) ); 755 756 $this->assertSame( $tag, webp_uploads_img_tag_update_mime_type( $tag, 'the_content', $attachment_id ) ); 757 } 758 759 /** 760 * Data provider for it_should_prevent_update_not_supported_images_with_no_available_sources. 761 */ 762 public function provider_it_should_prevent_update_not_supported_images_with_no_available_sources() { 763 yield 'PNG image' => array( DIR_TESTDATA . '/images/test-image.png' ); 764 yield 'GIFT image' => array( DIR_TESTDATA . '/images/test-image.gif' ); 765 } 766 365 767 } -
trunk/tests/phpunit/tests/image/functions.php
r53542 r53751 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'; … … 678 681 'mime-type' => 'image/jpeg', 679 682 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-232x300.jpg' ), 683 'sources' => array( 684 'image/jpeg' => array( 685 'file' => 'wordpress-gsoc-flyer-pdf-232x300.jpg', 686 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-232x300.jpg' ), 687 ), 688 ), 680 689 ), 681 690 'large' => array( … … 685 694 'mime-type' => 'image/jpeg', 686 695 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 696 'sources' => array( 697 'image/jpeg' => array( 698 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', 699 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 700 ), 701 ), 687 702 ), 688 703 'thumbnail' => array( … … 692 707 'mime-type' => 'image/jpeg', 693 708 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 709 'sources' => array( 710 'image/jpeg' => array( 711 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', 712 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 713 ), 714 ), 694 715 ), 695 716 ), … … 703 724 unlink( $temp_dir . $size['file'] ); 704 725 } 726 remove_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 705 727 } 706 728 … … 716 738 717 739 update_option( 'medium_crop', 1 ); 740 741 // Use legacy JPEG output. 742 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 718 743 719 744 $orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf'; … … 755 780 'mime-type' => 'image/jpeg', 756 781 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-300x300.jpg' ), 782 'sources' => array( 783 'image/jpeg' => array( 784 'file' => 'wordpress-gsoc-flyer-pdf-300x300.jpg', 785 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-300x300.jpg' ), 786 ), 787 ), 757 788 ), 758 789 'large' => array( … … 762 793 'mime-type' => 'image/jpeg', 763 794 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 795 'sources' => array( 796 'image/jpeg' => array( 797 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', 798 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), 799 ), 800 ), 801 764 802 ), 765 803 'thumbnail' => array( … … 769 807 'mime-type' => 'image/jpeg', 770 808 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 809 'sources' => array( 810 'image/jpeg' => array( 811 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', 812 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), 813 ), 814 ), 771 815 ), 772 816 ), … … 780 824 unlink( $temp_dir . $size['file'] ); 781 825 } 826 remove_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 827 782 828 } 783 829 … … 789 835 $this->markTestSkipped( 'Rendering PDFs is not supported on this system.' ); 790 836 } 837 838 // Use legacy JPEG output. 839 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 791 840 792 841 $orig_file = DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf'; … … 822 871 'mime-type' => 'image/jpeg', 823 872 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-77x100.jpg' ), 873 'sources' => array( 874 'image/jpeg' => array( 875 'file' => 'wordpress-gsoc-flyer-pdf-77x100.jpg', 876 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-77x100.jpg' ), 877 ), 878 ), 824 879 ); 825 880 … … 837 892 unlink( $temp_dir . $size['file'] ); 838 893 } 894 remove_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 839 895 } 840 896 … … 1027 1083 ); 1028 1084 } 1085 1086 /** 1087 * @ticket 55443 1088 */ 1089 public function test_wp_upload_image_mime_transforms_generates_webp_and_jpeg_for_both_by_default() { 1090 $result = wp_upload_image_mime_transforms( 42 ); 1091 $this->assertArrayHasKey( 'image/jpeg', $result ); 1092 $this->assertArrayHasKey( 'image/webp', $result ); 1093 $this->assertSameSets( array( 'image/jpeg', 'image/webp' ), $result['image/jpeg'] ); 1094 $this->assertSameSets( array( 'image/jpeg', 'image/webp' ), $result['image/webp'] ); 1095 } 1096 1097 /** 1098 * @ticket 55443 1099 */ 1100 public function test_wp_upload_image_mime_transforms_filter_always_use_webp_instead_of_jpeg() { 1101 add_filter( 1102 'wp_upload_image_mime_transforms', 1103 function( $transforms ) { 1104 // Ensure JPG only results in WebP files. 1105 $transforms['image/jpeg'] = array( 'image/webp' ); 1106 // Unset WebP since it does not need any transformation in that case. 1107 unset( $transforms['image/webp'] ); 1108 return $transforms; 1109 } 1110 ); 1111 1112 $result = wp_upload_image_mime_transforms( 42 ); 1113 $this->assertArrayHasKey( 'image/jpeg', $result ); 1114 $this->assertArrayNotHasKey( 'image/webp', $result ); 1115 $this->assertSameSets( array( 'image/webp' ), $result['image/jpeg'] ); 1116 } 1117 1118 /** 1119 * @ticket 55443 1120 */ 1121 public function test_wp_upload_image_mime_transforms_filter_receives_parameters() { 1122 $attachment_id = null; 1123 add_filter( 1124 'wp_upload_image_mime_transforms', 1125 function( $transforms, $param1 ) use ( &$attachment_id ) { 1126 $attachment_id = $param1; 1127 return $transforms; 1128 }, 1129 10, 1130 2 1131 ); 1132 1133 wp_upload_image_mime_transforms( 23 ); 1134 $this->assertSame( 23, $attachment_id ); 1135 } 1136 1137 /** 1138 * @ticket 55443 1139 */ 1140 public function test_wp_upload_image_mime_transforms_filter_with_empty_array() { 1141 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 1142 $result = wp_upload_image_mime_transforms( 42 ); 1143 $this->assertSame( array(), $result ); 1144 } 1145 1146 /** 1147 * @ticket 55443 1148 */ 1149 public function test_wp_upload_image_mime_transforms_filter_with_invalid_usage() { 1150 $default = wp_upload_image_mime_transforms( 42 ); 1151 1152 add_filter( 'wp_upload_image_mime_transforms', '__return_false' ); 1153 $result = wp_upload_image_mime_transforms( 42 ); 1154 $this->assertSame( $default, $result ); 1155 } 1156 1157 /** 1158 * @ticket 55443 1159 */ 1160 public function test__wp_get_primary_and_additional_mime_types_default() { 1161 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1162 1163 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1164 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1165 1166 // WebP may not be supported by the server, in which case it will be stripped from the results. 1167 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1168 $this->assertSame( array( 'image/webp' ), $additional_mime_types ); 1169 } else { 1170 $this->assertSame( array(), $additional_mime_types ); 1171 } 1172 } 1173 1174 /** 1175 * @ticket 55443 1176 */ 1177 public function test__wp_get_primary_and_additional_mime_types_prefer_original_mime() { 1178 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1179 1180 // Set 'image/jpeg' only as secondary output MIME type. 1181 // Still, because it is the original, it should be chosen as primary over 'image/webp'. 1182 add_filter( 1183 'wp_upload_image_mime_transforms', 1184 function( $transforms ) { 1185 $transforms['image/jpeg'] = array( 'image/webp', 'image/jpeg' ); 1186 return $transforms; 1187 } 1188 ); 1189 1190 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1191 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1192 1193 // WebP may not be supported by the server, in which case it will be stripped from the results. 1194 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1195 $this->assertSame( array( 'image/webp' ), $additional_mime_types ); 1196 } else { 1197 $this->assertSame( array(), $additional_mime_types ); 1198 } 1199 } 1200 1201 /** 1202 * @ticket 55443 1203 */ 1204 public function test__wp_get_primary_and_additional_mime_types_use_original_mime_when_no_transformation_rules() { 1205 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1206 1207 // Strip all transformation rules. 1208 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 1209 1210 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1211 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1212 $this->assertSame( array(), $additional_mime_types ); 1213 } 1214 1215 /** 1216 * @ticket 55443 1217 */ 1218 public function test__wp_get_primary_and_additional_mime_types_different_output_mime() { 1219 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1220 1221 // Set 'image/webp' as the only output MIME type. 1222 // In that case, JPEG is not generated at all, so WebP becomes the primary MIME type. 1223 add_filter( 1224 'wp_upload_image_mime_transforms', 1225 function( $transforms ) { 1226 $transforms['image/jpeg'] = array( 'image/webp' ); 1227 return $transforms; 1228 } 1229 ); 1230 1231 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1232 1233 // WebP may not be supported by the server, in which case it will fall back to the original MIME type. 1234 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1235 $this->assertSame( 'image/webp', $primary_mime_type ); 1236 } else { 1237 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1238 } 1239 1240 $this->assertSame( array(), $additional_mime_types ); 1241 } 1242 1243 /** 1244 * @ticket 55443 1245 */ 1246 public function test__wp_get_primary_and_additional_mime_types_different_output_mimes() { 1247 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1248 1249 // Set 'image/webp' and 'image/avif' as output MIME types. 1250 // In that case, JPEG is not generated at all, with WebP being the primary MIME type and AVIF the secondary. 1251 add_filter( 1252 'wp_upload_image_mime_transforms', 1253 function( $transforms ) { 1254 $transforms['image/jpeg'] = array( 'image/webp', 'image/avif' ); 1255 return $transforms; 1256 } 1257 ); 1258 1259 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1260 1261 // WebP may not be supported by the server, in which case it will fall back to the original MIME type. 1262 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1263 $this->assertSame( 'image/webp', $primary_mime_type ); 1264 } else { 1265 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1266 } 1267 1268 // AVIF may not be supported by the server, in which case it will be stripped from the results. 1269 if ( wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) { 1270 $this->assertSame( array( 'image/avif' ), $additional_mime_types ); 1271 } else { 1272 $this->assertSame( array(), $additional_mime_types ); 1273 } 1274 } 1275 1276 /** 1277 * @ticket 55443 1278 * @dataProvider data__wp_filter_image_sizes_additional_mime_type_support 1279 */ 1280 public function test__wp_filter_image_sizes_additional_mime_type_support( $input_size_data, $filter_callback, $expected_size_names ) { 1281 remove_all_filters( 'wp_image_sizes_with_additional_mime_type_support' ); 1282 if ( $filter_callback ) { 1283 add_filter( 'wp_image_sizes_with_additional_mime_type_support', $filter_callback ); 1284 } 1285 1286 $expected_size_data = array_intersect_key( $input_size_data, array_flip( $expected_size_names ) ); 1287 1288 $output_size_data = _wp_filter_image_sizes_additional_mime_type_support( $input_size_data, 42 ); 1289 $this->assertEqualSetsWithIndex( $expected_size_data, $output_size_data ); 1290 } 1291 1292 public function data__wp_filter_image_sizes_additional_mime_type_support() { 1293 $thumbnail_data = array( 1294 'width' => 150, 1295 'height' => 150, 1296 'crop' => true, 1297 ); 1298 $medium_data = array( 1299 'width' => 300, 1300 'height' => 300, 1301 'crop' => false, 1302 ); 1303 $medium_large_data = array( 1304 'width' => 768, 1305 'height' => 0, 1306 'crop' => false, 1307 ); 1308 $large_data = array( 1309 'width' => 1024, 1310 'height' => 1024, 1311 'crop' => false, 1312 ); 1313 $custom_data = array( 1314 'width' => 512, 1315 'height' => 512, 1316 'crop' => true, 1317 ); 1318 1319 return array( 1320 array( 1321 array( 1322 'thumbnail' => $thumbnail_data, 1323 'medium' => $medium_data, 1324 'medium_large' => $medium_large_data, 1325 'large' => $large_data, 1326 ), 1327 null, 1328 array( 'thumbnail', 'medium', 'medium_large', 'large' ), 1329 ), 1330 array( 1331 array( 1332 'thumbnail' => $thumbnail_data, 1333 'medium' => $medium_data, 1334 'custom' => $custom_data, 1335 ), 1336 null, 1337 array( 'thumbnail', 'medium' ), 1338 ), 1339 array( 1340 array( 1341 'thumbnail' => $thumbnail_data, 1342 'medium' => $medium_data, 1343 'medium_large' => $medium_large_data, 1344 'large' => $large_data, 1345 ), 1346 function( $enabled_sizes ) { 1347 unset( $enabled_sizes['medium_large'], $enabled_sizes['large'] ); 1348 return $enabled_sizes; 1349 }, 1350 array( 'thumbnail', 'medium' ), 1351 ), 1352 array( 1353 array( 1354 'thumbnail' => $thumbnail_data, 1355 'medium' => $medium_data, 1356 'medium_large' => $medium_large_data, 1357 'large' => $large_data, 1358 ), 1359 function( $enabled_sizes ) { 1360 $enabled_sizes['medium_large'] = false; 1361 $enabled_sizes['large'] = false; 1362 return $enabled_sizes; 1363 }, 1364 array( 'thumbnail', 'medium' ), 1365 ), 1366 array( 1367 array( 1368 'thumbnail' => $thumbnail_data, 1369 'medium' => $medium_data, 1370 'custom' => $custom_data, 1371 ), 1372 function( $enabled_sizes ) { 1373 unset( $enabled_sizes['medium'] ); 1374 $enabled_sizes['custom'] = true; 1375 return $enabled_sizes; 1376 }, 1377 array( 'thumbnail', 'custom' ), 1378 ), 1379 ); 1380 } 1381 1382 /** 1383 * Test the `_wp_maybe_scale_and_rotate_image()` function. 1384 * 1385 * @dataProvider data_test__wp_maybe_scale_and_rotate_image 1386 * 1387 * @ticket 55443 1388 */ 1389 public function test__wp_maybe_scale_and_rotate_image( $file, $imagesize, $mime_type, $expected ) { 1390 if ( ! wp_image_editor_supports( array( 'mime_type' => $mime_type ) ) ) { 1391 $this->markTestSkipped( sprintf( 'This test requires %s support.', $mime_type ) ); 1392 } 1393 1394 $attributes = array( 'post_mime_type' => $mime_type ); 1395 $attachment_id = $this->factory->attachment->create_object( $file, 0, $attributes ); 1396 $exif_meta = wp_read_image_metadata( $file ); 1397 1398 list( $editor, $resized, $rotated ) = _wp_maybe_scale_and_rotate_image( $file, $attachment_id, $imagesize, $exif_meta, $mime_type ); 1399 1400 $this->assertSame( $expected['rotated'], $rotated ); 1401 $this->assertSame( $expected['resized'], $resized ); 1402 $this->assertSame( $expected['size'], $editor->get_size() ); 1403 } 1404 1405 /** 1406 * Data provider for the `test__wp_maybe_scale_and_rotate_image()` test. 1407 * 1408 * @return array 1409 */ 1410 public function data_test__wp_maybe_scale_and_rotate_image() { 1411 return array( 1412 1413 // Image that will be scaled. 1414 array( 1415 DIR_TESTDATA . '/images/test-image-large.jpg', 1416 array( 3000, 2250 ), 1417 'image/jpeg', 1418 array( 1419 'rotated' => false, 1420 'resized' => true, 1421 'size' => array( 1422 'width' => 2560, 1423 'height' => 1920, 1424 ), 1425 ), 1426 ), 1427 1428 // Image that will not be scaled. 1429 array( 1430 DIR_TESTDATA . '/images/canola.jpg', 1431 array( 640, 480 ), 1432 'image/jpeg', 1433 array( 1434 'rotated' => false, 1435 'resized' => false, 1436 'size' => array( 1437 'width' => 640, 1438 'height' => 480, 1439 ), 1440 ), 1441 ), 1442 1443 // Image that will be flipped. 1444 array( 1445 DIR_TESTDATA . '/images/test-image-upside-down.jpg', 1446 array( 600, 450 ), 1447 'image/jpeg', 1448 array( 1449 'rotated' => true, 1450 'resized' => false, 1451 'size' => array( 1452 'width' => 600, 1453 'height' => 450, 1454 ), 1455 ), 1456 ), 1457 1458 // Image that will be rotated. 1459 array( 1460 DIR_TESTDATA . '/images/test-image-rotated-90ccw.jpg', 1461 array( 1200, 1800 ), 1462 'image/jpeg', 1463 array( 1464 'rotated' => true, 1465 'resized' => false, 1466 'size' => array( 1467 'width' => 1800, 1468 'height' => 1200, 1469 ), 1470 ), 1471 ), 1472 1473 // Image that will not be rotated - WebP Exif is not supported in PHP. 1474 array( 1475 DIR_TESTDATA . '/images/test-image-rotated-90cw.webp', 1476 array( 1024, 768 ), 1477 'image/webp', 1478 array( 1479 'rotated' => false, 1480 'resized' => false, 1481 'size' => array( 1482 'width' => 1024, 1483 'height' => 768, 1484 ), 1485 ), 1486 ), 1487 1488 ); 1489 } 1490 1491 /** 1492 * Test the `_wp_get_image_suffix()` function. 1493 * @dataProvider data_test__wp_get_image_suffix 1494 * 1495 * @ticket 55443 1496 */ 1497 public function test__wp_get_image_suffix( $resized, $rotated, $expected ) { 1498 $this->assertSame( $expected, _wp_get_image_suffix( $resized, $rotated ) ); 1499 } 1500 1501 /** 1502 * Data provider for the `test__wp_get_image_suffix()` test. 1503 */ 1504 public function data_test__wp_get_image_suffix() { 1505 return array( 1506 array( false, false, '' ), 1507 array( true, false, 'scaled' ), 1508 array( false, true, 'rotated' ), 1509 array( true, true, 'scaled' ), 1510 ); 1511 } 1029 1512 } -
trunk/tests/phpunit/tests/media.php
r53558 r53751 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 ) ); … … 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 … … 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 … … 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( … … 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' ); … … 2469 2477 2470 2478 $this->assertSame( $expected, $actual ); 2479 remove_filter( 'wp_content_image_mimes', '__return_empty_array' ); 2471 2480 } 2472 2481 … … 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 ) ); … … 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 … … 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 ) ); … … 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 … … 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 … … 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 … … 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' ); … … 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. … … 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
Note: See TracChangeset
for help on using the changeset viewer.