post_type !== 'attachment' ) { return array( 'success' => false, 'message' => __( 'Invalid attachment', 'ai-thumbnails-maker' ), 'attachment_id' => $attachment_id, ); } // Check if it's an image if ( ! wp_attachment_is_image( $attachment_id ) ) { return array( 'success' => false, 'message' => __( 'Attachment is not an image', 'ai-thumbnails-maker' ), 'attachment_id' => $attachment_id, 'title' => $attachment->post_title, ); } // Get fullsize image path $fullsizepath = get_attached_file( $attachment_id ); if ( ! $fullsizepath || ! file_exists( $fullsizepath ) ) { return array( 'success' => false, 'message' => __( 'Original image file not found', 'ai-thumbnails-maker' ), 'attachment_id' => $attachment_id, 'title' => $attachment->post_title, ); } // Parse options $only_missing = isset( $options['only_missing'] ) ? (bool) $options['only_missing'] : true; $delete_old = isset( $options['delete_old'] ) ? (bool) $options['delete_old'] : false; // Get old metadata before regeneration $old_metadata = wp_get_attachment_metadata( $attachment_id ); // Filter to skip existing thumbnails if needed if ( $only_missing ) { add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_only_missing_sizes' ), 10, 3 ); $this->old_metadata = $old_metadata; $this->skipped_sizes = array(); $this->current_att_id = $attachment_id; } // Regenerate thumbnails require_once ABSPATH . 'wp-admin/includes/image.php'; $new_metadata = wp_generate_attachment_metadata( $attachment_id, $fullsizepath ); // Restore skipped thumbnails if ( $only_missing ) { foreach ( $this->skipped_sizes as $skipped_size ) { if ( ! empty( $old_metadata['sizes'][ $skipped_size ] ) ) { $new_metadata['sizes'][ $skipped_size ] = $old_metadata['sizes'][ $skipped_size ]; } } remove_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_only_missing_sizes' ), 10 ); } // Delete old unregistered thumbnails if ( $delete_old ) { $this->delete_old_thumbnails( $attachment_id, $old_metadata, $new_metadata ); } // Update metadata wp_update_attachment_metadata( $attachment_id, $new_metadata ); // Count generated sizes $sizes_generated = isset( $new_metadata['sizes'] ) ? count( $new_metadata['sizes'] ) : 0; return array( 'success' => true, 'message' => __( 'Thumbnails regenerated successfully', 'ai-thumbnails-maker' ), 'attachment_id' => $attachment_id, 'title' => $attachment->post_title, 'sizes_generated' => $sizes_generated, 'thumbnail_url' => wp_get_attachment_image_url( $attachment_id, 'thumbnail' ), ); } /** * Old metadata for comparison * * @var array */ private $old_metadata = array(); /** * Skipped thumbnail sizes * * @var array */ private $skipped_sizes = array(); /** * Current attachment ID being processed * * @var int */ private $current_att_id = 0; /** * Filter to only regenerate missing thumbnail sizes * * @param array $sizes Array of thumbnail sizes. * @param array $metadata Current attachment metadata. * @param int $attachment_id Attachment ID. * @return array Filtered sizes. */ public function filter_only_missing_sizes( $sizes, $metadata, $attachment_id ) { if ( $attachment_id !== $this->current_att_id ) { return $sizes; } if ( empty( $this->old_metadata['sizes'] ) || ! is_array( $this->old_metadata['sizes'] ) ) { return $sizes; } foreach ( $sizes as $size_name => $size_data ) { // Check if this size already exists if ( isset( $this->old_metadata['sizes'][ $size_name ] ) ) { $old_size = $this->old_metadata['sizes'][ $size_name ]; // Check if dimensions match if ( isset( $old_size['width'], $old_size['height'] ) && $old_size['width'] == $size_data['width'] && $old_size['height'] == $size_data['height'] ) { // Check if file exists $upload_dir = wp_upload_dir(); $file_path = path_join( $upload_dir['basedir'], dirname( $this->old_metadata['file'] ) ); $file_path = path_join( $file_path, $old_size['file'] ); if ( file_exists( $file_path ) ) { // Skip this size $this->skipped_sizes[] = $size_name; unset( $sizes[ $size_name ] ); } } } } return $sizes; } /** * Delete old unregistered thumbnail files * * @param int $attachment_id Attachment ID. * @param array $old_metadata Old metadata. * @param array $new_metadata New metadata. */ private function delete_old_thumbnails( $attachment_id, $old_metadata, $new_metadata ) { if ( empty( $old_metadata['sizes'] ) ) { return; } $registered_sizes = get_intermediate_image_sizes(); $upload_dir = wp_upload_dir(); $file_path = path_join( $upload_dir['basedir'], dirname( $old_metadata['file'] ) ); foreach ( $old_metadata['sizes'] as $size_name => $size_data ) { // Skip if size is still registered if ( in_array( $size_name, $registered_sizes, true ) ) { continue; } // Delete the file $old_file = path_join( $file_path, $size_data['file'] ); if ( file_exists( $old_file ) ) { wp_delete_file( $old_file ); } } } /** * Get all registered thumbnail sizes * * @return array List of thumbnail sizes. */ public function get_registered_sizes() { global $_wp_additional_image_sizes; $sizes = array(); // Get default WordPress sizes $default_sizes = array( 'thumbnail', 'medium', 'medium_large', 'large' ); foreach ( $default_sizes as $size_name ) { $width = get_option( $size_name . '_size_w' ); $height = get_option( $size_name . '_size_h' ); $crop = get_option( $size_name . '_crop' ); if ( ! $width && ! $height ) { continue; } $sizes[ $size_name ] = array( 'label' => ucfirst( str_replace( '_', ' ', $size_name ) ), 'width' => $width, 'height' => $height, 'crop' => $crop, ); } // Get additional sizes registered by themes/plugins if ( isset( $_wp_additional_image_sizes ) && is_array( $_wp_additional_image_sizes ) ) { foreach ( $_wp_additional_image_sizes as $size_name => $size_data ) { $sizes[ $size_name ] = array( 'label' => ucfirst( str_replace( array( '_', '-' ), ' ', $size_name ) ), 'width' => isset( $size_data['width'] ) ? $size_data['width'] : 0, 'height' => isset( $size_data['height'] ) ? $size_data['height'] : 0, 'crop' => isset( $size_data['crop'] ) ? $size_data['crop'] : false, ); } } return $sizes; } }