From e1f7db91f84b0f98806349710e85add0e5f5bfb9 Mon Sep 17 00:00:00 2001 From: Dome Date: Sat, 25 Apr 2026 10:19:33 +0200 Subject: [PATCH] fix(performance): delete all original image subsizes during cleanup - Extend cleanup logic to remove full original image family (including subsizes) - Fix issue where only the main original file was deleted - Ensure consistent behavior for both manual batch processing and auto-delete - Improve cleanup safety by validating optimization state before deletion --- functions.php | 15 ++--- inc/performance-tools.php | 125 +++++++++++++++++++++++++++++++++++--- 2 files changed, 126 insertions(+), 14 deletions(-) diff --git a/functions.php b/functions.php index ba85a7e..1a04c69 100644 --- a/functions.php +++ b/functions.php @@ -558,12 +558,10 @@ add_filter( function zeitfresser_auto_delete_original_after_upload( $metadata, $attachment_id ) { - // 🔒 only images if ( ! wp_attachment_is_image( $attachment_id ) ) { return $metadata; } - // 🔒 feature toggles if ( ! get_theme_mod( 'ztfr_auto_optimize', true ) ) { return $metadata; } @@ -578,11 +576,10 @@ function zeitfresser_auto_delete_original_after_upload( $metadata, $attachment_i true ); - if ( ! $original || ! file_exists( $original ) ) { + if ( ! $original ) { return $metadata; } - // skip modern formats $ext = strtolower( pathinfo( $original, PATHINFO_EXTENSION ) ); if ( in_array( $ext, [ 'webp', 'avif' ], true ) ) { @@ -590,12 +587,16 @@ function zeitfresser_auto_delete_original_after_upload( $metadata, $attachment_i return $metadata; } - if ( ! is_writable( $original ) ) { + // If nothing remains, mark as completed. + if ( ! zeitfresser_original_family_exists( $attachment_id, $original ) ) { + update_post_meta( $attachment_id, '_zeitfresser_original_deleted', 1 ); return $metadata; } - // 🔥 delete original - if ( unlink( $original ) ) { + zeitfresser_delete_original_family_files( $attachment_id, $original ); + + // Only mark as deleted when all original-format files are gone. + if ( ! zeitfresser_original_family_exists( $attachment_id, $original ) ) { update_post_meta( $attachment_id, '_zeitfresser_original_deleted', 1 ); } diff --git a/inc/performance-tools.php b/inc/performance-tools.php index 1359d34..dcb8cbf 100644 --- a/inc/performance-tools.php +++ b/inc/performance-tools.php @@ -103,7 +103,118 @@ function zeitfresser_get_remaining_originals_count() { } /** - * DELETE ORIGINALS (UNCHANGED) + * Build a list of original-format files belonging to one attachment. + * + * This includes: + * - the original uploaded file + * - the original-format main generated file (e.g. scaled JPG) + * - original-format sub-size files derived from attachment metadata + * + * @param int $attachment_id Attachment ID. + * @param string $original Absolute path to the original uploaded file. + * @return array + */ +function zeitfresser_get_original_family_files( $attachment_id, $original ) { + + $files = []; + + if ( empty( $original ) ) { + return $files; + } + + $original_ext = strtolower( pathinfo( $original, PATHINFO_EXTENSION ) ); + + if ( empty( $original_ext ) ) { + return $files; + } + + $files[] = $original; + + $metadata = wp_get_attachment_metadata( $attachment_id ); + $upload_dir = wp_get_upload_dir(); + + if ( ! empty( $metadata['file'] ) ) { + $current_main_absolute = trailingslashit( $upload_dir['basedir'] ) . $metadata['file']; + + $files[] = preg_replace( + '/\.[^.]+$/', + '.' . $original_ext, + $current_main_absolute + ); + + $current_dir = dirname( $current_main_absolute ); + + if ( ! empty( $metadata['sizes'] ) && is_array( $metadata['sizes'] ) ) { + foreach ( $metadata['sizes'] as $size ) { + if ( empty( $size['file'] ) ) { + continue; + } + + $files[] = $current_dir . '/' . preg_replace( + '/\.[^.]+$/', + '.' . $original_ext, + $size['file'] + ); + } + } + } + + $files = array_unique( array_filter( $files ) ); + + return array_values( $files ); +} + +/** + * Check whether any original-format family files still exist. + * + * @param int $attachment_id Attachment ID. + * @param string $original Absolute path to the original uploaded file. + * @return bool + */ +function zeitfresser_original_family_exists( $attachment_id, $original ) { + + $files = zeitfresser_get_original_family_files( $attachment_id, $original ); + + foreach ( $files as $file ) { + if ( file_exists( $file ) ) { + return true; + } + } + + return false; +} + +/** + * Delete all original-format files belonging to one attachment. + * + * @param int $attachment_id Attachment ID. + * @param string $original Absolute path to the original uploaded file. + * @return int Number of deleted files. + */ +function zeitfresser_delete_original_family_files( $attachment_id, $original ) { + + $deleted_files = 0; + $files = zeitfresser_get_original_family_files( $attachment_id, $original ); + + foreach ( $files as $file ) { + if ( ! file_exists( $file ) ) { + continue; + } + + if ( ! is_writable( $file ) ) { + continue; + } + + if ( unlink( $file ) ) { + $deleted_files++; + } + } + + return $deleted_files; +} + +/** + * DELETE ORIGINALS (manual batch) */ function zeitfresser_delete_originals_batch( $batch_size = 10 ) { @@ -115,7 +226,7 @@ function zeitfresser_delete_originals_batch( $batch_size = 10 ) { 'post_mime_type' => 'image', 'fields' => 'ids', 'posts_per_page' => $batch_size, - 'meta_query' => [ + 'meta_query' => [ 'relation' => 'AND', [ 'key' => '_zeitfresser_original_file', @@ -153,16 +264,16 @@ function zeitfresser_delete_originals_batch( $batch_size = 10 ) { continue; } - if ( ! file_exists( $original ) ) { + // Nothing left to delete -> mark as done. + if ( ! zeitfresser_original_family_exists( $attachment_id, $original ) ) { update_post_meta( $attachment_id, '_zeitfresser_original_deleted', 1 ); continue; } - if ( ! is_writable( $original ) ) { - continue; - } + zeitfresser_delete_original_family_files( $attachment_id, $original ); - if ( unlink( $original ) ) { + // Only mark as deleted when the full original family is gone. + if ( ! zeitfresser_original_family_exists( $attachment_id, $original ) ) { $deleted++; update_post_meta( $attachment_id, '_zeitfresser_original_deleted', 1 ); }