'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image', 'fields' => 'ids', 'posts_per_page' => 1, 'meta_query' => [ 'relation' => 'OR', [ 'key' => '_zeitfresser_media_optimized_version', 'compare' => 'NOT EXISTS', ], [ 'key' => '_zeitfresser_media_optimized_version', 'value' => ZEITFRESSER_IMAGE_OPTIMIZATION_VERSION, 'compare' => '!=', ], ], 'no_found_rows' => false, ]); return (int) $query->found_posts; } /** * Count total images */ function zeitfresser_get_total_images_count() { $query = new WP_Query([ 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image', 'fields' => 'ids', 'posts_per_page' => 1, 'no_found_rows' => false, ]); return (int) $query->found_posts; } /** * NEW: Cleanup counters (ONLY ADDITIVE) */ function zeitfresser_get_total_originals_count() { $query = new WP_Query([ 'post_type'=>'attachment', 'post_status'=>'inherit', 'post_mime_type'=>'image', 'posts_per_page'=>1, 'fields'=>'ids', 'meta_query'=>[ ['key'=>'_zeitfresser_original_file','compare'=>'EXISTS'] ], 'no_found_rows'=>false ]); return (int) $query->found_posts; } function zeitfresser_get_remaining_originals_count() { $query = new WP_Query([ 'post_type'=>'attachment', 'post_status'=>'inherit', 'post_mime_type'=>'image', 'posts_per_page'=>1, 'fields'=>'ids', 'meta_query'=>[ 'relation'=>'AND', ['key'=>'_zeitfresser_original_file','compare'=>'EXISTS'], ['key'=>'_zeitfresser_original_deleted','compare'=>'NOT EXISTS'] ], 'no_found_rows'=>false ]); return (int) $query->found_posts; } /** * DELETE ORIGINALS (UNCHANGED) */ function zeitfresser_delete_originals_batch( $batch_size = 10 ) { $deleted = 0; $query = new WP_Query([ 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image', 'fields' => 'ids', 'posts_per_page' => $batch_size, 'meta_query' => [ 'relation' => 'AND', [ 'key' => '_zeitfresser_original_file', 'compare' => 'EXISTS', ], [ 'key' => '_zeitfresser_original_deleted', 'compare' => 'NOT EXISTS', ], ], ]); foreach ( $query->posts as $attachment_id ) { $original = get_post_meta( $attachment_id, '_zeitfresser_original_file', true ); if ( ! $original ) { continue; } $optimized_version = get_post_meta( $attachment_id, '_zeitfresser_media_optimized_version', true ); if ( ZEITFRESSER_IMAGE_OPTIMIZATION_VERSION !== $optimized_version ) { continue; } $ext = strtolower( pathinfo( $original, PATHINFO_EXTENSION ) ); if ( in_array( $ext, [ 'webp', 'avif' ], true ) ) { update_post_meta( $attachment_id, '_zeitfresser_original_deleted', 1 ); continue; } if ( ! file_exists( $original ) ) { update_post_meta( $attachment_id, '_zeitfresser_original_deleted', 1 ); continue; } if ( ! is_writable( $original ) ) { continue; } if ( unlink( $original ) ) { $deleted++; update_post_meta( $attachment_id, '_zeitfresser_original_deleted', 1 ); } } return $deleted; } /** * Optimizer batch for manual processing. * * Manual optimization must work independently of the auto-optimize upload toggle. * * @param int $batch_size Number of images per batch. * @return array */ function zeitfresser_process_legacy_images_batch( $batch_size = 25 ) { $results = [ 'processed' => 0, 'updated' => 0, 'skipped' => 0, 'errors' => 0, ]; $query = new WP_Query([ 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => 'image', 'fields' => 'ids', 'posts_per_page' => $batch_size, 'meta_query' => [ 'relation' => 'OR', [ 'key' => '_zeitfresser_media_optimized_version', 'compare' => 'NOT EXISTS', ], [ 'key' => '_zeitfresser_media_optimized_version', 'value' => ZEITFRESSER_IMAGE_OPTIMIZATION_VERSION, 'compare' => '!=', ], ], ]); // Force optimization for manual tool runs, regardless of upload automation setting. $GLOBALS['zeitfresser_force_image_optimization'] = true; foreach ( $query->posts as $attachment_id ) { $results['processed']++; $file = get_attached_file( $attachment_id ); if ( empty( $file ) || ! file_exists( $file ) ) { update_post_meta( $attachment_id, '_zeitfresser_media_optimized_version', 'missing' ); $results['skipped']++; continue; } if ( ! get_post_meta( $attachment_id, '_zeitfresser_original_file', true ) ) { update_post_meta( $attachment_id, '_zeitfresser_original_file', $file ); } $metadata = wp_generate_attachment_metadata( $attachment_id, $file ); if ( is_wp_error( $metadata ) || empty( $metadata ) ) { $results['errors']++; continue; } wp_update_attachment_metadata( $attachment_id, $metadata ); update_post_meta( $attachment_id, '_zeitfresser_media_optimized_version', ZEITFRESSER_IMAGE_OPTIMIZATION_VERSION ); $results['updated']++; } unset( $GLOBALS['zeitfresser_force_image_optimization'] ); return $results; } /** * AJAX: Optimizer (extended output only) */ function zeitfresser_ajax_optimize_images() { if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error(); } check_ajax_referer( 'zeitfresser_performance_tools', 'nonce' ); $results = zeitfresser_process_legacy_images_batch( 25 ); wp_send_json_success([ 'processed' => $results['processed'], 'updated' => $results['updated'], 'pending' => zeitfresser_get_pending_legacy_images_count(), 'total' => zeitfresser_get_total_images_count(), ]); } add_action( 'wp_ajax_zeitfresser_optimize_images', 'zeitfresser_ajax_optimize_images' ); /** * AJAX: Delete (extended ONLY) */ function zeitfresser_ajax_delete_originals() { if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error(); } check_ajax_referer( 'zeitfresser_performance_tools', 'nonce' ); $deleted = zeitfresser_delete_originals_batch( 10 ); $total = zeitfresser_get_total_originals_count(); $remaining = zeitfresser_get_remaining_originals_count(); wp_send_json_success([ 'deleted' => $deleted, 'total' => $total, 'remaining' => $remaining, 'deleted_total' => $total - $remaining, ]); } add_action( 'wp_ajax_zeitfresser_delete_originals', 'zeitfresser_ajax_delete_originals' ); /** * Render UI */ function zeitfresser_render_performance_tools_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $pending = zeitfresser_get_pending_legacy_images_count(); $total = zeitfresser_get_total_images_count(); $optimized = $total - $pending; $progress = $total > 0 ? round(($optimized / $total) * 100) : 0; // ๐ฅ NEW: Cleanup counters $cleanup_total = zeitfresser_get_total_originals_count(); $cleanup_remaining = zeitfresser_get_remaining_originals_count(); $cleanup_deleted = $cleanup_total - $cleanup_remaining; $cleanup_progress = $cleanup_total > 0 ? round(($cleanup_deleted / $cleanup_total) * 100) : 0; ?>
How this tool works
This tool helps you optimize your existing media library for better performance.
โข Images are converted to modern formats (AVIF/WebP) for smaller file sizes.
โข The original file path is safely stored before optimization.
โข Once optimized, original images can be deleted to save disk space.
Automation:
โข You can enable automatic optimization on upload in the Customizer under Performance Tools Settings.
โข Optionally, original images can also be deleted automatically after successful optimization.
Safety:
โข Images are only processed once per version.
โข Original files are only deleted when safe.
โข The tool can be run multiple times without side effects.
Tip: You can either automate the process via the Customizer or use this tool manually for full control.
Total Images:
Optimized:
Pending:
Progress: %
Total Originals:
Deleted:
Remaining:
Cleanup Progress: %
๐ Optimizer: Idle
๐งน Cleanup: Idle