26 $src_file = $src; |
26 $src_file = $src; |
27 if ( is_numeric( $src ) ) { // Handle int as attachment ID. |
27 if ( is_numeric( $src ) ) { // Handle int as attachment ID. |
28 $src_file = get_attached_file( $src ); |
28 $src_file = get_attached_file( $src ); |
29 |
29 |
30 if ( ! file_exists( $src_file ) ) { |
30 if ( ! file_exists( $src_file ) ) { |
31 // If the file doesn't exist, attempt a URL fopen on the src link. |
31 /* |
32 // This can occur with certain file replication plugins. |
32 * If the file doesn't exist, attempt a URL fopen on the src link. |
|
33 * This can occur with certain file replication plugins. |
|
34 */ |
33 $src = _load_image_to_edit_path( $src, 'full' ); |
35 $src = _load_image_to_edit_path( $src, 'full' ); |
34 } else { |
36 } else { |
35 $src = $src_file; |
37 $src = $src_file; |
36 } |
38 } |
37 } |
39 } |
157 function wp_update_image_subsizes( $attachment_id ) { |
159 function wp_update_image_subsizes( $attachment_id ) { |
158 $image_meta = wp_get_attachment_metadata( $attachment_id ); |
160 $image_meta = wp_get_attachment_metadata( $attachment_id ); |
159 $image_file = wp_get_original_image_path( $attachment_id ); |
161 $image_file = wp_get_original_image_path( $attachment_id ); |
160 |
162 |
161 if ( empty( $image_meta ) || ! is_array( $image_meta ) ) { |
163 if ( empty( $image_meta ) || ! is_array( $image_meta ) ) { |
162 // Previously failed upload? |
164 /* |
163 // If there is an uploaded file, make all sub-sizes and generate all of the attachment meta. |
165 * Previously failed upload? |
|
166 * If there is an uploaded file, make all sub-sizes and generate all of the attachment meta. |
|
167 */ |
164 if ( ! empty( $image_file ) ) { |
168 if ( ! empty( $image_file ) ) { |
165 $image_meta = wp_create_image_subsizes( $image_file, $attachment_id ); |
169 $image_meta = wp_create_image_subsizes( $image_file, $attachment_id ); |
166 } else { |
170 } else { |
167 return new WP_Error( 'invalid_attachment', __( 'The attached file cannot be found.' ) ); |
171 return new WP_Error( 'invalid_attachment', __( 'The attached file cannot be found.' ) ); |
168 } |
172 } |
209 $image_meta['height'] = $saved_data['height']; |
214 $image_meta['height'] = $saved_data['height']; |
210 |
215 |
211 // Make the file path relative to the upload dir. |
216 // Make the file path relative to the upload dir. |
212 $image_meta['file'] = _wp_relative_upload_path( $new_file ); |
217 $image_meta['file'] = _wp_relative_upload_path( $new_file ); |
213 |
218 |
|
219 // Add image file size. |
|
220 $image_meta['filesize'] = wp_filesize( $new_file ); |
|
221 |
214 // Store the original image file name in image_meta. |
222 // Store the original image file name in image_meta. |
215 $image_meta['original_image'] = wp_basename( $original_file ); |
223 $image_meta['original_image'] = wp_basename( $original_file ); |
216 |
|
217 // Add image file size. |
|
218 $image_meta['filesize'] = wp_filesize( $new_file ); |
|
219 |
224 |
220 return $image_meta; |
225 return $image_meta; |
221 } |
226 } |
222 |
227 |
223 /** |
228 /** |
280 * @param string $file Full path to the uploaded image file. |
285 * @param string $file Full path to the uploaded image file. |
281 * @param int $attachment_id Attachment post ID. |
286 * @param int $attachment_id Attachment post ID. |
282 */ |
287 */ |
283 $threshold = (int) apply_filters( 'big_image_size_threshold', 2560, $imagesize, $file, $attachment_id ); |
288 $threshold = (int) apply_filters( 'big_image_size_threshold', 2560, $imagesize, $file, $attachment_id ); |
284 |
289 |
285 // If the original image's dimensions are over the threshold, |
290 /* |
286 // scale the image and use it as the "full" size. |
291 * If the original image's dimensions are over the threshold, |
|
292 * scale the image and use it as the "full" size. |
|
293 */ |
287 if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) { |
294 if ( $threshold && ( $image_meta['width'] > $threshold || $image_meta['height'] > $threshold ) ) { |
288 $editor = wp_get_image_editor( $file ); |
295 $editor = wp_get_image_editor( $file ); |
289 |
296 |
290 if ( is_wp_error( $editor ) ) { |
297 if ( is_wp_error( $editor ) ) { |
291 // This image cannot be edited. |
298 // This image cannot be edited. |
301 $resized = $editor->maybe_exif_rotate(); |
308 $resized = $editor->maybe_exif_rotate(); |
302 $rotated = $resized; |
309 $rotated = $resized; |
303 } |
310 } |
304 |
311 |
305 if ( ! is_wp_error( $resized ) ) { |
312 if ( ! is_wp_error( $resized ) ) { |
306 // Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg". |
313 /* |
307 // This doesn't affect the sub-sizes names as they are generated from the original image (for best quality). |
314 * Append "-scaled" to the image file name. It will look like "my_image-scaled.jpg". |
|
315 * This doesn't affect the sub-sizes names as they are generated from the original image (for best quality). |
|
316 */ |
308 $saved = $editor->save( $editor->generate_filename( 'scaled' ) ); |
317 $saved = $editor->save( $editor->generate_filename( 'scaled' ) ); |
309 |
318 |
310 if ( ! is_wp_error( $saved ) ) { |
319 if ( ! is_wp_error( $saved ) ) { |
311 $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id ); |
320 $image_meta = _wp_image_meta_replace_original( $saved, $file, $image_meta, $attachment_id ); |
312 |
321 |
472 |
481 |
473 return $image_meta; |
482 return $image_meta; |
474 } |
483 } |
475 |
484 |
476 /** |
485 /** |
477 * Generate attachment meta data and create image sub-sizes for images. |
486 * Copy parent attachment properties to newly cropped image. |
|
487 * |
|
488 * @since 6.5.0 |
|
489 * |
|
490 * @param string $cropped Path to the cropped image file. |
|
491 * @param int $parent_attachment_id Parent file Attachment ID. |
|
492 * @param string $context Control calling the function. |
|
493 * @return array Properties of attachment. |
|
494 */ |
|
495 function wp_copy_parent_attachment_properties( $cropped, $parent_attachment_id, $context = '' ) { |
|
496 $parent = get_post( $parent_attachment_id ); |
|
497 $parent_url = wp_get_attachment_url( $parent->ID ); |
|
498 $parent_basename = wp_basename( $parent_url ); |
|
499 $url = str_replace( wp_basename( $parent_url ), wp_basename( $cropped ), $parent_url ); |
|
500 |
|
501 $size = wp_getimagesize( $cropped ); |
|
502 $image_type = $size ? $size['mime'] : 'image/jpeg'; |
|
503 |
|
504 $sanitized_post_title = sanitize_file_name( $parent->post_title ); |
|
505 $use_original_title = ( |
|
506 ( '' !== trim( $parent->post_title ) ) && |
|
507 /* |
|
508 * Check if the original image has a title other than the "filename" default, |
|
509 * meaning the image had a title when originally uploaded or its title was edited. |
|
510 */ |
|
511 ( $parent_basename !== $sanitized_post_title ) && |
|
512 ( pathinfo( $parent_basename, PATHINFO_FILENAME ) !== $sanitized_post_title ) |
|
513 ); |
|
514 $use_original_description = ( '' !== trim( $parent->post_content ) ); |
|
515 |
|
516 $attachment = array( |
|
517 'post_title' => $use_original_title ? $parent->post_title : wp_basename( $cropped ), |
|
518 'post_content' => $use_original_description ? $parent->post_content : $url, |
|
519 'post_mime_type' => $image_type, |
|
520 'guid' => $url, |
|
521 'context' => $context, |
|
522 ); |
|
523 |
|
524 // Copy the image caption attribute (post_excerpt field) from the original image. |
|
525 if ( '' !== trim( $parent->post_excerpt ) ) { |
|
526 $attachment['post_excerpt'] = $parent->post_excerpt; |
|
527 } |
|
528 |
|
529 // Copy the image alt text attribute from the original image. |
|
530 if ( '' !== trim( $parent->_wp_attachment_image_alt ) ) { |
|
531 $attachment['meta_input'] = array( |
|
532 '_wp_attachment_image_alt' => wp_slash( $parent->_wp_attachment_image_alt ), |
|
533 ); |
|
534 } |
|
535 |
|
536 $attachment['post_parent'] = $parent_attachment_id; |
|
537 |
|
538 return $attachment; |
|
539 } |
|
540 |
|
541 /** |
|
542 * Generates attachment meta data and create image sub-sizes for images. |
478 * |
543 * |
479 * @since 2.1.0 |
544 * @since 2.1.0 |
|
545 * @since 6.0.0 The `$filesize` value was added to the returned array. |
480 * |
546 * |
481 * @param int $attachment_id Attachment ID to process. |
547 * @param int $attachment_id Attachment ID to process. |
482 * @param string $file Filepath of the attached image. |
548 * @param string $file Filepath of the attached image. |
483 * @return array Metadata for attachment. |
549 * @return array Metadata for attachment. |
484 */ |
550 */ |
688 if ( ! is_numeric( $numerator ) || ! is_numeric( $denominator ) ) { |
754 if ( ! is_numeric( $numerator ) || ! is_numeric( $denominator ) ) { |
689 return 0; |
755 return 0; |
690 } |
756 } |
691 |
757 |
692 // The denominator must not be zero. |
758 // The denominator must not be zero. |
693 if ( 0 == $denominator ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison -- Deliberate loose comparison. |
759 if ( 0 == $denominator ) { // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual -- Deliberate loose comparison. |
694 return 0; |
760 return 0; |
695 } |
761 } |
696 |
762 |
697 return $numerator / $denominator; |
763 return $numerator / $denominator; |
698 } |
764 } |
699 |
765 |
700 /** |
766 /** |
701 * Convert the exif date format to a unix timestamp. |
767 * Converts the exif date format to a unix timestamp. |
702 * |
768 * |
703 * @since 2.5.0 |
769 * @since 2.5.0 |
704 * |
770 * |
705 * @param string $str A date string expected to be in Exif format (Y:m:d H:i:s). |
771 * @param string $str A date string expected to be in Exif format (Y:m:d H:i:s). |
706 * @return int|false The unix timestamp, or false on failure. |
772 * @return int|false The unix timestamp, or false on failure. |
711 |
777 |
712 return strtotime( "{$y}-{$m}-{$d} {$time}" ); |
778 return strtotime( "{$y}-{$m}-{$d} {$time}" ); |
713 } |
779 } |
714 |
780 |
715 /** |
781 /** |
716 * Get extended image metadata, exif or iptc as available. |
782 * Gets extended image metadata, exif or iptc as available. |
717 * |
783 * |
718 * Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso |
784 * Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso |
719 * created_timestamp, focal_length, shutter_speed, and title. |
785 * created_timestamp, focal_length, shutter_speed, and title. |
720 * |
786 * |
721 * The IPTC metadata that is retrieved is APP13, credit, byline, created date |
787 * The IPTC metadata that is retrieved is APP13, credit, byline, created date |
770 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
836 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
771 && ! defined( 'WP_RUN_CORE_TESTS' ) |
837 && ! defined( 'WP_RUN_CORE_TESTS' ) |
772 ) { |
838 ) { |
773 $iptc = iptcparse( $info['APP13'] ); |
839 $iptc = iptcparse( $info['APP13'] ); |
774 } else { |
840 } else { |
775 // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
841 // Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
776 $iptc = @iptcparse( $info['APP13'] ); |
842 $iptc = @iptcparse( $info['APP13'] ); |
777 } |
843 } |
778 |
844 |
779 if ( ! is_array( $iptc ) ) { |
845 if ( ! is_array( $iptc ) ) { |
780 $iptc = array(); |
846 $iptc = array(); |
843 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
909 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
844 && ! defined( 'WP_RUN_CORE_TESTS' ) |
910 && ! defined( 'WP_RUN_CORE_TESTS' ) |
845 ) { |
911 ) { |
846 $exif = exif_read_data( $file ); |
912 $exif = exif_read_data( $file ); |
847 } else { |
913 } else { |
848 // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
914 // Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
849 $exif = @exif_read_data( $file ); |
915 $exif = @exif_read_data( $file ); |
850 } |
916 } |
851 |
917 |
852 if ( ! is_array( $exif ) ) { |
918 if ( ! is_array( $exif ) ) { |
853 $exif = array(); |
919 $exif = array(); |
854 } |
920 } |
855 |
921 |
|
922 $exif_description = ''; |
|
923 $exif_usercomment = ''; |
856 if ( ! empty( $exif['ImageDescription'] ) ) { |
924 if ( ! empty( $exif['ImageDescription'] ) ) { |
|
925 $exif_description = trim( $exif['ImageDescription'] ); |
|
926 } |
|
927 |
|
928 if ( ! empty( $exif['COMPUTED']['UserComment'] ) ) { |
|
929 $exif_usercomment = trim( $exif['COMPUTED']['UserComment'] ); |
|
930 } |
|
931 |
|
932 if ( $exif_description ) { |
857 mbstring_binary_safe_encoding(); |
933 mbstring_binary_safe_encoding(); |
858 $description_length = strlen( $exif['ImageDescription'] ); |
934 $description_length = strlen( $exif_description ); |
859 reset_mbstring_encoding(); |
935 reset_mbstring_encoding(); |
860 |
|
861 if ( empty( $meta['title'] ) && $description_length < 80 ) { |
936 if ( empty( $meta['title'] ) && $description_length < 80 ) { |
862 // Assume the title is stored in ImageDescription. |
937 // Assume the title is stored in ImageDescription. |
863 $meta['title'] = trim( $exif['ImageDescription'] ); |
938 $meta['title'] = $exif_description; |
864 } |
939 } |
865 |
940 |
866 if ( empty( $meta['caption'] ) && ! empty( $exif['COMPUTED']['UserComment'] ) ) { |
941 // If both user comments and description are present. |
867 $meta['caption'] = trim( $exif['COMPUTED']['UserComment'] ); |
942 if ( empty( $meta['caption'] ) && $exif_description && $exif_usercomment ) { |
|
943 if ( ! empty( $meta['title'] ) && $exif_description === $meta['title'] ) { |
|
944 $caption = $exif_usercomment; |
|
945 } else { |
|
946 if ( $exif_description === $exif_usercomment ) { |
|
947 $caption = $exif_description; |
|
948 } else { |
|
949 $caption = trim( $exif_description . ' ' . $exif_usercomment ); |
|
950 } |
|
951 } |
|
952 $meta['caption'] = $caption; |
|
953 } |
|
954 |
|
955 if ( empty( $meta['caption'] ) && $exif_usercomment ) { |
|
956 $meta['caption'] = $exif_usercomment; |
868 } |
957 } |
869 |
958 |
870 if ( empty( $meta['caption'] ) ) { |
959 if ( empty( $meta['caption'] ) ) { |
871 $meta['caption'] = trim( $exif['ImageDescription'] ); |
960 $meta['caption'] = $exif_description; |
|
961 } |
|
962 } elseif ( empty( $meta['caption'] ) && $exif_usercomment ) { |
|
963 $meta['caption'] = $exif_usercomment; |
|
964 $description_length = strlen( $exif_usercomment ); |
|
965 if ( empty( $meta['title'] ) && $description_length < 80 ) { |
|
966 $meta['title'] = trim( $exif_usercomment ); |
872 } |
967 } |
873 } elseif ( empty( $meta['caption'] ) && ! empty( $exif['Comments'] ) ) { |
968 } elseif ( empty( $meta['caption'] ) && ! empty( $exif['Comments'] ) ) { |
874 $meta['caption'] = trim( $exif['Comments'] ); |
969 $meta['caption'] = trim( $exif['Comments'] ); |
875 } |
970 } |
876 |
971 |
941 * @param int $image_type Type of image, one of the `IMAGETYPE_XXX` constants. |
1036 * @param int $image_type Type of image, one of the `IMAGETYPE_XXX` constants. |
942 * @param array $iptc IPTC data. |
1037 * @param array $iptc IPTC data. |
943 * @param array $exif EXIF data. |
1038 * @param array $exif EXIF data. |
944 */ |
1039 */ |
945 return apply_filters( 'wp_read_image_metadata', $meta, $file, $image_type, $iptc, $exif ); |
1040 return apply_filters( 'wp_read_image_metadata', $meta, $file, $image_type, $iptc, $exif ); |
946 |
1041 } |
947 } |
1042 |
948 |
1043 /** |
949 /** |
1044 * Validates that file is an image. |
950 * Validate that file is an image. |
|
951 * |
1045 * |
952 * @since 2.5.0 |
1046 * @since 2.5.0 |
953 * |
1047 * |
954 * @param string $path File path to test if valid image. |
1048 * @param string $path File path to test if valid image. |
955 * @return bool True if valid image, false if not valid image. |
1049 * @return bool True if valid image, false if not valid image. |
958 $size = wp_getimagesize( $path ); |
1052 $size = wp_getimagesize( $path ); |
959 return ! empty( $size ); |
1053 return ! empty( $size ); |
960 } |
1054 } |
961 |
1055 |
962 /** |
1056 /** |
963 * Validate that file is suitable for displaying within a web page. |
1057 * Validates that file is suitable for displaying within a web page. |
964 * |
1058 * |
965 * @since 2.5.0 |
1059 * @since 2.5.0 |
966 * |
1060 * |
967 * @param string $path File path to test. |
1061 * @param string $path File path to test. |
968 * @return bool True if suitable, false if not suitable. |
1062 * @return bool True if suitable, false if not suitable. |
969 */ |
1063 */ |
970 function file_is_displayable_image( $path ) { |
1064 function file_is_displayable_image( $path ) { |
971 $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP ); |
1065 $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP, IMAGETYPE_AVIF ); |
972 |
1066 |
973 $info = wp_getimagesize( $path ); |
1067 $info = wp_getimagesize( $path ); |
974 if ( empty( $info ) ) { |
1068 if ( empty( $info ) ) { |
975 $result = false; |
1069 $result = false; |
976 } elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) { |
1070 } elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) { |