Ticket #55443: 55443.6.diff
File 55443.6.diff, 91.8 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..75b4e48562 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_output_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_output_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 Associative array of image sizes. 652 * @param int $attachment_id Attachment ID. 653 * @return array $sizes Filtered $sizes with only those 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 * @return array An array of valid mime types, where the key is the source file mime type and the list of mime types to 1462 * generate. 1463 */ 1464 function wp_upload_image_mime_transforms( $attachment_id ) { 1465 $default_image_mime_transforms = array( 1466 'image/jpeg' => array( 'image/jpeg', 'image/webp' ), 1467 'image/webp' => array( 'image/webp', 'image/jpeg' ), 1468 ); 1469 $image_mime_transforms = $default_image_mime_transforms; 1470 1471 /** 1472 * Filter the output mime types for a given input mime type and image size. 1473 * 1474 * @since 6.1.0 1475 * 1476 * @param array $image_mime_transforms A map with the valid mime transforms where the key is the source file mime type 1477 * and the value is one or more mime file types to generate. 1478 * @param int $attachment_id The ID of the attachment where the hook was dispatched. 1479 */ 1480 $image_mime_transforms = apply_filters( 'wp_upload_image_mime_transforms', $image_mime_transforms, $attachment_id ); 1481 1482 if ( ! is_array( $image_mime_transforms ) ) { 1483 return $default_image_mime_transforms; 1484 } 1485 1486 return array_map( 1487 function( $transforms_list ) { 1488 return (array) $transforms_list; 1489 }, 1490 $image_mime_transforms 1491 ); 1492 } 1493 1494 /** 1495 * Extract the primary and additional mime output types for an image from the $image_mime_transforms. 1496 * 1497 * @since 6.1.0 1498 * @access private 1499 * 1500 * @param string $file Full path to the image file. 1501 * @param int $attachment_id Attachment ID to process. 1502 * @return array An array with two entries, the primary mime type and the list of additional mime types. 1503 */ 1504 function _wp_get_primary_and_additional_mime_types( $file, $attachment_id ) { 1505 $image_mime_transforms = wp_upload_image_mime_transforms( $attachment_id ); 1506 $original_mime_type = wp_get_image_mime( $file ); 1507 $output_mime_types = isset( $image_mime_transforms[ $original_mime_type ] ) ? $image_mime_transforms[ $original_mime_type ] : array( $original_mime_type ); 1508 1509 // Exclude any output mime types that the system doesn't support. 1510 $output_mime_types = array_values( 1511 array_filter( 1512 $output_mime_types, 1513 function( $mime_type ) { 1514 return wp_image_editor_supports( 1515 array( 1516 'mime_type' => $mime_type, 1517 ) 1518 ); 1519 } 1520 ) 1521 ); 1522 1523 // Handle an empty value for $output_mime_types: only output the original type. 1524 if ( empty( $output_mime_types ) ) { 1525 return array( $original_mime_type, array() ); 1526 } 1527 1528 // Use original mime type as primary mime type, or alternatively the first one. 1529 $primary_mime_type_key = array_search( $original_mime_type, $output_mime_types, true ); 1530 if ( false === $primary_mime_type_key ) { 1531 $primary_mime_type_key = 0; 1532 } 1533 // Split output mime types into primary mime type and additional mime types. 1534 $additional_mime_types = $output_mime_types; 1535 list( $primary_mime_type ) = array_splice( $additional_mime_types, $primary_mime_type_key, 1 ); 1536 1537 return array( 1538 $primary_mime_type, 1539 $additional_mime_types, 1540 ); 1541 } -
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..5353ec1bba 100644
abstract class WP_Image_Editor { 334 334 protected function get_output_format( $filename = null, $mime_type = null ) { 335 335 $new_ext = null; 336 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 } 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 { 425 430 } 426 431 427 432 /** 428 * Builds an output filename based on current file, and adding proper suffix 433 * Builds an output filename based on current file, and adding proper suffix. 429 434 * 430 435 * @since 3.5.0 431 * 432 * @param string $suffix 433 * @param string $dest_path 434 * @param string $extension 435 * @return string filename 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 } 442 454 … … abstract class WP_Image_Editor { 457 469 } 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, .jpg and .jpeg 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 463 489 /** … … abstract class WP_Image_Editor { 637 663 638 664 return wp_get_default_extension_for_mime_type( $mime_type ); 639 665 } 640 }641 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 } 690 } -
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 9689e008ea..c7dcc13b8d 100644
function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) { 6481 6481 $intermediate_dir = path_join( $uploadpath['basedir'], dirname( $file ) ); 6482 6482 6483 6483 foreach ( $meta['sizes'] as $size => $sizeinfo ) { 6484 $intermediate_file = str_replace( wp_basename( $file ), $sizeinfo['file'], $file );6485 6484 6486 if ( ! empty( $intermediate_file ) ) { 6487 $intermediate_file = path_join( $uploadpath['basedir'], $intermediate_file ); 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 ); 6488 6499 6489 if ( ! wp_delete_file_from_directory( $intermediate_file, $intermediate_dir ) ) { 6490 $deleted = false; 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 } 6493 6508 } … … function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) { 6509 6524 } 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 ) ) { 6513 $del_dir = path_join( $uploadpath['basedir'], dirname( $meta['file'] ) );6514 6547 6548 $del_dir = path_join( $uploadpath['basedir'], dirname( $meta['file'] ) ); 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 ); 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'] ); 6520 6570 6521 if ( ! wp_delete_file_from_directory( $del_file, $del_dir ) ) { 6522 $deleted = false; 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 6579 } 6527 6580 6528 if ( ! wp_delete_file_from_directory( $file, $uploadpath['basedir'] ) ) {6529 $deleted = false;6530 }6531 6532 6581 return $deleted; 6533 6582 } 6534 6583 -
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..2115fe2594 100644
class Tests_Image_Editor extends WP_Image_UnitTestCase { 131 131 $this->assertSame( 86, $editor->get_quality(), 'Output image format is WEBP. Quality setting for it should be 86.' ); 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(); 136 137 $this->assertSame( 82, $editor->get_quality(), 'After removing image conversion quality setting should reset to the default of 82.' ); … … class Tests_Image_Editor extends WP_Image_UnitTestCase { 154 155 $this->assertSame( 42, $editor->get_quality(), 'Image conversion from JPEG to WEBP. Filtered WEBP quality shoild be 42.' ); 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(); 159 161 $this->assertSame( … … class Tests_Image_Editor extends WP_Image_UnitTestCase { 226 228 $this->assertSame( trailingslashit( realpath( get_temp_dir() ) ), trailingslashit( realpath( dirname( $editor->generate_filename( null, get_temp_dir() ) ) ) ) ); 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. 235 237 $this->assertSame( 'file://testing/path/canola-100x50.jpg', $editor->generate_filename( null, 'file://testing/path' ) ); … … class Tests_Image_Editor extends WP_Image_UnitTestCase { 362 364 ); 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 } -
tests/phpunit/tests/image/functions.php
diff --git tests/phpunit/tests/image/functions.php tests/phpunit/tests/image/functions.php index 86d559145e..7e4734bf0f 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 ); 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 ); 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 add_filter( 1123 'wp_upload_image_mime_transforms', 1124 function( $transforms, $param1 ) use ( &$attachment_id ) { 1125 $attachment_id = $param1; 1126 return $transforms; 1127 }, 1128 10, 1129 2 1130 ); 1131 1132 wp_upload_image_mime_transforms( 23 ); 1133 $this->assertSame( 23, $attachment_id ); 1134 } 1135 1136 /** 1137 * @ticket 55443 1138 */ 1139 public function test_wp_upload_image_mime_transforms_filter_with_empty_array() { 1140 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 1141 $result = wp_upload_image_mime_transforms( 42 ); 1142 $this->assertSame( array(), $result ); 1143 } 1144 1145 /** 1146 * @ticket 55443 1147 */ 1148 public function test_wp_upload_image_mime_transforms_filter_with_invalid_usage() { 1149 $default = wp_upload_image_mime_transforms( 42 ); 1150 1151 add_filter( 'wp_upload_image_mime_transforms', '__return_false' ); 1152 $result = wp_upload_image_mime_transforms( 42 ); 1153 $this->assertSame( $default, $result ); 1154 } 1155 1156 /** 1157 * @ticket 55443 1158 */ 1159 public function test__wp_get_primary_and_additional_mime_types_default() { 1160 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1161 1162 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1163 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1164 1165 // WebP may not be supported by the server, in which case it will be stripped from the results. 1166 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1167 $this->assertSame( array( 'image/webp' ), $additional_mime_types ); 1168 } else { 1169 $this->assertSame( array(), $additional_mime_types ); 1170 } 1171 } 1172 1173 /** 1174 * @ticket 55443 1175 */ 1176 public function test__wp_get_primary_and_additional_mime_types_prefer_original_mime() { 1177 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1178 1179 // Set 'image/jpeg' only as secondary output MIME type. 1180 // Still, because it is the original, it should be chosen as primary over 'image/webp'. 1181 add_filter( 1182 'wp_upload_image_mime_transforms', 1183 function( $transforms ) { 1184 $transforms['image/jpeg'] = array( 'image/webp', 'image/jpeg' ); 1185 return $transforms; 1186 } 1187 ); 1188 1189 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1190 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1191 1192 // WebP may not be supported by the server, in which case it will be stripped from the results. 1193 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1194 $this->assertSame( array( 'image/webp' ), $additional_mime_types ); 1195 } else { 1196 $this->assertSame( array(), $additional_mime_types ); 1197 } 1198 } 1199 1200 /** 1201 * @ticket 55443 1202 */ 1203 public function test__wp_get_primary_and_additional_mime_types_use_original_mime_when_no_transformation_rules() { 1204 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1205 1206 // Strip all transformation rules. 1207 add_filter( 'wp_upload_image_mime_transforms', '__return_empty_array' ); 1208 1209 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1210 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1211 $this->assertSame( array(), $additional_mime_types ); 1212 } 1213 1214 /** 1215 * @ticket 55443 1216 */ 1217 public function test__wp_get_primary_and_additional_mime_types_different_output_mime() { 1218 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1219 1220 // Set 'image/webp' as the only output MIME type. 1221 // In that case, JPEG is not generated at all, so WebP becomes the primary MIME type. 1222 add_filter( 1223 'wp_upload_image_mime_transforms', 1224 function( $transforms ) { 1225 $transforms['image/jpeg'] = array( 'image/webp' ); 1226 return $transforms; 1227 } 1228 ); 1229 1230 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1231 1232 // WebP may not be supported by the server, in which case it will fall back to the original MIME type. 1233 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1234 $this->assertSame( 'image/webp', $primary_mime_type ); 1235 } else { 1236 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1237 } 1238 1239 $this->assertSame( array(), $additional_mime_types ); 1240 } 1241 1242 /** 1243 * @ticket 55443 1244 */ 1245 public function test__wp_get_primary_and_additional_mime_types_different_output_mimes() { 1246 $jpeg_file = DIR_TESTDATA . '/images/test-image-large.jpg'; 1247 1248 // Set 'image/webp' and 'image/avif' as output MIME types. 1249 // In that case, JPEG is not generated at all, with WebP being the primary MIME type and AVIF the secondary. 1250 add_filter( 1251 'wp_upload_image_mime_transforms', 1252 function( $transforms ) { 1253 $transforms['image/jpeg'] = array( 'image/webp', 'image/avif' ); 1254 return $transforms; 1255 } 1256 ); 1257 1258 list( $primary_mime_type, $additional_mime_types ) = _wp_get_primary_and_additional_mime_types( $jpeg_file, 42 ); 1259 1260 // WebP may not be supported by the server, in which case it will fall back to the original MIME type. 1261 if ( wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { 1262 $this->assertSame( 'image/webp', $primary_mime_type ); 1263 } else { 1264 $this->assertSame( 'image/jpeg', $primary_mime_type ); 1265 } 1266 1267 // AVIF may not be supported by the server, in which case it will be stripped from the results. 1268 if ( wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) { 1269 $this->assertSame( array( 'image/avif' ), $additional_mime_types ); 1270 } else { 1271 $this->assertSame( array(), $additional_mime_types ); 1272 } 1273 } 1274 1275 /** 1276 * @ticket 55443 1277 * @dataProvider data__wp_filter_image_sizes_additional_mime_type_support 1278 */ 1279 public function test__wp_filter_image_sizes_additional_mime_type_support( $input_size_data, $filter_callback, $expected_size_names ) { 1280 remove_all_filters( 'wp_image_sizes_with_additional_mime_type_support' ); 1281 if ( $filter_callback ) { 1282 add_filter( 'wp_image_sizes_with_additional_mime_type_support', $filter_callback ); 1283 } 1284 1285 $expected_size_data = array_intersect_key( $input_size_data, array_flip( $expected_size_names ) ); 1286 1287 $output_size_data = _wp_filter_image_sizes_additional_mime_type_support( $input_size_data, 42 ); 1288 $this->assertEqualSetsWithIndex( $expected_size_data, $output_size_data ); 1289 } 1290 1291 public function data__wp_filter_image_sizes_additional_mime_type_support() { 1292 $thumbnail_data = array( 1293 'width' => 150, 1294 'height' => 150, 1295 'crop' => true, 1296 ); 1297 $medium_data = array( 1298 'width' => 300, 1299 'height' => 300, 1300 'crop' => false, 1301 ); 1302 $medium_large_data = array( 1303 'width' => 768, 1304 'height' => 0, 1305 'crop' => false, 1306 ); 1307 $large_data = array( 1308 'width' => 1024, 1309 'height' => 1024, 1310 'crop' => false, 1311 ); 1312 $custom_data = array( 1313 'width' => 512, 1314 'height' => 512, 1315 'crop' => true, 1316 ); 1317 1318 return array( 1319 array( 1320 array( 1321 'thumbnail' => $thumbnail_data, 1322 'medium' => $medium_data, 1323 'medium_large' => $medium_large_data, 1324 'large' => $large_data, 1325 ), 1326 null, 1327 array( 'thumbnail', 'medium', 'medium_large', 'large' ), 1328 ), 1329 array( 1330 array( 1331 'thumbnail' => $thumbnail_data, 1332 'medium' => $medium_data, 1333 'custom' => $custom_data, 1334 ), 1335 null, 1336 array( 'thumbnail', 'medium' ), 1337 ), 1338 array( 1339 array( 1340 'thumbnail' => $thumbnail_data, 1341 'medium' => $medium_data, 1342 'medium_large' => $medium_large_data, 1343 'large' => $large_data, 1344 ), 1345 function( $enabled_sizes ) { 1346 unset( $enabled_sizes['medium_large'], $enabled_sizes['large'] ); 1347 return $enabled_sizes; 1348 }, 1349 array( 'thumbnail', 'medium' ), 1350 ), 1351 array( 1352 array( 1353 'thumbnail' => $thumbnail_data, 1354 'medium' => $medium_data, 1355 'medium_large' => $medium_large_data, 1356 'large' => $large_data, 1357 ), 1358 function( $enabled_sizes ) { 1359 $enabled_sizes['medium_large'] = false; 1360 $enabled_sizes['large'] = false; 1361 return $enabled_sizes; 1362 }, 1363 array( 'thumbnail', 'medium' ), 1364 ), 1365 array( 1366 array( 1367 'thumbnail' => $thumbnail_data, 1368 'medium' => $medium_data, 1369 'custom' => $custom_data, 1370 ), 1371 function( $enabled_sizes ) { 1372 unset( $enabled_sizes['medium'] ); 1373 $enabled_sizes['custom'] = true; 1374 return $enabled_sizes; 1375 }, 1376 array( 'thumbnail', 'custom' ), 1377 ), 1378 ); 1379 } 1380 1381 /** 1382 * Test the `_wp_maybe_scale_and_rotate_image()` function. 1383 * 1384 * @dataProvider data_test__wp_maybe_scale_and_rotate_image 1385 * 1386 * @ticket 55443 1387 */ 1388 public function test__wp_maybe_scale_and_rotate_image( $file, $imagesize, $mime_type, $expected ) { 1389 if ( ! wp_image_editor_supports( array( 'mime_type' => $mime_type ) ) ) { 1390 $this->markTestSkipped( sprintf( 'This test requires %s support.', $mime_type ) ); 1391 } 1392 1393 $attributes = array( 'post_mime_type' => $mime_type ); 1394 $attachment_id = $this->factory->attachment->create_object( $file, 0, $attributes ); 1395 $exif_meta = wp_read_image_metadata( $file ); 1396 1397 list( $editor, $resized, $rotated ) = _wp_maybe_scale_and_rotate_image( $file, $attachment_id, $imagesize, $exif_meta, $mime_type ); 1398 1399 $this->assertSame( $expected['rotated'], $rotated ); 1400 $this->assertSame( $expected['resized'], $resized ); 1401 $this->assertSame( $expected['size'], $editor->get_size() ); 1402 } 1403 1404 /** 1405 * Data provider for the `test__wp_maybe_scale_and_rotate_image()` test. 1406 * 1407 * @return array 1408 */ 1409 public function data_test__wp_maybe_scale_and_rotate_image() { 1410 return array( 1411 1412 // Image that will be scaled. 1413 array( 1414 DIR_TESTDATA . '/images/test-image-large.jpg', 1415 array( 3000, 2250 ), 1416 'image/jpeg', 1417 array( 1418 'rotated' => false, 1419 'resized' => true, 1420 'size' => array( 1421 'width' => 2560, 1422 'height' => 1920, 1423 ), 1424 ), 1425 ), 1426 1427 // Image that will not be scaled. 1428 array( 1429 DIR_TESTDATA . '/images/canola.jpg', 1430 array( 640, 480 ), 1431 'image/jpeg', 1432 array( 1433 'rotated' => false, 1434 'resized' => false, 1435 'size' => array( 1436 'width' => 640, 1437 'height' => 480, 1438 ), 1439 ), 1440 ), 1441 1442 // Image that will be flipped. 1443 array( 1444 DIR_TESTDATA . '/images/test-image-upside-down.jpg', 1445 array( 600, 450 ), 1446 'image/jpeg', 1447 array( 1448 'rotated' => true, 1449 'resized' => false, 1450 'size' => array( 1451 'width' => 600, 1452 'height' => 450, 1453 ), 1454 ), 1455 ), 1456 1457 // Image that will be rotated. 1458 array( 1459 DIR_TESTDATA . '/images/test-image-rotated-90ccw.jpg', 1460 array( 1200, 1800 ), 1461 'image/jpeg', 1462 array( 1463 'rotated' => true, 1464 'resized' => false, 1465 'size' => array( 1466 'width' => 1800, 1467 'height' => 1200, 1468 ), 1469 ), 1470 ), 1471 1472 // Image that will not be rotated - WebP Exif is not supported in PHP. 1473 array( 1474 DIR_TESTDATA . '/images/test-image-rotated-90cw.webp', 1475 array( 1024, 768 ), 1476 'image/webp', 1477 array( 1478 'rotated' => false, 1479 'resized' => false, 1480 'size' => array( 1481 'width' => 1024, 1482 'height' => 768, 1483 ), 1484 ), 1485 ), 1486 1487 ); 1488 } 1489 1490 /** 1491 * Test the `_wp_get_image_suffix()` function. 1492 * @dataProvider data_test__wp_get_image_suffix 1493 * 1494 * @ticket 55443 1495 */ 1496 public function test__wp_get_image_suffix( $resized, $rotated, $expected ) { 1497 $this->assertSame( $expected, _wp_get_image_suffix( $resized, $rotated ) ); 1498 } 1499 1500 /** 1501 * Data provider for the `test__wp_get_image_suffix()` test. 1502 */ 1503 public function data_test__wp_get_image_suffix() { 1504 return array( 1505 array( false, false, '' ), 1506 array( true, false, 'scaled' ), 1507 array( false, true, 'rotated' ), 1508 array( true, true, 'scaled' ), 1509 ); 1510 } 1029 1511 } -
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 /**