| @@ -731,8 +731,17 @@ | ||
| 731 | 731 | ]; |
| 732 | 732 | } |
| 733 | 733 | } |
| 734 | 734 | |
| 735 | + if ( ! empty( $extras['additional_files'] ) ) { | |
| 736 | + foreach ( $extras['additional_files'] as $name => $data ) { | |
| 737 | + $files[ $name ] = [ | |
| 738 | + 'key' => $data['key'] ?? null, | |
| 739 | + 'path' => $data['source_path'] ?? null, | |
| 740 | + ]; | |
| 741 | + } | |
| 742 | + } | |
| 743 | + | |
| 735 | 744 | // ALL files |
| 736 | 745 | if ( $all ) { |
| 737 | 746 | $results = []; |
| 738 | 747 | |
| @@ -795,9 +804,9 @@ | ||
| 795 | 804 | return empty( array_diff( $expected_backup, $restored_backup ) ); |
| 796 | 805 | } |
| 797 | 806 | |
| 798 | 807 | /** |
| 799 | - * File labels (full, original, each named size) a given item row is expected to have. | |
| 808 | + * File labels (full, original, each named size, each additional file) a given item row is expected to have. | |
| 800 | 809 | */ |
| 801 | 810 | private function expected_restore_labels( $item_row ) { |
| 802 | 811 | $expected = [ 'full' ]; |
| 803 | 812 | if ( ! empty( $item_row['original_key'] ) || ! empty( $item_row['original_source_path'] ) ) { |
| @@ -807,8 +816,11 @@ | ||
| 807 | 816 | $extras = ! empty( $item_row['extra'] ) ? Utils::maybe_unserialize( $item_row['extra'] ) : []; |
| 808 | 817 | if ( ! empty( $extras['sizes'] ) ) { |
| 809 | 818 | $expected = array_merge( $expected, array_keys( $extras['sizes'] ) ); |
| 810 | 819 | } |
| 820 | + if ( ! empty( $extras['additional_files'] ) ) { | |
| 821 | + $expected = array_merge( $expected, array_keys( $extras['additional_files'] ) ); | |
| 822 | + } | |
| 811 | 823 | |
| 812 | 824 | return $expected; |
| 813 | 825 | } |
| 814 | 826 | |
| @@ -865,9 +877,9 @@ | ||
| 865 | 877 | return true; |
| 866 | 878 | } |
| 867 | 879 | |
| 868 | 880 | $extras = $this->get_extras( $source_id, false, $source_type ) ?: []; |
| 869 | - | |
| 881 | + | |
| 870 | 882 | // 3. Check sizes |
| 871 | 883 | if ( ! empty( $extras['sizes'] ) ) { |
| 872 | 884 | foreach ( $extras['sizes'] as $size ) { |
| 873 | 885 | if ( |
| @@ -885,8 +897,27 @@ | ||
| 885 | 897 | } |
| 886 | 898 | } |
| 887 | 899 | } |
| 888 | 900 | |
| 901 | + // 4. Check additional files (HEIC source, animated-GIF video/poster) | |
| 902 | + if ( ! empty( $extras['additional_files'] ) ) { | |
| 903 | + foreach ( $extras['additional_files'] as $additional_file ) { | |
| 904 | + if ( | |
| 905 | + isset( $additional_file['source_path'] ) && | |
| 906 | + ! empty( $additional_file['source_path'] ) && | |
| 907 | + $additional_file['source_path'] === $source_path && | |
| 908 | + $this->move_to_server_by_key_and_path( | |
| 909 | + $additional_file['key'] ?? null, | |
| 910 | + $additional_file['source_path'], | |
| 911 | + $source_id, | |
| 912 | + $source_type | |
| 913 | + ) | |
| 914 | + ) { | |
| 915 | + return true; | |
| 916 | + } | |
| 917 | + } | |
| 918 | + } | |
| 919 | + | |
| 889 | 920 | return false; |
| 890 | 921 | } |
| 891 | 922 | |
| 892 | 923 | /** |
| @@ -979,8 +1010,19 @@ | ||
| 979 | 1010 | } |
| 980 | 1011 | |
| 981 | 1012 | if ( |
| 982 | 1013 | isset($extras) && !empty($extras) && |
| 1014 | + isset($extras['additional_files']) && !empty($extras['additional_files']) | |
| 1015 | + ) { | |
| 1016 | + foreach ($extras['additional_files'] as $file) { | |
| 1017 | + if (isset($file['key']) && !empty($file['key'])) { | |
| 1018 | + Service::instance()->deleteSingle($file['key']); | |
| 1019 | + } | |
| 1020 | + } | |
| 1021 | + } | |
| 1022 | + | |
| 1023 | + if ( | |
| 1024 | + isset($extras) && !empty($extras) && | |
| 983 | 1025 | isset($extras['backup']) && !empty($extras['backup']) && |
| 984 | 1026 | $delete_backup |
| 985 | 1027 | ) { |
| 986 | 1028 | $backup = Utils::maybe_unserialize($extras['backup']); |
| @@ -1220,8 +1262,32 @@ | ||
| 1220 | 1262 | ) { |
| 1221 | 1263 | foreach ($extras['sizes'] as $sub_image) { |
| 1222 | 1264 | if (isset($sub_image['source_path']) && !empty($sub_image['source_path'])) { |
| 1223 | 1265 | $file = trailingslashit($upload_dir['basedir']) . $sub_image['source_path']; |
| 1266 | + if(file_exists($file)) { | |
| 1267 | + $files_to_remove[] = $file; | |
| 1268 | + } | |
| 1269 | + } | |
| 1270 | + } | |
| 1271 | + } | |
| 1272 | + if ( | |
| 1273 | + isset($extras) && !empty($extras) && | |
| 1274 | + isset($extras['additional_files']) && !empty($extras['additional_files']) | |
| 1275 | + ) { | |
| 1276 | + // animated_video/animated_video_poster are resolved client-side by slicing | |
| 1277 | + // the main image's own (possibly presigned) source_url down to its directory | |
| 1278 | + // and appending the file's filename — verified in WP core's shipped JS | |
| 1279 | + // (block-library.js). That trick drops any presigned-URL query string, so for | |
| 1280 | + // a private item it produces an unsigned request to a private S3 key, which | |
| 1281 | + // fails once the local copy is gone. Keep these two local for private items; | |
| 1282 | + // source_image is unaffected (never fetched by any client, private or not). | |
| 1283 | + $unsafe_when_private = ['animated_video', 'animated_video_poster']; | |
| 1284 | + foreach ($extras['additional_files'] as $name => $additional_file) { | |
| 1285 | + if (!empty($item['is_private']) && in_array($name, $unsafe_when_private, true)) { | |
| 1286 | + continue; | |
| 1287 | + } | |
| 1288 | + if (isset($additional_file['source_path']) && !empty($additional_file['source_path'])) { | |
| 1289 | + $file = trailingslashit($upload_dir['basedir']) . $additional_file['source_path']; | |
| 1224 | 1290 | if(file_exists($file)) { |
| 1225 | 1291 | $files_to_remove[] = $file; |
| 1226 | 1292 | } |
| 1227 | 1293 | } |