<?php

/**
 * Plugin Name:     WebP Image Converter & Replacer – Image Optimisation, No Duplicates, Save Disk Space
 * Plugin URI:      https://coreessentials.online/plugins-for-wordpress/webp-image-converter-replacer/
 * Description:     Adds a link to the Media Library to convert JPEG/PNG/Static GIF images to WebP format, replacing the original if smaller.
 * Version:         1.1.3
 * Requires at least: 5.8
 * Author:          Core Essentials
 * Author URI:      https://coreessentials.online/
 * License:         GPL2
 * License URI:     https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:     webp-image-converter-replacer
 */
// Exit if accessed directly.
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
if ( function_exists( 'webpicr_fs' ) ) {
    webpicr_fs()->set_basename( false, __FILE__ );
} else {
    /**
     * DO NOT REMOVE THIS IF, IT IS ESSENTIAL FOR THE
     * `function_exists` CALL ABOVE TO PROPERLY WORK.
     */
    if ( !function_exists( 'webpicr_fs' ) ) {
        // Create a helper function for easy SDK access.
        function webpicr_fs() {
            global $webpicr_fs;
            if ( !isset( $webpicr_fs ) ) {
                // Activate multisite network integration.
                if ( !defined( 'WP_FS__PRODUCT_19000_MULTISITE' ) ) {
                    define( 'WP_FS__PRODUCT_19000_MULTISITE', true );
                }
                // Include Freemius SDK.
                require_once dirname( __FILE__ ) . '/vendor/freemius/start.php';
                $webpicr_fs = fs_dynamic_init( array(
                    'id'               => '19000',
                    'slug'             => 'webp-image-converter-replacer',
                    'type'             => 'plugin',
                    'public_key'       => 'pk_86f7e71b86d1e84bebd8d46248334',
                    'is_premium'       => false,
                    'premium_suffix'   => 'Premium',
                    'has_addons'       => false,
                    'has_paid_plans'   => true,
                    'is_org_compliant' => true,
                    'menu'             => array(
                        'first-path' => 'plugins.php',
                        'contact'    => false,
                        'support'    => false,
                    ),
                    'is_live'          => true,
                ) );
            }
            return $webpicr_fs;
        }

        // Init Freemius.
        webpicr_fs();
        // Signal that SDK was initiated.
        do_action( 'webpicr_fs_loaded' );
    }
    /**
     * Checks if the server supports WebP conversion via GD or Imagick.
     *
     * @return bool True if supported, false otherwise.
     */
    function webpicr_is_webp_supported() {
        if ( function_exists( 'imagewebp' ) && function_exists( 'imagecreatefromstring' ) ) {
            return true;
            // GD is available and supports WebP.
        }
        if ( class_exists( 'Imagick' ) ) {
            try {
                $imagick = new Imagick();
                $formats = $imagick->queryFormats( 'WEBP' );
                if ( !empty( $formats ) ) {
                    return true;
                    // Imagick is available and supports WebP.
                }
            } catch ( Exception $e ) {
                // Imagick might be installed but not configured properly.
                return false;
            }
        }
        return false;
    }

    /**
     * Determines the primary image editor available (Imagick preferred).
     *
     * @return string 'imagick', 'gd', or 'none'.
     */
    function webpicr_get_primary_image_editor() {
        if ( class_exists( 'Imagick' ) ) {
            // Verify Imagick can handle WebP (basic check)
            try {
                $imagick = new Imagick();
                if ( !empty( $imagick->queryFormats( 'WEBP' ) ) ) {
                    return 'imagick';
                }
            } catch ( Exception $e ) {
                // Imagick might exist but be unusable
            }
        }
        if ( function_exists( 'imagewebp' ) && function_exists( 'imagecreatefromstring' ) ) {
            return 'gd';
        }
        return 'none';
    }

    /**
     * Get ImageMagick resource limits
     * 
     * @return array Array of limits or defaults if Imagick unavailable
     */
    function webpicr_get_imagick_limits() {
        $limits = array(
            'width'  => 10000,
            'height' => 10000,
            'area'   => 100000000,
            'memory' => 256 * 1024 * 1024,
        );
        if ( class_exists( 'Imagick' ) ) {
            try {
                $imagick = new Imagick();
                // Get actual resource limits from ImageMagick
                if ( method_exists( $imagick, 'getResourceLimit' ) ) {
                    // Width limit (if defined)
                    $width_limit = $imagick->getResourceLimit( Imagick::RESOURCETYPE_WIDTH );
                    if ( $width_limit > 0 && $width_limit < PHP_INT_MAX ) {
                        $limits['width'] = $width_limit;
                    }
                    // Height limit (if defined)
                    $height_limit = $imagick->getResourceLimit( Imagick::RESOURCETYPE_HEIGHT );
                    if ( $height_limit > 0 && $height_limit < PHP_INT_MAX ) {
                        $limits['height'] = $height_limit;
                    }
                    // Area limit (total pixels)
                    $area_limit = $imagick->getResourceLimit( Imagick::RESOURCETYPE_AREA );
                    if ( $area_limit > 0 && $area_limit < PHP_INT_MAX ) {
                        $limits['area'] = $area_limit;
                    }
                    // Memory limit
                    $memory_limit = $imagick->getResourceLimit( Imagick::RESOURCETYPE_MEMORY );
                    if ( $memory_limit > 0 && $memory_limit < PHP_INT_MAX ) {
                        $limits['memory'] = $memory_limit;
                    }
                }
                $imagick->clear();
                $imagick->destroy();
            } catch ( Exception $e ) {
                // Fall back to defaults
                webpicr_debug_log( "[WEBPICR Limits] Could not get Imagick limits: " . $e->getMessage() );
            }
        }
        return $limits;
    }

    /**
     * Checks if a GIF file is animated using Imagick.
     *
     * @param string $file_path Full path to the GIF file.
     * @return bool|null Returns true if STATIC (1 frame), false if ANIMATED (>1 frame),
     *                   null if Imagick is unavailable or fails to read the image.
     */
    function webpicr_is_gif_animated_imagick(  $file_path  ) {
        webpicr_debug_log( "[WEBPICR Animation Check] START - Checking file: {$file_path}" );
        if ( !class_exists( 'Imagick' ) ) {
            webpicr_debug_log( "[WEBPICR Animation Check] ERROR: Imagick class not available" );
            return null;
            // Imagick not available
        }
        webpicr_debug_log( "[WEBPICR Animation Check] Imagick class found, creating instance..." );
        try {
            $imagick = new Imagick();
            webpicr_debug_log( "[WEBPICR Animation Check] Imagick instance created, calling readImage..." );
            // Use readImage (not pingImage) to ensure all frames are loaded
            // pingImage only reads the first frame for animated GIFs
            $read_success = @$imagick->readImage( $file_path );
            webpicr_debug_log( "[WEBPICR Animation Check] readImage result: " . (( $read_success ? 'SUCCESS' : 'FAILED' )) );
            if ( !$read_success ) {
                webpicr_debug_log( "[WEBPICR Warning] Imagick::readImage failed for GIF: {$file_path}" );
                return null;
                // Failed basic read
            }
            $totalImages = $imagick->getNumberImages();
            webpicr_debug_log( "[WEBPICR Animation Check] Initial frame count (before coalesce): {$totalImages}" );
            // Coalesce the GIF to expand optimized/delta frames
            // This is critical for screen recordings and optimized GIFs that store frames as deltas
            if ( $totalImages > 0 ) {
                webpicr_debug_log( "[WEBPICR Animation Check] Attempting to coalesce frames..." );
                try {
                    $coalesced = $imagick->coalesceImages();
                    $coalescedCount = $coalesced->getNumberImages();
                    webpicr_debug_log( "[WEBPICR Animation Check] Coalesce successful! Frame count: {$coalescedCount}" );
                    // Replace original with coalesced version for accurate counting
                    $imagick->clear();
                    $imagick->destroy();
                    $imagick = $coalesced;
                    $totalImages = $coalescedCount;
                } catch ( Exception $coalesceEx ) {
                    webpicr_debug_log( "[WEBPICR Animation Check] Coalesce failed: " . $coalesceEx->getMessage() . " - using original frame count" );
                    // Continue with original $imagick and $totalImages
                }
            }
            webpicr_debug_log( "[WEBPICR Animation Check] Final frame count (after coalesce): {$totalImages}" );
            // Count frames with actual dimensions (width > 0 and height > 0)
            $visibleFrames = 0;
            // Check if iteration is possible
            if ( $totalImages > 0 ) {
                webpicr_debug_log( "[WEBPICR Animation Check] Starting frame iteration (total: {$totalImages})..." );
                try {
                    $frameIndex = 0;
                    foreach ( $imagick as $frame ) {
                        $width = $frame->getImageWidth();
                        $height = $frame->getImageHeight();
                        webpicr_debug_log( "[WEBPICR Animation Check] Frame {$frameIndex}: {$width}x{$height}" );
                        if ( $width > 0 && $height > 0 ) {
                            $visibleFrames++;
                            webpicr_debug_log( "[WEBPICR Animation Check] Frame {$frameIndex} is VISIBLE (count now: {$visibleFrames})" );
                        }
                        $frameIndex++;
                    }
                    webpicr_debug_log( "[WEBPICR Animation Check] Frame iteration complete. Visible frames: {$visibleFrames}" );
                } catch ( Exception $iteratorException ) {
                    // Handle cases where frame iteration might fail
                    webpicr_debug_log( "[WEBPICR Warning] Exception iterating frames for GIF: " . $iteratorException->getMessage() . " for file: {$file_path}. Falling back to getNumberImages count." );
                    // Fallback: Use the raw number if iteration fails
                    $rawFrameCount = $imagick->getNumberImages();
                    webpicr_debug_log( "[WEBPICR Animation Check] FALLBACK: Using raw frame count: {$rawFrameCount}" );
                    // Apply previous logic (treat only exactly 1 as static)
                    $imagick->clear();
                    $imagick->destroy();
                    $result = ( $rawFrameCount === 1 ? true : (( $rawFrameCount === false || $rawFrameCount === null ? null : false )) );
                    webpicr_debug_log( "[WEBPICR Animation Check] FALLBACK RESULT: " . var_export( $result, true ) );
                    return $result;
                }
            } else {
                // If getNumberImages is 0 or less, treat as error
                webpicr_debug_log( "[WEBPICR Animation Check] WARNING: getNumberImages returned 0 or less" );
                $visibleFrames = 0;
            }
            $imagick->clear();
            $imagick->destroy();
            // Return true (is static) ONLY if exactly one visible frame was found
            $isStatic = $visibleFrames === 1;
            webpicr_debug_log( "[WEBPICR Animation Check] FINAL RESULT: " . (( $isStatic ? 'STATIC (1 frame)' : 'ANIMATED or ERROR (' . $visibleFrames . ' frames)' )) );
            return $isStatic;
        } catch ( Exception $e ) {
            webpicr_debug_log( "[WEBPICR Error] Exception checking GIF animation with Imagick: " . $e->getMessage() . " for file: {$file_path}" );
            // Ensure Imagick is destroyed if an exception occurs mid-process
            if ( isset( $imagick ) ) {
                try {
                    $imagick->clear();
                    $imagick->destroy();
                } catch ( Exception $ex ) {
                }
            }
            return null;
            // Indicate failure
        }
    }

    /**
     * Formats bytes into a human-readable string (KB, MB, etc.).
     *
     * @param int $bytes Number of bytes.
     * @param int $decimals Number of decimal places.
     * @return string Formatted string.
     */
    function webpicr_format_bytes(  $bytes, $decimals = 2  ) {
        $bytes = (int) $bytes;
        if ( $bytes <= 0 ) {
            return '0 Bytes';
        }
        // Handle zero or negative bytes
        $size = array(
            'Bytes',
            'KB',
            'MB',
            'GB',
            'TB',
            'PB',
            'EB',
            'ZB',
            'YB'
        );
        $factor = floor( (strlen( $bytes ) - 1) / 3 );
        // Ensure factor is within the bounds of the $size array
        $factor = min( $factor, count( $size ) - 1 );
        return sprintf( "%.{$decimals}f", $bytes / pow( 1024, $factor ) ) . ' ' . $size[$factor];
    }

    /**
     * Attempts to convert an image to WebP format using GD or Imagick.
     *
     * @param string $source_path Full path to the source image (JPEG/PNG).
     * @param string $dest_path   Full path where the WebP image should be saved.
     * @param int    $quality     WebP quality setting (0-100).
     * @return bool True on success, false on failure.
     */
    function webpicr_convert_image_to_webp(  $source_path, $dest_path, $quality = 80  ) {
        $success = false;
        $image_type = @exif_imagetype( $source_path );
        // Use @ to suppress errors for non-images
        if ( !$image_type ) {
            return false;
            // Not a valid image type recognized by exif_imagetype
        }
        // Memory management for large images
        $original_memory_limit = ini_get( 'memory_limit' );
        $current_memory_usage = memory_get_usage( true );
        $available_memory = webpicr_parse_memory_limit( $original_memory_limit ) - $current_memory_usage;
        // Get image dimensions to estimate memory requirements
        $image_info = @getimagesize( $source_path );
        if ( !$image_info ) {
            return false;
            // Can't get image dimensions
        }
        list( $width, $height ) = $image_info;
        // Estimate memory needed: width * height * 4 bytes per pixel * 3 (original + webp + working copy)
        $estimated_memory_needed = $width * $height * 4 * 3;
        webpicr_debug_log( "[WEBPICR Memory] Image: {$width}x{$height}, Estimated memory needed: " . webpicr_format_bytes( $estimated_memory_needed ) );
        webpicr_debug_log( "[WEBPICR Memory] Available memory: " . webpicr_format_bytes( $available_memory ) );
        // If we need more memory, try to increase the limit temporarily
        $memory_increased = false;
        if ( $estimated_memory_needed > $available_memory ) {
            $new_limit = max( webpicr_parse_memory_limit( $original_memory_limit ) + $estimated_memory_needed, 512 * 1024 * 1024 );
            $memory_increased = @ini_set( 'memory_limit', $new_limit );
            webpicr_debug_log( "[WEBPICR Memory] Increased memory limit to: " . webpicr_format_bytes( $new_limit ) . " (success: " . (( $memory_increased ? 'yes' : 'no' )) . ")" );
        }
        // Try GD first.
        if ( function_exists( 'imagewebp' ) ) {
            $image = null;
            switch ( $image_type ) {
                case IMAGETYPE_JPEG:
                    $image = @imagecreatefromjpeg( $source_path );
                    break;
                case IMAGETYPE_PNG:
                    $image = @imagecreatefrompng( $source_path );
                    if ( $image ) {
                        imagepalettetotruecolor( $image );
                        imagealphablending( $image, true );
                        imagesavealpha( $image, true );
                    }
                    break;
                case IMAGETYPE_GIF:
                    $image = @imagecreatefromgif( $source_path );
                    // Note: GD's imagecreatefromgif typically only gets the first frame.
                    // We rely on the calling function (AJAX handler) to ensure this is only called for static GIFs.
                    if ( $image ) {
                        // Convert palette images to true color (fixes "Palette image not supported by webp" error)
                        imagepalettetotruecolor( $image );
                        imagealphablending( $image, true );
                        imagesavealpha( $image, true );
                    }
                    break;
            }
            if ( $image ) {
                // Suppress errors for imagewebp in case of issues
                $success = @imagewebp( $image, $dest_path, $quality );
                imagedestroy( $image );
                // Restore original memory limit if we increased it
                if ( $memory_increased ) {
                    @ini_set( 'memory_limit', $original_memory_limit );
                    webpicr_debug_log( "[WEBPICR Memory] Restored memory limit to: {$original_memory_limit}" );
                }
                if ( $success && file_exists( $dest_path ) && filesize( $dest_path ) > 0 ) {
                    return true;
                }
                $success = false;
                // Ensure success is false if imagewebp failed or produced empty file
                // Cleanup failed GD attempt if file exists
                if ( file_exists( $dest_path ) ) {
                    wp_delete_file( $dest_path );
                }
            } else {
                // Restore memory limit even if image creation failed
                if ( $memory_increased ) {
                    @ini_set( 'memory_limit', $original_memory_limit );
                    webpicr_debug_log( "[WEBPICR Memory] Restored memory limit after image creation failure" );
                }
            }
        }
        // Try Imagick if GD failed or wasn't suitable.
        webpicr_debug_log( "[WEBPICR Imagick] Attempting Imagick fallback for: {$source_path}" );
        if ( class_exists( 'Imagick' ) ) {
            webpicr_debug_log( "[WEBPICR Imagick] Imagick class available, creating instance..." );
            try {
                $imagick = new Imagick();
                webpicr_debug_log( "[WEBPICR Imagick] Imagick instance created, reading image..." );
                $imagick->pingImage( $source_path );
                // Fast check if it's a valid image for Imagick
                $imagick->readImage( $source_path );
                webpicr_debug_log( "[WEBPICR Imagick] Image read successfully, setting format to WEBP..." );
                $imagick->setImageFormat( 'WEBP' );
                $imagick->setImageCompressionQuality( $quality );
                webpicr_debug_log( "[WEBPICR Imagick] Format and quality set, attempting to write..." );
                // For PNGs with transparency, ensure settings are appropriate
                if ( $image_type === IMAGETYPE_PNG ) {
                    $imagick->setOption( 'webp:lossless', ( $quality >= 90 ? 'true' : 'false' ) );
                }
                // For GIFs handled by Imagick (static ones, as animated are blocked earlier)
                if ( $image_type === IMAGETYPE_GIF ) {
                    // Imagick handles GIF transparency reasonably well by default for WebP conversion.
                    // No specific options usually needed here for static GIFs.
                }
                $imagick->stripImage();
                // Remove metadata like EXIF.
                $success = $imagick->writeImage( $dest_path );
                webpicr_debug_log( "[WEBPICR Imagick] writeImage result: " . (( $success ? 'SUCCESS' : 'FAILED' )) );
                $imagick->clear();
                $imagick->destroy();
                // Restore original memory limit if we increased it
                if ( $memory_increased ) {
                    @ini_set( 'memory_limit', $original_memory_limit );
                    webpicr_debug_log( "[WEBPICR Memory] Restored memory limit to: {$original_memory_limit} (Imagick success)" );
                }
                if ( $success && file_exists( $dest_path ) && filesize( $dest_path ) > 0 ) {
                    webpicr_debug_log( "[WEBPICR Imagick] Conversion SUCCESSFUL via Imagick!" );
                    return true;
                }
                // Cleanup failed Imagick attempt if file exists
                webpicr_debug_log( "[WEBPICR Imagick] Conversion FAILED - cleaning up" );
                if ( file_exists( $dest_path ) ) {
                    wp_delete_file( $dest_path );
                }
                $success = false;
            } catch ( Exception $e ) {
                // Cleanup potentially failed Imagick attempt
                $error_msg = $e->getMessage();
                webpicr_debug_log( "[WEBPICR Imagick] EXCEPTION caught: " . $error_msg );
                // Check if it's a WebP dimension limit error
                if ( strpos( $error_msg, 'WidthOrHeightExceedsLimit' ) !== false ) {
                    webpicr_debug_log( "[WEBPICR Imagick] WebP format dimension limit exceeded (max 16,383px)" );
                }
                if ( file_exists( $dest_path ) ) {
                    wp_delete_file( $dest_path );
                }
                $success = false;
            }
        } else {
            webpicr_debug_log( "[WEBPICR Imagick] Imagick class NOT available" );
        }
        // Restore memory limit if we increased it and haven't restored yet
        if ( $memory_increased ) {
            @ini_set( 'memory_limit', $original_memory_limit );
            webpicr_debug_log( "[WEBPICR Memory] Restored memory limit to: {$original_memory_limit} (final cleanup)" );
        }
        return $success;
    }

    /**
     * Parse memory limit string to bytes
     * 
     * @param string $memory_limit Memory limit string (e.g., "256M", "1G", "512000")
     * @return int Memory limit in bytes
     */
    function webpicr_parse_memory_limit(  $memory_limit  ) {
        if ( is_numeric( $memory_limit ) ) {
            return (int) $memory_limit;
        }
        $memory_limit = trim( $memory_limit );
        $last = strtolower( substr( $memory_limit, -1 ) );
        $value = (int) substr( $memory_limit, 0, -1 );
        switch ( $last ) {
            case 'g':
                $value *= 1024;
            // Fall through
            case 'm':
                $value *= 1024;
            // Fall through
            case 'k':
                $value *= 1024;
                break;
        }
        return $value;
    }

    /**
     * Adds a "Convert to WebP" link to the media library actions for supported image types.
     *
     * @param array   $actions An array of action links for each attachment.
     * @param WP_Post $post    The attachment post object.
     * @return array Filtered array of action links.
     */
    function webpicr_add_convert_to_webp_link(  $actions, $post  ) {
        // Only show actions for users who can manage media within the admin area
        if ( !is_admin() || !current_user_can( 'upload_files' ) ) {
            return $actions;
        }
        // Check if already converted successfully FIRST, regardless of current mime type
        $already_converted = get_post_meta( $post->ID, '_webpicr_converted_successfully', true );
        if ( $already_converted ) {
            // Display persistent saved info using TOTAL sizes
            $original_size = get_post_meta( $post->ID, '_webpicr_total_original_size', true );
            $final_size = get_post_meta( $post->ID, '_webpicr_total_final_size', true );
            if ( is_numeric( $original_size ) && is_numeric( $final_size ) && $original_size > $final_size ) {
                $saved_bytes = $original_size - $final_size;
                $saved_formatted = webpicr_format_bytes( $saved_bytes );
                $actions['webp_converted'] = '<span>' . sprintf( 
                    /* translators: %s: Human readable file size (e.g., 123.4 KB) */
                    esc_html__( 'WebP (Saved %s)', 'webp-image-converter-replacer' ),
                    esc_html( $saved_formatted )
                 ) . '</span>';
            } else {
                // Fallback if size meta is missing
                $actions['webp_converted'] = '<span>' . esc_html__( 'WebP (Converted)', 'webp-image-converter-replacer' ) . '</span>';
            }
            return $actions;
            // Stop here if already converted
        }
        // Determine available editor and mime type
        $editor = webpicr_get_primary_image_editor();
        $mime_type = $post->post_mime_type;
        // Check if image exceeds WebP format limits (16,383 x 16,383)
        $file_path = get_attached_file( $post->ID, true );
        if ( $file_path && file_exists( $file_path ) ) {
            $image_info = @getimagesize( $file_path );
            if ( $image_info ) {
                list( $width, $height ) = $image_info;
                $webp_max_dimension = 16383;
                if ( $width > $webp_max_dimension || $height > $webp_max_dimension ) {
                    // Image exceeds WebP format limits
                    $exceeded_dim = '';
                    if ( $width > $webp_max_dimension && $height > $webp_max_dimension ) {
                        $exceeded_dim = sprintf( '%dx%d', $width, $height );
                    } elseif ( $width > $webp_max_dimension ) {
                        $exceeded_dim = sprintf( 'Width %dpx', $width );
                    } else {
                        $exceeded_dim = sprintf( 'Height %dpx', $height );
                    }
                    $actions['webp_too_large'] = '<span>' . sprintf( esc_html__( 'Image exceeds WebP limit (%s)', 'webp-image-converter-replacer' ), esc_html( $exceeded_dim ) ) . '</span>';
                    return $actions;
                    // Stop here for oversized images
                }
            }
        }
        // --- Handle GIFs ---
        if ( $mime_type === 'image/gif' ) {
            if ( $editor === 'imagick' ) {
                $file_path = get_attached_file( $post->ID, true );
                if ( $file_path && file_exists( $file_path ) ) {
                    $is_static = webpicr_is_gif_animated_imagick( $file_path );
                    if ( $is_static === true ) {
                        // Static GIF, check for previous non-smaller failure
                        $failed_before = get_post_meta( $post->ID, '_webpicr_conversion_failed', true );
                        if ( $failed_before === 'webp_not_smaller' ) {
                            // Show not smaller message (copied from JPEG/PNG block for consistency)
                            $orig_main_size = get_post_meta( $post->ID, '_webpicr_original_main_size', true );
                            $gen_webp_size = get_post_meta( $post->ID, '_webpicr_generated_webp_size', true );
                            $message = esc_html__( 'WebP not smaller', 'webp-image-converter-replacer' );
                            if ( is_numeric( $orig_main_size ) && is_numeric( $gen_webp_size ) ) {
                                $message .= ' (' . esc_html( webpicr_format_bytes( $gen_webp_size ) ) . ' vs ' . esc_html( webpicr_format_bytes( $orig_main_size ) ) . ')';
                            }
                            $actions['webp_not_smaller'] = '<span>' . $message . '</span>';
                        } else {
                            // OK to show convert link for static GIF
                            $actions['convert_to_webp'] = '<a href="#" class="webpicr-convert-link" data-attachment-id="' . $post->ID . '" data-nonce="' . wp_create_nonce( 'webpicr_convert_image_' . $post->ID ) . '" aria-label="' . esc_attr__( 'Convert Static GIF to WebP', 'webp-image-converter-replacer' ) . '">' . esc_html__( 'Convert to WebP', 'webp-image-converter-replacer' ) . '</a>';
                        }
                    } elseif ( $is_static === false ) {
                        // Animated GIF or unexpected frame count (e.g., 0, 2, >2)
                        $actions['webp_animated_gif'] = '<span>' . esc_html__( 'Animated/Unsupported GIF', 'webp-image-converter-replacer' ) . '</span>';
                    } else {
                        // $is_static === null
                        // Animation check failed (null)
                        $actions['webp_gif_check_fail'] = '<span>' . esc_html__( 'GIF (Animation Check Failed)', 'webp-image-converter-replacer' ) . '</span>';
                    }
                } else {
                    $actions['webp_gif_file_missing'] = '<span>' . esc_html__( 'GIF (File Missing)', 'webp-image-converter-replacer' ) . '</span>';
                }
            } else {
                // GD or None editor for GIF
                $actions['webp_gif_imagick_req'] = '<span>' . esc_html__( 'GIF (Requires Imagick)', 'webp-image-converter-replacer' ) . '</span>';
            }
            return $actions;
            // Stop here for GIFs
        }
        // --- Handle JPEG/PNG ---
        $supported_mimes = array('image/jpeg', 'image/png');
        if ( in_array( $mime_type, $supported_mimes, true ) ) {
            // Check if it failed because WebP wasn't smaller or editor wasn't supported (non-retryable)
            $failed_before = get_post_meta( $post->ID, '_webpicr_conversion_failed', true );
            if ( $failed_before === 'webp_not_smaller' ) {
                // Optionally display the size difference here if available
                $orig_main_size = get_post_meta( $post->ID, '_webpicr_original_main_size', true );
                $gen_webp_size = get_post_meta( $post->ID, '_webpicr_generated_webp_size', true );
                $message = esc_html__( 'WebP not smaller', 'webp-image-converter-replacer' );
                if ( is_numeric( $orig_main_size ) && is_numeric( $gen_webp_size ) ) {
                    $message .= ' (' . esc_html( webpicr_format_bytes( $gen_webp_size ) ) . ' vs ' . esc_html( webpicr_format_bytes( $orig_main_size ) ) . ')';
                }
                $actions['webp_not_smaller'] = '<span>' . $message . '</span>';
            } elseif ( $failed_before === 'no_editor_support' ) {
                // Optionally add a message indicating lack of server support?
                // For now, just don't show the convert link.
            } else {
                // Show the convert link if it's eligible and hasn't failed for a permanent reason
                $convert_url = wp_nonce_url( admin_url( 'admin-ajax.php?action=webpicr_convert_image_to_webp&attachment_id=' . $post->ID ), 'webpicr_convert_image_' . $post->ID, 'webpicr_nonce' );
                $actions['convert_to_webp'] = '<a href="#" class="webpicr-convert-link" data-attachment-id="' . $post->ID . '" data-nonce="' . wp_create_nonce( 'webpicr_convert_image_' . $post->ID ) . '" aria-label="' . esc_attr__( 'Convert to WebP if smaller', 'webp-image-converter-replacer' ) . '">' . esc_html__( 'Convert to WebP', 'webp-image-converter-replacer' ) . '</a>';
            }
        }
        return $actions;
    }

    add_filter(
        'media_row_actions',
        'webpicr_add_convert_to_webp_link',
        10,
        2
    );
    /**
     * Handles the AJAX request to convert an image to WebP.
     */
    function webpicr_ajax_convert_image_to_webp() {
        // Increase PHP execution time limit to 5 minutes (matches AJAX timeout)
        // This prevents timeouts during thumbnail regeneration for large images
        @set_time_limit( 300 );
        // Start output buffering to catch any unexpected output that could corrupt JSON response
        if ( !ob_get_level() ) {
            ob_start();
        }
        // Set up error handler to catch warnings/notices that might output to screen
        set_error_handler( function (
            $errno,
            $errstr,
            $errfile,
            $errline
        ) {
            // Log the error instead of displaying it
            webpicr_debug_log( "[WEBPICR Ajax Error] {$errstr} in {$errfile}:{$errline}" );
            return true;
            // Don't execute PHP's internal error handler
        } );
        // Get the nonce and attachment ID from the request.
        $nonce = ( isset( $_REQUEST['webpicr_nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['webpicr_nonce'] ) ) : '' );
        $attachment_id = ( isset( $_REQUEST['attachment_id'] ) ? (int) $_REQUEST['attachment_id'] : 0 );
        // Verify the nonce. The action must match exactly what was used in wp_create_nonce().
        // The nonce is specific to the attachment ID.
        if ( !wp_verify_nonce( $nonce, 'webpicr_convert_image_' . $attachment_id ) ) {
            webpicr_send_conversion_error( __( 'Nonce verification failed.', 'webp-image-converter-replacer' ), 403 );
        }
        // Check User Capabilities.
        // Ensure the user can upload files (general permission for media)
        // and edit the specific attachment.
        if ( !current_user_can( 'upload_files' ) || !current_user_can( 'edit_post', $attachment_id ) ) {
            webpicr_send_conversion_error( __( 'Permission denied.', 'webp-image-converter-replacer' ), 403 );
        }
        // Now that nonce and capabilities are verified, proceed with the main logic.
        // The original check_ajax_referer() also dies, but wp_verify_nonce() returns bool,
        // so we handle the error explicitly.
        // Proceed with checks using the $attachment_id variable.
        if ( !$attachment_id || !wp_attachment_is_image( $attachment_id ) ) {
            webpicr_send_conversion_error( __( 'Invalid attachment ID or not an image.', 'webp-image-converter-replacer' ), 400 );
        }
        // --- Re-verify image type and editor support for security ---
        $editor = webpicr_get_primary_image_editor();
        $mime_type = get_post_mime_type( $attachment_id );
        webpicr_debug_log( "[WEBPICR GIF Check] Attachment ID: {$attachment_id}, Mime Type: '{$mime_type}', Editor: '{$editor}'" );
        if ( $mime_type === 'image/gif' ) {
            webpicr_debug_log( "[WEBPICR GIF Check] GIF detected! Starting animation check..." );
            if ( $editor === 'imagick' ) {
                webpicr_debug_log( "[WEBPICR GIF Check] Imagick available for GIF check" );
                $file_path_check = get_attached_file( $attachment_id, true );
                webpicr_debug_log( "[WEBPICR GIF Check] File path: {$file_path_check}" );
                if ( !$file_path_check || !file_exists( $file_path_check ) ) {
                    webpicr_debug_log( "[WEBPICR GIF Check] ERROR: File missing!" );
                    webpicr_send_conversion_error( __( 'GIF file missing for check.', 'webp-image-converter-replacer' ) );
                }
                webpicr_debug_log( "[WEBPICR GIF Check] Calling webpicr_is_gif_animated_imagick()..." );
                $is_static = webpicr_is_gif_animated_imagick( $file_path_check );
                // Returns true if static
                webpicr_debug_log( "[WEBPICR GIF Check] Animation check result: " . var_export( $is_static, true ) );
                if ( $is_static === null ) {
                    // Check failed
                    webpicr_debug_log( "[WEBPICR GIF Check] ERROR: Animation check returned NULL (check failed)" );
                    webpicr_send_conversion_error( __( 'Failed to check GIF animation status.', 'webp-image-converter-replacer' ) );
                }
                if ( $is_static === false ) {
                    // Animated or indeterminate frame count
                    webpicr_debug_log( "[WEBPICR GIF Check] GIF is ANIMATED - SKIPPING conversion" );
                    update_post_meta( $attachment_id, '_webpicr_conversion_failed', 'animated_gif' );
                    // Ensure no duplicate status entries
                    delete_post_meta( $attachment_id, '_webpicr_status' );
                    update_post_meta( $attachment_id, '_webpicr_status', 'skipped' );
                    // Increment the total media skipped counter
                    $total_skipped = (int) get_option( 'webpicr_total_media_skipped', 0 );
                    update_option( 'webpicr_total_media_skipped', $total_skipped + 1 );
                    webpicr_send_conversion_error( __( 'Animated/Unsupported GIFs cannot be converted.', 'webp-image-converter-replacer' ) );
                }
                // If $is_static is true, execution continues - proceed with conversion for static GIF
                webpicr_debug_log( "[WEBPICR GIF Check] GIF is STATIC (single frame) - proceeding with conversion" );
            } else {
                // GD or no editor available for GIF
                webpicr_debug_log( "[WEBPICR GIF Check] ERROR: Imagick NOT available, cannot check GIF animation" );
                webpicr_send_conversion_error( __( 'Imagick is required to convert GIFs.', 'webp-image-converter-replacer' ) );
            }
        } elseif ( $mime_type !== 'image/jpeg' && $mime_type !== 'image/png' ) {
            // Neither GIF, JPEG, nor PNG
            webpicr_debug_log( "[WEBPICR GIF Check] Unsupported image type: '{$mime_type}'" );
            webpicr_send_conversion_error( __( 'Unsupported image type.', 'webp-image-converter-replacer' ) );
        } else {
            webpicr_debug_log( "[WEBPICR GIF Check] Image type is JPEG or PNG - skipping GIF check" );
        }
        // --- End Security Re-verification ---
        // Prevent re-conversion if already successful
        if ( get_post_meta( $attachment_id, '_webpicr_converted_successfully', true ) ) {
            webpicr_send_conversion_error( __( 'Image already converted.', 'webp-image-converter-replacer' ) );
        }
        // Check for server support first.
        if ( !webpicr_is_webp_supported() ) {
            update_post_meta( $attachment_id, '_webpicr_conversion_failed', 'no_editor_support' );
            update_post_meta( $attachment_id, '_webpicr_status', 'failed' );
            // Clear statistics cache after failed conversion
            webpicr_clear_statistics_cache();
            // Increment the total media failed counter
            $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
            update_option( 'webpicr_total_media_failed', $total_failed + 1 );
            webpicr_send_conversion_error( __( 'Server does not support WebP conversion.', 'webp-image-converter-replacer' ) );
        }
        // Get original file path
        $original_file_path = get_attached_file( $attachment_id, true );
        // True for unfiltered path
        if ( !$original_file_path || !file_exists( $original_file_path ) ) {
            update_post_meta( $attachment_id, '_webpicr_conversion_failed', 'file_missing' );
            update_post_meta( $attachment_id, '_webpicr_status', 'failed' );
            // Clear statistics cache after failed conversion
            webpicr_clear_statistics_cache();
            // Increment the total media failed counter
            $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
            update_option( 'webpicr_total_media_failed', $total_failed + 1 );
            webpicr_send_conversion_error( __( 'Original file missing.', 'webp-image-converter-replacer' ) );
        }
        // Check image dimensions against server limits
        $image_info = @getimagesize( $original_file_path );
        if ( $image_info ) {
            list( $width, $height ) = $image_info;
            $total_pixels = $width * $height;
            // Get actual ImageMagick limits
            $limits = webpicr_get_imagick_limits();
            webpicr_debug_log( "[WEBPICR Limits] Image: {$width}x{$height} ({$total_pixels} pixels)" );
            webpicr_debug_log( "[WEBPICR Limits] Server max width: {$limits['width']}, max height: {$limits['height']}, max area: {$limits['area']}" );
            // Check if image exceeds limits
            $errors = array();
            // WebP format hard limit: 16,383 x 16,383 (14-bit dimensions)
            $webp_max_dimension = 16383;
            if ( $width > $webp_max_dimension ) {
                $errors[] = sprintf( __( 'Width %dpx exceeds WebP size limit of %dpx', 'webp-image-converter-replacer' ), $width, $webp_max_dimension );
            }
            if ( $height > $webp_max_dimension ) {
                $errors[] = sprintf( __( 'Height %dpx exceeds WebP size limit of %dpx', 'webp-image-converter-replacer' ), $height, $webp_max_dimension );
            }
            // Server limits (only check if WebP limits passed)
            if ( empty( $errors ) && $width > $limits['width'] ) {
                $errors[] = sprintf( __( 'Width %dpx exceeds server limit of %dpx', 'webp-image-converter-replacer' ), $width, $limits['width'] );
            }
            if ( empty( $errors ) && $height > $limits['height'] ) {
                $errors[] = sprintf( __( 'Height %dpx exceeds server limit of %dpx', 'webp-image-converter-replacer' ), $height, $limits['height'] );
            }
            if ( empty( $errors ) && $total_pixels > $limits['area'] ) {
                $errors[] = sprintf( __( 'Total pixels %s exceeds server limit of %s', 'webp-image-converter-replacer' ), number_format( $total_pixels ), number_format( $limits['area'] ) );
            }
            // Check for extreme aspect ratios (>30:1 or <1:30)
            $aspect_ratio = max( $width, $height ) / min( $width, $height );
            if ( $aspect_ratio > 30 ) {
                $errors[] = sprintf( __( 'Extreme aspect ratio %.1f:1 may cause issues', 'webp-image-converter-replacer' ), $aspect_ratio );
            }
            if ( !empty( $errors ) ) {
                webpicr_debug_log( "[WEBPICR Limits] Image exceeds limits: " . implode( ', ', $errors ) );
                update_post_meta( $attachment_id, '_webpicr_conversion_failed', 'image_too_large' );
                update_post_meta( $attachment_id, '_webpicr_status', 'failed' );
                // Clear statistics cache
                webpicr_clear_statistics_cache();
                // Increment the total media failed counter
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                update_option( 'webpicr_total_media_failed', $total_failed + 1 );
                $error_message = __( 'Image too large for server to process: ', 'webp-image-converter-replacer' ) . implode( '; ', $errors );
                webpicr_send_conversion_error( $error_message );
            }
        }
        // Define temporary WebP path
        $path_parts = pathinfo( $original_file_path );
        // Use a temporary name to avoid conflict if the original is somehow already .webp
        $temp_webp_path = $path_parts['dirname'] . '/' . $path_parts['filename'] . '-temp.webp';
        // Attempt conversion
        $conversion_success = webpicr_convert_image_to_webp( $original_file_path, $temp_webp_path );
        // Clear previous failure states if we are retrying
        delete_post_meta( $attachment_id, '_webpicr_conversion_failed' );
        delete_post_meta( $attachment_id, '_webpicr_status' );
        delete_post_meta( $attachment_id, '_webp_original_size' );
        delete_post_meta( $attachment_id, '_webp_generated_size' );
        if ( !$conversion_success || !file_exists( $temp_webp_path ) ) {
            update_post_meta( $attachment_id, '_webpicr_conversion_failed', 'conversion_error' );
            update_post_meta( $attachment_id, '_webpicr_status', 'failed' );
            // Clear statistics cache after failed conversion
            webpicr_clear_statistics_cache();
            // Increment the total media failed counter
            $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
            update_option( 'webpicr_total_media_failed', $total_failed + 1 );
            if ( file_exists( $temp_webp_path ) ) {
                wp_delete_file( $temp_webp_path );
            }
            webpicr_send_conversion_error( __( 'Conversion process failed.', 'webp-image-converter-replacer' ) );
        }
        // Compare file sizes
        $original_metadata = wp_get_attachment_metadata( $attachment_id );
        $total_original_bytes = 0;
        if ( !empty( $original_metadata['filesize'] ) ) {
            $total_original_bytes += (int) $original_metadata['filesize'];
        }
        if ( !empty( $original_metadata['sizes'] ) && is_array( $original_metadata['sizes'] ) ) {
            $upload_dir = wp_get_upload_dir();
            $original_basedir = dirname( get_attached_file( $attachment_id ) );
            // Get dir of original file
            $counted_original_files = [];
            // Track unique files
            foreach ( $original_metadata['sizes'] as $size => $size_info ) {
                if ( empty( $size_info['file'] ) ) {
                    continue;
                }
                // Skip if no file listed
                $filename = $size_info['file'];
                if ( in_array( $filename, $counted_original_files, true ) ) {
                    continue;
                }
                // Skip if already counted
                if ( !empty( $size_info['filesize'] ) ) {
                    $total_original_bytes += (int) $size_info['filesize'];
                    $counted_original_files[] = $filename;
                    // Mark as counted
                } else {
                    // Fallback if filesize meta is missing (less accurate)
                    $thumb_path = $original_basedir . '/' . $size_info['file'];
                    if ( file_exists( $thumb_path ) ) {
                        $total_original_bytes += filesize( $thumb_path );
                    }
                }
            }
        }
        $temp_webp_size = filesize( $temp_webp_path );
        // Compare ONLY the main file sizes for the decision to proceed
        $original_main_filesize = ( isset( $original_metadata['filesize'] ) ? (int) $original_metadata['filesize'] : filesize( $original_file_path ) );
        if ( $temp_webp_size < $original_main_filesize ) {
            // WebP main file is smaller - Proceed with replacement
            // --- Phoenix Integration (if available) ---
            if ( class_exists( 'Phoenix_Media_Rename' ) && method_exists( 'Phoenix_Media_Rename', 'do_rename' ) ) {
                webpicr_debug_log( "[WEBPICR] Phoenix available - using Phoenix for extension change" );
                // Get current filename without extension
                $current_filename = pathinfo( $original_file_path, PATHINFO_FILENAME );
                // Call Phoenix to change extension to .webp (Phoenix handles all database updates)
                $phoenix_result = Phoenix_Media_Rename::do_rename(
                    $attachment_id,
                    $current_filename,
                    // Keep same filename
                    0,
                    // Don't retitle
                    0,
                    // Don't get title from post
                    0,
                    // Don't get name from post
                    false,
                    // Don't check post parent
                    false,
                    // Don't force lowercase
                    false,
                    // Don't force serialization
                    true,
                    // $rename = true (Phoenix handles file operations)
                    'webp'
                );
                if ( $phoenix_result === 1 ) {
                    webpicr_debug_log( "[WEBPICR] Phoenix successfully changed extension to .webp" );
                    // Get the new WebP file path that Phoenix created
                    $phoenix_webp_path = get_attached_file( $attachment_id );
                    // Replace Phoenix's file with our optimized WebP content
                    global $wp_filesystem;
                    if ( empty( $wp_filesystem ) ) {
                        require_once ABSPATH . 'wp-admin/includes/file.php';
                        WP_Filesystem();
                    }
                    $replace_success = $wp_filesystem->move( $temp_webp_path, $phoenix_webp_path, true );
                    if ( $replace_success ) {
                        webpicr_debug_log( "[WEBPICR] Successfully replaced Phoenix file with optimized WebP" );
                        // Regenerate metadata for the optimized WebP
                        $new_metadata = wp_generate_attachment_metadata( $attachment_id, $phoenix_webp_path );
                        if ( !is_wp_error( $new_metadata ) && $new_metadata ) {
                            wp_update_attachment_metadata( $attachment_id, $new_metadata );
                            webpicr_debug_log( "[WEBPICR] Metadata regenerated for optimized WebP" );
                        }
                        // Phoenix handled everything - jump to success
                        $final_webp_path = $phoenix_webp_path;
                        $total_original_bytes = $original_main_filesize;
                        $total_final_bytes = $temp_webp_size;
                        $main_final_webp_filesize = $temp_webp_size;
                        // Set success variables for Phoenix path
                        update_post_meta( $attachment_id, '_webpicr_converted_successfully', time() );
                        // Ensure no duplicate status entries
                        delete_post_meta( $attachment_id, '_webpicr_status' );
                        update_post_meta( $attachment_id, '_webpicr_status', 'converted' );
                        update_post_meta( $attachment_id, '_webpicr_total_original_size', $total_original_bytes );
                        update_post_meta( $attachment_id, '_webpicr_total_final_size', $total_final_bytes );
                        update_post_meta( $attachment_id, '_webpicr_main_original_filesize_on_conversion', $original_main_filesize );
                        update_post_meta( $attachment_id, '_webpicr_main_final_webp_filesize', $main_final_webp_filesize );
                        // Update total counters
                        $total_converted = (int) get_option( 'webpicr_total_media_converted', 0 );
                        update_option( 'webpicr_total_media_converted', $total_converted + 1 );
                        // Clear statistics cache after successful conversion
                        webpicr_clear_statistics_cache();
                        $current_total_saved = (int) get_option( 'webpicr_total_bytes_saved', 0 );
                        $savings = $total_original_bytes - $total_final_bytes;
                        $current_total_saved_after_update = $current_total_saved + $savings;
                        update_option( 'webpicr_total_bytes_saved', $current_total_saved_after_update );
                        $success_message = __( 'WebP Converted (with DB)', 'webp-image-converter-replacer' );
                        // Get total converted count with caching
                        $cache_key = 'webpicr_total_converted_count';
                        $total_converted_count = wp_cache_get( $cache_key );
                        if ( $total_converted_count === false ) {
                            global $wpdb;
                            $total_converted_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                                 INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                                 WHERE p.post_type = 'attachment' \n                                 AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                                 AND pm.meta_key IN ('_webp_converted_successfully', '_webp_path')" );
                            // Cache for 5 minutes
                            wp_cache_set(
                                $cache_key,
                                $total_converted_count,
                                '',
                                300
                            );
                        }
                        // Phoenix handled everything - send success response
                        webpicr_send_conversion_success_response(
                            $success_message,
                            $total_original_bytes,
                            $total_final_bytes,
                            $original_main_filesize,
                            $main_final_webp_filesize,
                            $current_total_saved_after_update,
                            $total_converted_count
                        );
                        return;
                    } else {
                        webpicr_debug_log( "[WEBPICR] Failed to replace Phoenix file - falling back to manual process" );
                        // Fall through to manual process
                    }
                } else {
                    webpicr_debug_log( "[WEBPICR] Phoenix failed with result: " . wp_json_encode( $phoenix_result ) . " - falling back to manual process" );
                    // Fall through to manual process
                }
            }
            // --- Manual Process (fallback when Phoenix not available or fails) ---
            webpicr_debug_log( "[WEBPICR] Using manual process for file operations" );
            // Note: We already have $original_metadata from above
            // Define a backup path manually
            $path_parts_backup = pathinfo( $original_file_path );
            $backup_file_path = $path_parts_backup['dirname'] . '/' . $path_parts_backup['filename'] . '-webpicr-original-backup.' . $path_parts_backup['extension'];
            $backup_created = @copy( $original_file_path, $backup_file_path );
            // Create a backup just in case
            // --- Step 1: Delete original Thumbnails ---
            $thumbs_deleted_successfully = true;
            // Assume success initially
            if ( isset( $original_metadata['sizes'] ) && is_array( $original_metadata['sizes'] ) ) {
                foreach ( $original_metadata['sizes'] as $size => $size_info ) {
                    if ( isset( $size_info['file'] ) ) {
                        // Construct full path to the thumbnail
                        $thumb_path = $original_basedir . '/' . $size_info['file'];
                        if ( file_exists( $thumb_path ) ) {
                            $thumb_deleted = wp_delete_file( $thumb_path );
                            if ( !$thumb_deleted ) {
                                $thumbs_deleted_successfully = false;
                                // Mark failure
                            }
                        }
                    }
                }
            }
            webpicr_debug_log( "[WEBPICR Debug] Attachment ID: {$attachment_id} - Finished attempting thumbnail deletion. Overall success: " . (( $thumbs_deleted_successfully ? 'Yes' : 'No' )) );
            // --- Step 2: Delete the main original file ---
            global $wp_filesystem;
            if ( empty( $wp_filesystem ) ) {
                require_once ABSPATH . 'wp-admin/includes/file.php';
                WP_Filesystem();
            }
            $original_dir = dirname( $original_file_path );
            $file_writable = $wp_filesystem->is_writable( $original_file_path );
            $dir_writable = $wp_filesystem->is_writable( $original_dir );
            if ( !$dir_writable ) {
                webpicr_send_conversion_error( __( 'Uploads directory permissions prevent file deletion.', 'webp-image-converter-replacer' ) );
            }
            // Note: is_writable on the file itself might return false if it exists but user can't write *to* it,
            // but deletion primarily depends on directory write permissions.
            $original_deleted = false;
            if ( file_exists( $original_file_path ) ) {
                webpicr_debug_log( "[WEBPICR Debug] Attempting to delete original file: {$original_file_path}" );
                webpicr_debug_log( "[WEBPICR Debug] File permissions: " . substr( sprintf( '%o', fileperms( $original_file_path ) ), -4 ) );
                webpicr_debug_log( "[WEBPICR Debug] File size: " . filesize( $original_file_path ) . " bytes" );
                // Use wp_delete_file() as recommended by WordPress coding standards
                $original_deleted = wp_delete_file( $original_file_path );
                webpicr_debug_log( "[WEBPICR Debug] wp_delete_file() result: " . (( $original_deleted ? 'SUCCESS' : 'FAILED' )) );
                // If wp_delete_file() failed, try WP_Filesystem as fallback
                if ( !$original_deleted && !empty( $wp_filesystem ) ) {
                    webpicr_debug_log( "[WEBPICR Debug] Trying WP_Filesystem->delete() as fallback" );
                    $original_deleted = $wp_filesystem->delete( $original_file_path );
                    webpicr_debug_log( "[WEBPICR Debug] WP_Filesystem->delete() result: " . (( $original_deleted ? 'SUCCESS' : 'FAILED' )) );
                }
            } else {
                // Treat as success if already gone
                $original_deleted = true;
                webpicr_debug_log( "[WEBPICR Debug] Original file already missing, treating as success" );
            }
            if ( !$original_deleted ) {
                // Failed to delete original, attempt to restore backup if created
                if ( $backup_created ) {
                    // Use WP_Filesystem to move/rename files.
                    $wp_filesystem->move( $backup_file_path, $original_file_path, true );
                }
                wp_delete_file( $temp_webp_path );
                // Clean up temp WebP
                update_post_meta( $attachment_id, '_webp_conversion_failed', 'unlink_original_failed' );
                // Increment the total media failed counter
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                update_option( 'webpicr_total_media_failed', $total_failed + 1 );
                webpicr_send_conversion_error( __( 'Failed to delete original file.', 'webp-image-converter-replacer' ) );
            }
            // --- Step 3: Rename temp WebP to FINAL WebP path ---
            $path_parts = pathinfo( $original_file_path );
            // Use original path to get filename base
            $final_webp_path = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
            // Construct final .webp path
            // Use WP_Filesystem to move/rename files.
            $renamed = $wp_filesystem->move( $temp_webp_path, $final_webp_path, true );
            if ( !$renamed ) {
                // Critical error: original deleted, rename failed. Try restoring backup.
                if ( $backup_created ) {
                    $wp_filesystem->move( $backup_file_path, $original_file_path, true );
                }
                wp_delete_file( $temp_webp_path );
                // Clean up temp WebP if it still exists
                update_post_meta( $attachment_id, '_webp_conversion_failed', 'rename_webp_failed' );
                // Increment the total media failed counter
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                update_option( 'webpicr_total_media_failed', $total_failed + 1 );
                webpicr_debug_log( "WebP Converter Critical Error: Failed to rename temp WebP to final path ({$final_webp_path}) after deleting original. Original *should* be restored from backup. Attachment ID: {$attachment_id}" );
                webpicr_send_conversion_error( __( 'Failed to rename WebP file (check logs).', 'webp-image-converter-replacer' ) );
            }
            // --- Step 4: Update Post Mime Type & Attached File Meta ---
            wp_update_post( array(
                'ID'             => $attachment_id,
                'post_mime_type' => 'image/webp',
            ) );
            // Update _wp_attached_file meta with the NEW relative .webp path
            $uploads = wp_get_upload_dir();
            $relative_webp_path = ltrim( str_replace( $uploads['basedir'], '', $final_webp_path ), '/' );
            update_post_meta( $attachment_id, '_wp_attached_file', $relative_webp_path );
            // --- Step 5: Regenerate metadata and thumbnails for the new WebP file ---
            $new_metadata = wp_generate_attachment_metadata( $attachment_id, $final_webp_path );
            // IMPORTANT: Use the final .webp path!
            if ( false === $new_metadata || is_wp_error( $new_metadata ) ) {
                $error_message = ( is_wp_error( $new_metadata ) ? $new_metadata->get_error_message() : 'Unknown reason' );
                webpicr_debug_log( "[WEBPICR Error] Attachment ID: {$attachment_id} - wp_generate_attachment_metadata failed. Reason: {$error_message}" );
                // Metadata generation failed. Restore original file!
                if ( $backup_created ) {
                    // Delete the renamed webp file first
                    wp_delete_file( $final_webp_path );
                    $restored = $wp_filesystem->move( $backup_file_path, $original_file_path, true );
                    if ( $restored ) {
                        // Restore original mime type & attached file meta
                        $original_mime = mime_content_type( $original_file_path );
                        if ( $original_mime ) {
                            wp_update_post( array(
                                'ID'             => $attachment_id,
                                'post_mime_type' => $original_mime,
                            ) );
                            $relative_original_path = ltrim( str_replace( $uploads['basedir'], '', $original_file_path ), '/' );
                            update_post_meta( $attachment_id, '_wp_attached_file', $relative_original_path );
                        } else {
                            webpicr_debug_log( "[WEBPICR Warning] Attachment ID: {$attachment_id} - Could not determine original mime type after restoring backup." );
                        }
                    } else {
                        webpicr_debug_log( "[WEBPICR Critical Error] Attachment ID: {$attachment_id} - Failed to restore original from backup ({$backup_file_path}) after metadata failure. File system state may be inconsistent." );
                    }
                } else {
                    webpicr_debug_log( "[WEBPICR Error] Attachment ID: {$attachment_id} - Metadata failed and no backup was created. Cannot restore original." );
                }
                // Delete potentially leftover temp webp file if rename failed earlier and we ended up here somehow
                if ( file_exists( $temp_webp_path ) ) {
                    wp_delete_file( $temp_webp_path );
                }
                update_post_meta( $attachment_id, '_webp_conversion_failed', 'metadata_error' );
                // Increment the total media failed counter
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                update_option( 'webpicr_total_media_failed', $total_failed + 1 );
                webpicr_send_conversion_error( __( 'Failed to generate WebP metadata (check logs).', 'webp-image-converter-replacer' ) );
            }
            // --- Step 6: Update metadata in database ---
            wp_update_attachment_metadata( $attachment_id, $new_metadata );
            // Log snippet of new metadata for verification
            $log_metadata = ( is_array( $new_metadata ) ? json_encode( array_slice( $new_metadata, 0, 2 ) ) : 'Invalid metadata format' );
            // Log first couple elements
            // --- Step 6.5: Force MIME type update again (wp_generate_attachment_metadata may have overwritten it) ---
            wp_update_post( array(
                'ID'             => $attachment_id,
                'post_mime_type' => 'image/webp',
            ) );
            // --- Step 7: Calculate FINAL total size from NEW metadata and Store success meta ---
            $final_metadata = wp_get_attachment_metadata( $attachment_id );
            // Re-fetch final metadata
            $total_final_bytes = 0;
            if ( !empty( $final_metadata['filesize'] ) ) {
                $total_final_bytes += (int) $final_metadata['filesize'];
            }
            // Capture main final WebP filesize for specific comparison
            $main_final_webp_filesize = ( isset( $final_metadata['filesize'] ) ? (int) $final_metadata['filesize'] : 0 );
            if ( !empty( $final_metadata['sizes'] ) && is_array( $final_metadata['sizes'] ) ) {
                // Need base dir for final webp thumbs
                $final_webp_path = get_attached_file( $attachment_id );
                // Get the final .webp path stored in meta
                $final_basedir = dirname( $final_webp_path );
                $counted_final_files = [];
                // Track unique files
                foreach ( $final_metadata['sizes'] as $size => $size_info ) {
                    if ( empty( $size_info['file'] ) ) {
                        continue;
                    }
                    // Skip if no file listed
                    $filename = $size_info['file'];
                    if ( in_array( $filename, $counted_final_files, true ) ) {
                        continue;
                    }
                    // Skip if already counted
                    $current_thumb_filesize = 0;
                    // To log
                    if ( !empty( $size_info['filesize'] ) ) {
                        $total_final_bytes += (int) $size_info['filesize'];
                        $current_thumb_filesize = (int) $size_info['filesize'];
                        // For logging
                        $counted_final_files[] = $filename;
                        // Mark as counted
                    } else {
                        // Fallback if filesize meta is missing (less accurate)
                        $webp_thumb_path = $final_basedir . '/' . $size_info['file'];
                        if ( file_exists( $webp_thumb_path ) ) {
                            $filesize_on_disk = filesize( $webp_thumb_path );
                            // For logging
                            $total_final_bytes += $filesize_on_disk;
                            $current_thumb_filesize = $filesize_on_disk;
                            // For logging
                        }
                    }
                }
            }
            update_post_meta( $attachment_id, '_webpicr_converted_successfully', time() );
            // Ensure no duplicate status entries
            delete_post_meta( $attachment_id, '_webpicr_status' );
            update_post_meta( $attachment_id, '_webpicr_status', 'converted' );
            // Store the TOTAL original and final sizes
            update_post_meta( $attachment_id, '_webpicr_total_original_size', $total_original_bytes );
            update_post_meta( $attachment_id, '_webpicr_total_final_size', $total_final_bytes );
            // Store the MAIN original (pre-conversion) and final WebP (post-conversion) filesizes
            update_post_meta( $attachment_id, '_webpicr_main_original_filesize_on_conversion', $original_main_filesize );
            // $original_main_filesize was calculated earlier
            update_post_meta( $attachment_id, '_webpicr_main_final_webp_filesize_on_conversion', $main_final_webp_filesize );
            // --- Update Global Savings Tracker ---
            $saved_bytes = $total_original_bytes - $total_final_bytes;
            // Use TOTAL difference
            if ( $saved_bytes < 0 ) {
                $saved_bytes = 0;
            }
            // Avoid negative savings in global total
            $total_saved = (int) get_option( 'webpicr_total_bytes_saved', 0 );
            $new_total_saved = $total_saved + $saved_bytes;
            update_option( 'webpicr_total_bytes_saved', $new_total_saved );
            // Increment the total media converted counter
            $total_converted = (int) get_option( 'webpicr_total_media_converted', 0 );
            update_option( 'webpicr_total_media_converted', $total_converted + 1 );
            // Clear statistics cache after successful conversion
            webpicr_clear_statistics_cache();
            // Re-fetch the value immediately after updating to get the latest state
            $current_total_saved_after_update = (int) get_option( 'webpicr_total_bytes_saved', 0 );
            // --- Step 7.5: URL Replacement (Disabled - Partner Plugin Integration) ---
            $url_replacement_success = false;
            $url_replacement_count = 0;
            // --- Step 8: Clean up backup file ---
            if ( $backup_created ) {
                $backup_deleted = wp_delete_file( $backup_file_path );
            }
            // --- Step 9: Send back success message with TOTAL sizes ---
            $success_message = __( 'WebP Converted', 'webp-image-converter-replacer' );
            // URL replacement info removed - will be handled by partner plugin
            // Get total converted count for bulk UI display with caching
            $cache_key = 'webpicr_bulk_converted_count';
            $total_converted_count = wp_cache_get( $cache_key );
            if ( $total_converted_count === false ) {
                global $wpdb;
                $total_converted_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                     INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                     WHERE p.post_type = 'attachment' \n                     AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                     AND pm.meta_key IN ('_webp_converted_successfully', '_webp_path')" );
                // Cache for 5 minutes
                wp_cache_set(
                    $cache_key,
                    $total_converted_count,
                    '',
                    300
                );
            }
            wp_send_json_success( array(
                'message'               => $success_message,
                'original_size'         => $total_original_bytes,
                'final_size'            => $total_final_bytes,
                'main_original_size'    => $original_main_filesize,
                'main_final_size'       => $main_final_webp_filesize,
                'total_saved_bytes'     => $current_total_saved_after_update,
                'total_converted_count' => (int) $total_converted_count,
            ) );
        } else {
            // WebP main file not smaller, delete temp file
            wp_delete_file( $temp_webp_path );
            update_post_meta( $attachment_id, '_webpicr_conversion_failed', 'webp_not_smaller' );
            // Ensure no duplicate status entries
            delete_post_meta( $attachment_id, '_webpicr_status' );
            update_post_meta( $attachment_id, '_webpicr_status', 'skipped' );
            // Store original main size and generated main size for info, using new meta keys
            update_post_meta( $attachment_id, '_webpicr_original_main_size', $original_main_filesize );
            update_post_meta( $attachment_id, '_webpicr_generated_webp_size', $temp_webp_size );
            // Increment the total media skipped counter
            $total_skipped = (int) get_option( 'webpicr_total_media_skipped', 0 );
            update_option( 'webpicr_total_media_skipped', $total_skipped + 1 );
            // Remove old/unused meta keys if they exist
            delete_post_meta( $attachment_id, '_webp_original_size' );
            delete_post_meta( $attachment_id, '_webp_final_size' );
            delete_post_meta( $attachment_id, '_webp_generated_size' );
            webpicr_send_conversion_error( __( 'WebP not smaller', 'webp-image-converter-replacer' ) );
        }
    }

    add_action( 'wp_ajax_webpicr_convert_image_to_webp', 'webpicr_ajax_convert_image_to_webp' );
    /**
     * Ajax handler to check if a conversion completed after timeout
     */
    function webpicr_ajax_check_conversion_status() {
        // Verify nonce
        $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
        if ( !wp_verify_nonce( $nonce, 'webpicr_status_check_nonce' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Security check failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Get attachment ID
        $attachment_id = ( isset( $_POST['attachment_id'] ) ? (int) $_POST['attachment_id'] : 0 );
        if ( !$attachment_id ) {
            wp_send_json_error( array(
                'message' => __( 'Invalid attachment ID.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Check if conversion succeeded
        $converted = get_post_meta( $attachment_id, '_webpicr_converted_successfully', true );
        if ( $converted ) {
            // Get saved bytes info
            $original_size = get_post_meta( $attachment_id, '_webpicr_total_original_size', true );
            $final_size = get_post_meta( $attachment_id, '_webpicr_total_final_size', true );
            $saved_bytes = 0;
            if ( $original_size && $final_size && $original_size > $final_size ) {
                $saved_bytes = $original_size - $final_size;
            }
            // Get total savings
            $total_saved_bytes = webpicr_calculate_total_saved();
            wp_send_json_success( array(
                'converted'         => true,
                'saved_bytes'       => $saved_bytes,
                'total_saved_bytes' => $total_saved_bytes,
            ) );
        } else {
            // Not converted yet, or conversion failed
            wp_send_json_success( array(
                'converted' => false,
            ) );
        }
    }

    add_action( 'wp_ajax_webpicr_check_conversion_status', 'webpicr_ajax_check_conversion_status' );
    /**
     * AJAX handler to fix WebP MIME types
     */
    function webpicr_ajax_fix_mime_types() {
        // Security check
        if ( !check_ajax_referer( 'webpicr_fix_mime_types_nonce', 'nonce', false ) ) {
            wp_send_json_error( array(
                'message' => __( 'Security check failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        if ( !current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Insufficient permissions.', 'webp-image-converter-replacer' ),
            ) );
        }
        global $wpdb;
        // Find all WebP files with incorrect MIME types
        $broken_ids = $wpdb->get_col( "SELECT DISTINCT p.ID \n            FROM {$wpdb->posts} p\n            INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_wp_attached_file'\n            WHERE p.post_type = 'attachment'\n            AND p.post_mime_type != 'image/webp'\n            AND pm.meta_value LIKE '%.webp'" );
        if ( empty( $broken_ids ) ) {
            wp_send_json_success( array(
                'message' => __( 'No MIME type issues found.', 'webp-image-converter-replacer' ),
                'fixed'   => 0,
            ) );
        }
        // Fix each one
        $fixed_count = 0;
        foreach ( $broken_ids as $id ) {
            $result = wp_update_post( array(
                'ID'             => $id,
                'post_mime_type' => 'image/webp',
            ), true );
            if ( !is_wp_error( $result ) ) {
                $fixed_count++;
            }
        }
        wp_send_json_success( array(
            'message' => sprintf( __( 'Fixed %d WebP MIME types successfully!', 'webp-image-converter-replacer' ), $fixed_count ),
            'fixed'   => $fixed_count,
        ) );
    }

    add_action( 'wp_ajax_webpicr_fix_mime_types', 'webpicr_ajax_fix_mime_types' );
    /**
     * Helper function for conditional debug logging
     * Only logs when WP_DEBUG and WP_DEBUG_LOG are enabled
     */
    function webpicr_debug_log(  $message  ) {
        if ( defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
            error_log( $message );
        }
    }

    /**
     * Sanitize boolean setting values
     * Ensures only true/false values are stored
     */
    function webpicr_sanitize_boolean_setting(  $value  ) {
        return (bool) $value;
    }

    /**
     * Helper function to clear statistics cache
     */
    function webpicr_clear_statistics_cache() {
        wp_cache_delete( 'webpicr_total_converted_count' );
        wp_cache_delete( 'webpicr_bulk_converted_count' );
        wp_cache_delete( 'webpicr_total_skipped_count' );
        wp_cache_delete( 'webpicr_total_failed_count' );
        wp_cache_delete( 'webpicr_legacy_converted_count' );
        wp_cache_delete( 'webpicr_legacy_failed_count' );
        wp_cache_delete( 'webpicr_legacy_skipped_count' );
        wp_cache_delete( 'webpicr_init_converted_count' );
        wp_cache_delete( 'webpicr_init_skipped_count' );
        wp_cache_delete( 'webpicr_init_failed_count' );
        wp_cache_delete( 'webpicr_eligible_attachments_raw' );
        wp_cache_delete( 'webpicr_backup_options_list' );
        wp_cache_delete( 'webpicr_gif_attachments_migration' );
    }

    /**
     * Helper function to send conversion success response
     */
    function webpicr_send_conversion_success_response(
        $success_message,
        $total_original_bytes,
        $total_final_bytes,
        $original_main_filesize,
        $main_final_webp_filesize,
        $current_total_saved_after_update,
        $total_converted_count
    ) {
        // Clean up output buffer before sending JSON
        webpicr_clean_ajax_output();
        wp_send_json_success( array(
            'message'               => $success_message,
            'original_size'         => $total_original_bytes,
            'final_size'            => $total_final_bytes,
            'main_original_size'    => $original_main_filesize,
            'main_final_size'       => $main_final_webp_filesize,
            'total_saved_bytes'     => $current_total_saved_after_update,
            'total_converted_count' => (int) $total_converted_count,
        ) );
    }

    /**
     * Helper function to send conversion error response
     */
    function webpicr_send_conversion_error(  $message, $status_code = null  ) {
        // Clean up output buffer before sending JSON
        webpicr_clean_ajax_output();
        if ( $status_code !== null ) {
            wp_send_json_error( array(
                'message' => $message,
            ), $status_code );
        } else {
            wp_send_json_error( array(
                'message' => $message,
            ) );
        }
    }

    /**
     * Helper function to clean up output buffer and restore error handler
     */
    function webpicr_clean_ajax_output() {
        // Clean up any output buffer content
        if ( ob_get_level() ) {
            ob_end_clean();
        }
        // Restore error handler
        @restore_error_handler();
    }

    /**
     * Enqueue admin scripts for the media library and settings page.
     */
    function webpicr_enqueue_admin_scripts(  $hook_suffix  ) {
        // Load on both upload.php (Media Library) and options-media.php (Settings > Media)
        if ( 'upload.php' !== $hook_suffix && 'options-media.php' !== $hook_suffix ) {
            return;
        }
        // Add the filter hook only when on the media library screen
        if ( 'upload.php' === $hook_suffix ) {
            add_filter( 'views_upload', 'webpicr_display_total_savings_banner' );
        }
        $script_path = plugin_dir_url( __FILE__ ) . 'js/admin-scripts.js';
        $script_asset_path = plugin_dir_path( __FILE__ ) . 'js/admin-scripts.asset.php';
        $script_asset = ( file_exists( $script_asset_path ) ? require $script_asset_path : array(
            'dependencies' => array('jquery'),
            'version'      => filemtime( plugin_dir_path( __FILE__ ) . 'js/admin-scripts.js' ),
        ) );
        wp_enqueue_script(
            'webpicr-admin-script',
            $script_path,
            $script_asset['dependencies'],
            $script_asset['version'],
            true
        );
        // Check if a bulk action was just triggered and pass IDs to script
        $bulk_data = array(
            'webpicrBulkIds'   => array(),
            'webpicrStartBulk' => false,
            'bulk_nonce_value' => wp_create_nonce( 'webpicr_convert_image_' ),
            'ajax_url'         => admin_url( 'admin-ajax.php' ),
        );
        $transient_key = 'webpicr_bulk_ids_' . get_current_user_id();
        $bulk_ids = get_transient( $transient_key );
        if ( false !== $bulk_ids && is_array( $bulk_ids ) ) {
            // We have IDs, pass them to the script and delete the transient
            $bulk_data['webpicrBulkIds'] = $bulk_ids;
            $bulk_data['webpicrStartBulk'] = true;
            delete_transient( $transient_key );
        }
        // Localize script AFTER enqueueing
        wp_localize_script( 'webpicr-admin-script', 'webpicr_bulk_vars', $bulk_data );
        // Add global nonce for status checking
        wp_add_inline_script( 'webpicr-admin-script', 'var webpicr_status_check_nonce = "' . wp_create_nonce( 'webpicr_status_check_nonce' ) . '";' . 'var webpicr_fix_mime_types_nonce = "' . wp_create_nonce( 'webpicr_fix_mime_types_nonce' ) . '";', 'before' );
        // We can pass the ajaxurl via wp_localize_script if needed,
        // but it's usually available globally in admin scripts anyway.
        // wp_localize_script('webpicr-admin-script', 'webpicr_ajax_object', array('ajax_url' => admin_url('admin-ajax.php')));
    }

    add_action( 'admin_enqueue_scripts', 'webpicr_enqueue_admin_scripts' );
    /**
     * Optional: Clean up WebP conversion meta keys when an attachment is deleted.
     *
     * @param int $post_id Post ID.
     */
    function webpicr_cleanup_meta_on_delete(  $post_id  ) {
        // Check if it's an attachment post type before proceeding
        // Need to check if the post exists first in case it's already deleted
        $post = get_post( $post_id );
        if ( $post && $post->post_type === 'attachment' ) {
            // Only process image attachments
            if ( !wp_attachment_is_image( $post_id ) ) {
                return;
            }
            webpicr_debug_log( "[WEBPICR Cleanup] Processing deletion of attachment ID: {$post_id}" );
            // Get the current status before deletion to update counters
            $webpicr_status = get_post_meta( $post_id, '_webpicr_status', true );
            $converted_successfully = get_post_meta( $post_id, '_webpicr_converted_successfully', true );
            // Update statistics counters based on what this image was
            if ( $converted_successfully || $webpicr_status === 'converted' ) {
                // Decrease converted count
                $total_converted = (int) get_option( 'webpicr_total_media_converted', 0 );
                if ( $total_converted > 0 ) {
                    update_option( 'webpicr_total_media_converted', $total_converted - 1 );
                    webpicr_debug_log( "[WEBPICR Cleanup] Decreased converted count to: " . ($total_converted - 1) );
                }
                // Decrease total bytes saved
                $original_size = get_post_meta( $post_id, '_webpicr_total_original_size', true );
                $final_size = get_post_meta( $post_id, '_webpicr_total_final_size', true );
                if ( $original_size && $final_size && $original_size > $final_size ) {
                    $saved_bytes = $original_size - $final_size;
                    $total_saved = (int) get_option( 'webpicr_total_bytes_saved', 0 );
                    $new_total = max( 0, $total_saved - $saved_bytes );
                    update_option( 'webpicr_total_bytes_saved', $new_total );
                    webpicr_debug_log( "[WEBPICR Cleanup] Decreased total bytes saved by: " . webpicr_format_bytes( $saved_bytes ) );
                }
            } elseif ( $webpicr_status === 'skipped' ) {
                // Decrease skipped count
                $total_skipped = (int) get_option( 'webpicr_total_media_skipped', 0 );
                if ( $total_skipped > 0 ) {
                    update_option( 'webpicr_total_media_skipped', $total_skipped - 1 );
                    webpicr_debug_log( "[WEBPICR Cleanup] Decreased skipped count to: " . ($total_skipped - 1) );
                }
            } elseif ( $webpicr_status === 'failed' ) {
                // Decrease failed count
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                if ( $total_failed > 0 ) {
                    update_option( 'webpicr_total_media_failed', $total_failed - 1 );
                    webpicr_debug_log( "[WEBPICR Cleanup] Decreased failed count to: " . ($total_failed - 1) );
                }
            }
            // Clean up all plugin-related meta keys (original functionality)
            delete_post_meta( $post_id, '_webpicr_conversion_failed' );
            delete_post_meta( $post_id, '_webpicr_converted_successfully' );
            delete_post_meta( $post_id, '_webpicr_status' );
            // Delete old keys (if they exist from previous versions)
            delete_post_meta( $post_id, '_webp_original_size' );
            delete_post_meta( $post_id, '_webp_final_size' );
            delete_post_meta( $post_id, '_webp_generated_size' );
            delete_post_meta( $post_id, '_webp_conversion_failed' );
            delete_post_meta( $post_id, '_webp_converted_successfully' );
            delete_post_meta( $post_id, '_webp_path' );
            // Delete new total size keys
            delete_post_meta( $post_id, '_webpicr_total_original_size' );
            delete_post_meta( $post_id, '_webpicr_total_final_size' );
            // Delete new failed comparison keys
            delete_post_meta( $post_id, '_webpicr_original_main_size' );
            delete_post_meta( $post_id, '_webpicr_generated_webp_size' );
            // Clear all statistics caches since counts have changed
            webpicr_clear_statistics_cache();
            webpicr_debug_log( "[WEBPICR Cleanup] Completed cleanup for attachment ID: {$post_id}" );
        }
    }

    add_action( 'delete_post', 'webpicr_cleanup_meta_on_delete' );
    // Use delete_post hook for attachments
    /**
     * Displays the total space saved by the plugin above the media library table.
     *
     * @param array $views Array of view links (e.g., All, Mine).
     * @return array Modified array of view links.
     */
    function webpicr_display_total_savings_banner(  $views  ) {
        // Only show banner for users who can manage media within the admin area
        if ( !is_admin() || !current_user_can( 'upload_files' ) ) {
            return $views;
        }
        $total_saved = (int) get_option( 'webpicr_total_bytes_saved', 0 );
        $saved_formatted = webpicr_format_bytes( $total_saved );
        $banner_text_prefix = esc_html__( 'Total Savings via WebP Converter:', 'webp-image-converter-replacer' );
        $container_style = ( $total_saved > 0 ? 'display: inline-block;' : 'display: none;' );
        // Hide if 0
        // Add recalculate button
        $recalc_nonce = wp_create_nonce( 'webpicr_recalculate_savings_nonce' );
        $recalc_button = sprintf( ' <button type="button" id="webpicr-recalculate-button" class="button button-secondary button-small" data-nonce="%s" title="%s" style="vertical-align: middle; margin:0 0 0 8px;display:inline-flex;align-items:center;"><span class="dashicons dashicons-update"></span></button>', esc_attr( $recalc_nonce ), esc_attr__( 'Too fast and furious? Recalculate total savings and conversion count.', 'webp-image-converter-replacer' ) );
        // Add upsell link for free users
        $upsell_link_html = '';
        if ( function_exists( 'webpicr_fs' ) && webpicr_fs()->is_not_paying() && !webpicr_fs()->can_use_premium_code__premium_only() ) {
            $upgrade_url = webpicr_fs()->get_upgrade_url();
            $upsell_link_html = sprintf( '<a href="%s" target="_blank" style="font-size: smaller; text-decoration: none; margin-top: 4px; margin-left:10px; display: inline-block;">%s</a>', esc_url( $upgrade_url ), esc_html__( 'Bulk Conversion', 'webp-image-converter-replacer' ) );
        }
        // Always output the container, hide via style if savings are 0
        $views['webpicr_savings_banner'] = sprintf(
            '<div id="webpicr-total-savings-banner-container" class="webpicr-savings-banner" style="margin: 0 8px; padding: 2px 10px; background-color: #e7f7e7; border: 1px solid #c7e7c7; border-radius: 3px; %s"><span style="vertical-align: middle;">%s <span id="webpicr-total-savings-banner-value">%s</span></span>%s%s</div>',
            esc_attr( $container_style ),
            $banner_text_prefix,
            esc_html( $saved_formatted ),
            $recalc_button,
            // Add the button here
            $upsell_link_html
        );
        return $views;
    }

    /**
     * AJAX handler to recalculate the total savings accurately.
     */
    function webpicr_ajax_recalculate_savings() {
        global $wpdb;
        // Verify nonce
        check_ajax_referer( 'webpicr_recalculate_savings_nonce', 'webpicr_nonce' );
        // Check against nonce passed from JS
        // Check capability - use manage_options as it's a potentially heavier query
        if ( !current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Permission denied.', 'webp-image-converter-replacer' ),
            ), 403 );
        }
        $accurate_total_saved = 0;
        // Query for all successfully converted attachments
        $args = array(
            'post_type'      => 'attachment',
            'post_status'    => 'inherit',
            'posts_per_page' => -1,
            'meta_query'     => array(
                'relation' => 'AND',
                array(
                    'key'     => '_webpicr_status',
                    'value'   => 'converted',
                    'compare' => '=',
                ),
                array(
                    'key'     => '_webpicr_total_original_size',
                    'compare' => 'EXISTS',
                ),
                array(
                    'key'     => '_webpicr_total_final_size',
                    'compare' => 'EXISTS',
                ),
            ),
            'fields'         => 'ids',
        );
        $converted_attachments = new WP_Query($args);
        if ( $converted_attachments->have_posts() ) {
            foreach ( $converted_attachments->posts as $attachment_id ) {
                // Use the TOTAL size meta keys for recalculation
                $original_size = (int) get_post_meta( $attachment_id, '_webpicr_total_original_size', true );
                $final_size = (int) get_post_meta( $attachment_id, '_webpicr_total_final_size', true );
                if ( $original_size > 0 && $final_size > 0 && $original_size > $final_size ) {
                    $accurate_total_saved += $original_size - $final_size;
                }
            }
        }
        // Update the options with the accurate totals
        update_option( 'webpicr_total_bytes_saved', $accurate_total_saved );
        // Calculate and update the total media converted count
        $total_converted_count = $converted_attachments->found_posts;
        update_option( 'webpicr_total_media_converted', $total_converted_count );
        // Calculate and update the total media skipped count using new status system with caching
        $cache_key = 'webpicr_total_skipped_count';
        $total_skipped_count = wp_cache_get( $cache_key );
        if ( $total_skipped_count === false ) {
            $total_skipped_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                 INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                 WHERE p.post_type = 'attachment' \n                 AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                 AND pm.meta_key = '_webpicr_status' AND pm.meta_value = 'skipped'" );
            // Cache for 5 minutes
            wp_cache_set(
                $cache_key,
                $total_skipped_count,
                '',
                300
            );
        }
        update_option( 'webpicr_total_media_skipped', $total_skipped_count );
        // Calculate and update the total media failed count using new status system with caching
        $cache_key = 'webpicr_total_failed_count';
        $total_failed_count = wp_cache_get( $cache_key );
        if ( $total_failed_count === false ) {
            $total_failed_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                 INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                 WHERE p.post_type = 'attachment' \n                 AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                 AND pm.meta_key = '_webpicr_status' AND pm.meta_value = 'failed'" );
            // Cache for 5 minutes
            wp_cache_set(
                $cache_key,
                $total_failed_count,
                '',
                300
            );
        }
        update_option( 'webpicr_total_media_failed', $total_failed_count );
        // Send back the accurate totals
        wp_send_json_success( array(
            'accurate_total_saved_bytes'     => $accurate_total_saved,
            'accurate_total_converted_count' => $total_converted_count,
            'accurate_total_skipped_count'   => $total_skipped_count,
            'accurate_total_failed_count'    => $total_failed_count,
        ) );
    }

    add_action( 'wp_ajax_webpicr_recalculate_savings', 'webpicr_ajax_recalculate_savings' );
    // --- Bulk Action ---
    /**
     * Adds the 'Convert Selected to WebP' option to the Media Library bulk actions dropdown.
     *
     * @param array $bulk_actions An array of available bulk actions.
     * @return array Modified array of bulk actions.
     */
    function webpicr_add_bulk_convert_action(  $bulk_actions  ) {
        // Only show actions for users who can manage media within the admin area
        if ( !is_admin() || !current_user_can( 'upload_files' ) ) {
            return $bulk_actions;
        }
        // Check premium status
        if ( webpicr_fs()->is_not_paying() ) {
            // Add an informational/upsell item for non-paying users
            $bulk_actions['webpicr_bulk_convert_upsell'] = __( 'Convert Selected to WebP (Premium only)', 'webp-image-converter-replacer' );
        }
        return $bulk_actions;
    }

    add_filter( 'bulk_actions-upload', 'webpicr_add_bulk_convert_action' );
    // THIS FILTER MUST BE OUTSIDE THE PREMIUM CHECK TO HANDLE THE UPSELL ACTION
    add_filter(
        'handle_bulk_actions-upload',
        'webpicr_handle_bulk_convert_action',
        11,
        3
    );
    /**
     * Handles the 'Convert Selected to WebP' bulk action.
     *
     * Stores the selected attachment IDs in a transient to be processed by JavaScript.
     * Or, if the upsell action is triggered by a free user, redirects to the upgrade page.
     *
     * @param string $redirect_to The redirect URL.
     * @param string $doaction    The action being performed.
     * @param array  $post_ids    An array of post IDs selected.
     * @return string The redirect URL.
     */
    function webpicr_handle_bulk_convert_action(  $redirect_to, $doaction, $post_ids  ) {
        if ( 'webpicr_bulk_convert_upsell' === $doaction ) {
            check_admin_referer( 'bulk-media' );
            // Check nonce for this action
            if ( function_exists( 'webpicr_fs' ) && !webpicr_fs()->can_use_premium_code__premium_only() ) {
                $url = admin_url( 'upload.php' );
                // Add a nonce for the notice display
                $notice_nonce = wp_create_nonce( 'webpicr_bulk_notice_nonce_action' );
                $url_with_notice = add_query_arg( array(
                    'webpicr_bulk_notice'   => 'premium_feature',
                    '_webpicr_notice_nonce' => $notice_nonce,
                ), $url );
                wp_safe_redirect( $url_with_notice );
                exit;
            }
            // If premium user or Freemius not available, let WP handle redirect (less likely path)
            return $redirect_to;
        }
        if ( 'webpicr_bulk_convert' === $doaction ) {
            check_admin_referer( 'bulk-media' );
            // Check nonce for this action
            // Ensure user is premium for the actual conversion.
            if ( function_exists( 'webpicr_fs' ) && !webpicr_fs()->can_use_premium_code__premium_only() ) {
                // Non-premium user tried 'webpicr_bulk_convert' directly
                wp_safe_redirect( webpicr_fs()->get_upgrade_url() );
                exit;
            }
            if ( !function_exists( 'webpicr_fs' ) ) {
                // Fallback if Freemius isn't active
                $error_nonce = wp_create_nonce( 'webpicr_bulk_notice_nonce_action' );
                return add_query_arg( array(
                    'webpicr_bulk_error'    => '3',
                    '_webpicr_notice_nonce' => $error_nonce,
                ), $redirect_to );
                // Error: Premium feature
            }
            // Security check: Verify user capability (already performed by nonce and premium check mostly)
            if ( !current_user_can( 'upload_files' ) ) {
                // This case should ideally be caught by higher-level checks or nonces, but as a fallback:
                $error_nonce = wp_create_nonce( 'webpicr_bulk_notice_nonce_action' );
                // We can't easily display a custom wp_die message *and* redirect with a nonce for a notice.
                // So, we'll redirect to an error notice that explains the permission issue.
                // Or, more simply, let WordPress handle the wp_die() which is more direct for permission failures.
                wp_die( esc_html__( 'You do not have permission to convert these files.', 'webp-image-converter-replacer' ) );
            }
            if ( empty( $post_ids ) ) {
                $error_nonce = wp_create_nonce( 'webpicr_bulk_notice_nonce_action' );
                return add_query_arg( array(
                    'webpicr_bulk_error'    => '1',
                    '_webpicr_notice_nonce' => $error_nonce,
                ), $redirect_to );
                // Error: No items selected
            }
            $image_ids_filtered = array_filter( $post_ids, 'wp_attachment_is_image' );
            if ( empty( $image_ids_filtered ) ) {
                $error_nonce = wp_create_nonce( 'webpicr_bulk_notice_nonce_action' );
                return add_query_arg( array(
                    'webpicr_bulk_error'    => '2',
                    '_webpicr_notice_nonce' => $error_nonce,
                ), $redirect_to );
                // Error: No valid images selected
            }
            $image_ids = array_values( $image_ids_filtered );
            $transient_key = 'webpicr_bulk_ids_' . get_current_user_id();
            set_transient( $transient_key, $image_ids, MINUTE_IN_SECONDS );
            $success_nonce = wp_create_nonce( 'webpicr_bulk_notice_nonce_action' );
            return add_query_arg( array(
                'webpicr_bulk_queued'   => count( $image_ids ),
                '_webpicr_notice_nonce' => $success_nonce,
            ), $redirect_to );
        }
        // If not our actions, return the original redirect URL
        return $redirect_to;
    }

    /**
     * Display admin notices for bulk action results.
     */
    function webpicr_bulk_action_admin_notices() {
        // Check if any of our notice parameters are set.
        if ( empty( $_REQUEST['webpicr_bulk_queued'] ) && empty( $_REQUEST['webpicr_bulk_error'] ) && empty( $_REQUEST['webpicr_bulk_notice'] ) ) {
            return;
            // No notice to display
        }
        // Verify nonce for displaying these notices.
        // The nonce should be present if any of our parameters are set.
        $nonce = ( isset( $_REQUEST['_webpicr_notice_nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_webpicr_notice_nonce'] ) ) : '' );
        if ( !wp_verify_nonce( $nonce, 'webpicr_bulk_notice_nonce_action' ) ) {
            // If nonce is invalid, and one of our params is set, this is suspicious. Don't show the notice.
            // Optionally, log this or show a generic error, but for now, just bail.
            // Only show a warning if a user who *can* manage options sees this.
            if ( current_user_can( 'manage_options' ) && (isset( $_REQUEST['webpicr_bulk_queued'] ) || isset( $_REQUEST['webpicr_bulk_error'] ) || isset( $_REQUEST['webpicr_bulk_notice'] )) ) {
                printf( '<div class="notice notice-error"><p>%s</p></div>', esc_html__( 'A WebP Converter notice could not be displayed due to a security check failure.', 'webp-image-converter-replacer' ) );
            }
            return;
        }
        // Nonce is valid, proceed to check capabilities for displaying admin notices.
        // Typically, 'upload_files' or 'edit_posts' is sufficient for media library related notices.
        // 'manage_options' is too high for just viewing a notice.
        if ( !current_user_can( 'upload_files' ) ) {
            return;
            // Don't show notices if user doesn't have basic media permissions.
        }
        if ( !empty( $_REQUEST['webpicr_bulk_queued'] ) ) {
            $count = (int) $_REQUEST['webpicr_bulk_queued'];
            /* translators: %s: Number of images. */
            printf( '<div id="message" class="notice notice-info is-dismissible"><p>' . esc_html__( 'Queued %s images for WebP conversion. Processing will start now. Please keep this browser tab open.', 'webp-image-converter-replacer' ) . '</p></div>', esc_html( $count ) );
        }
        if ( !empty( $_REQUEST['webpicr_bulk_error'] ) ) {
            $error_code = (int) $_REQUEST['webpicr_bulk_error'];
            $message = '';
            if ( $error_code === 1 ) {
                $message = __( 'Bulk Conversion Error: No items were selected.', 'webp-image-converter-replacer' );
            } elseif ( $error_code === 2 ) {
                $message = __( 'Bulk Conversion Error: No valid images were selected.', 'webp-image-converter-replacer' );
            } elseif ( $error_code === 3 ) {
                $message = __( 'Bulk Conversion Error: This is a premium feature. Please upgrade.', 'webp-image-converter-replacer' );
            } else {
                $message = __( 'Bulk Conversion Error: An unknown error occurred.', 'webp-image-converter-replacer' );
            }
            printf( '<div id="message" class="notice notice-error is-dismissible"><p>%s</p></div>', esc_html( $message ) );
        }
        if ( !empty( $_REQUEST['webpicr_bulk_notice'] ) && $_REQUEST['webpicr_bulk_notice'] === 'premium_feature' ) {
            $upgrade_url = ( function_exists( 'webpicr_fs' ) ? webpicr_fs()->get_upgrade_url() : '#' );
            // Prepare the raw HTML message content first
            $raw_html_message = sprintf( 
                /* translators: %s: URL to upgrade to premium */
                __( 'Bulk conversion is a premium feature. <a href="%s" target="_blank">Upgrade to Premium</a> to enable it.', 'webp-image-converter-replacer' ),
                esc_url( $upgrade_url )
             );
            // Sanitize directly in printf
            printf( '<div id="message" class="notice notice-warning is-dismissible"><p>%s</p></div>', wp_kses_post( $raw_html_message ) );
        }
    }

    add_action( 'admin_notices', 'webpicr_bulk_action_admin_notices' );
    // --- Bulk Optimize All (Settings Page) ---
    /**
     * Add settings section for Bulk Optimize All feature
     */
    function webpicr_register_settings_section() {
        add_settings_section(
            'webpicr_bulk_optimize_section',
            __( 'WebP Image Converter & Replacer', 'webp-image-converter-replacer' ),
            'webpicr_bulk_optimize_section_callback',
            'media'
        );
        // Register the auto-convert setting
        register_setting( 'media', 'webpicr_auto_convert_uploads', array(
            'type'              => 'boolean',
            'default'           => false,
            'sanitize_callback' => 'webpicr_sanitize_boolean_setting',
        ) );
    }

    /**
     * Check if Phoenix Media Rename plugin is installed (but not necessarily activated)
     */
    function webpicr_is_phoenix_installed() {
        // Check common plugin paths for Phoenix Media Rename
        $plugin_paths = array('phoenix-media-rename/phoenix-media-rename.php', 'phoenix-media-rename-premium/phoenix-media-rename.php');
        foreach ( $plugin_paths as $plugin_path ) {
            if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin_path ) ) {
                return $plugin_path;
            }
        }
        return false;
    }

    /**
     * Render Fix WebP MIME Types utility
     */
    function webpicr_render_fix_mime_types_utility() {
        global $wpdb;
        // Find WebP files with incorrect MIME types (quick count)
        $broken_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) \n            FROM {$wpdb->posts} p\n            INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_wp_attached_file'\n            WHERE p.post_type = 'attachment'\n            AND p.post_mime_type != 'image/webp'\n            AND pm.meta_value LIKE '%.webp'" );
        // Only show if there are broken entries
        if ( $broken_count > 0 ) {
            ?>
            <div class="webpicr-fix-mime-types" style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px; padding: 15px; margin: 15px 0;">
                <div style="display: flex; align-items: flex-start; gap: 15px;">
                    <span style="color: #856404; font-size: 20px; margin-top: 2px;">⚠️</span>
                    <div style="flex: 1;">
                        <h4 style="margin: 0 0 8px 0; color: #856404;"><?php 
            esc_html_e( 'WebP MIME Type Issue Detected', 'webp-image-converter-replacer' );
            ?></h4>
                        <p style="margin: 0 0 12px 0; color: #856404;">
                            <?php 
            printf( esc_html__( 'Found %d WebP files with incorrect MIME types in the database. This is cosmetic and doesn\'t affect functionality, but can be fixed with one click.', 'webp-image-converter-replacer' ), (int) $broken_count );
            ?>
                        </p>
                        <button type="button" id="webpicr-fix-mime-types-btn" class="button button-secondary" style="background: #856404; color: white; border-color: #6c5228;">
                            <?php 
            printf( esc_html__( 'Fix %d MIME Types', 'webp-image-converter-replacer' ), (int) $broken_count );
            ?>
                        </button>
                        <span id="webpicr-fix-mime-types-result" style="margin-left: 10px; font-weight: bold;"></span>
                    </div>
                </div>
            </div>
            <?php 
        }
    }

    /**
     * Render Phoenix Media Rename integration status card
     */
    function webpicr_render_phoenix_integration_status() {
        // Check if Phoenix is installed (files exist) vs activated (class loaded)
        $phoenix_activated = class_exists( 'Phoenix_Media_Rename' );
        $phoenix_installed = webpicr_is_phoenix_installed();
        $phoenix_has_do_rename = $phoenix_activated && method_exists( 'Phoenix_Media_Rename', 'do_rename' );
        // Check if Phoenix has the new extension parameter support
        // Version 3.12.12+ includes the new extension parameter
        $phoenix_has_extension_support = false;
        if ( $phoenix_has_do_rename ) {
            $phoenix_version = webpicr_get_phoenix_version();
            $phoenix_has_extension_support = version_compare( $phoenix_version, '3.12.12', '>=' );
            // Debug logging
            webpicr_debug_log( "[WEBPICR DEBUG] Phoenix version detected: " . $phoenix_version );
            webpicr_debug_log( "[WEBPICR DEBUG] Version comparison (>= 3.12.12): " . (( $phoenix_has_extension_support ? 'true' : 'false' )) );
        }
        if ( $phoenix_activated && $phoenix_has_extension_support ) {
            // Phoenix is activated and integrated
            ?>
            <div class="webpicr-phoenix-status" style="background: #d1e7dd; border: 1px solid #badbcc; border-radius: 4px; padding: 15px; margin: 15px 0;">
                <div style="display: flex; align-items: center; gap: 10px;">
                    <span style="color: #0f5132; font-size: 18px;">✅</span>
                    <div>
                        <h4 style="margin: 0 0 5px 0; color: #0f5132;"><?php 
            esc_html_e( 'Phoenix Media Rename Integration Active', 'webp-image-converter-replacer' );
            ?></h4>
                        <p style="margin: 0; color: #0f5132;">
                            <?php 
            esc_html_e( 'Database URL updates will be handled automatically and safely. All converted images will maintain proper links in your content.', 'webp-image-converter-replacer' );
            ?>
                        </p>
                    </div>
                </div>
            </div>
            <?php 
        } elseif ( $phoenix_activated && !$phoenix_has_extension_support ) {
            // Phoenix is activated but outdated - show update notice
            $current_version = webpicr_get_phoenix_version();
            // Debug: Log the exact versions for troubleshooting
            webpicr_debug_log( "[WEBPICR DEBUG] Showing update notice for Phoenix version: " . $current_version );
            webpicr_debug_log( "[WEBPICR DEBUG] Required version: 3.12.12" );
            webpicr_debug_log( "[WEBPICR DEBUG] Comparison result: " . (( version_compare( $current_version, '3.12.12', '>=' ) ? 'SHOULD BE COMPATIBLE' : 'NEEDS UPDATE' )) );
            ?>
            <div class="webpicr-phoenix-outdated" style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px; padding: 15px; margin: 15px 0;">
                <div style="display: flex; align-items: flex-start; gap: 15px;">
                    <span style="color: #856404; font-size: 18px; margin-top: 2px;">⚠️</span>
                    <div style="flex: 1;">
                        <h4 style="margin: 0 0 10px 0; color: #856404;"><?php 
            esc_html_e( 'Phoenix Media Rename Needs Update', 'webp-image-converter-replacer' );
            ?></h4>
                        <p style="margin: 0 0 15px 0; color: #856404;">
                            <?php 
            printf( 
                /* translators: %s: Phoenix Media Rename version number */
                esc_html__( 'You have Phoenix Media Rename installed (version %s), but it needs to be updated to version 3.12.12 or higher for full WebP integration compatibility.', 'webp-image-converter-replacer' ),
                esc_html( $current_version )
             );
            ?>
                            <br><small style="opacity: 0.7;">
                                DEBUG: Detected version: "<?php 
            echo esc_html( $current_version );
            ?>" | 
                                Comparison: <?php 
            echo ( version_compare( $current_version, '3.12.12', '>=' ) ? 'SHOULD PASS' : 'FAILS' );
            ?>
                            </small>
                        </p>
                        
                        <div style="margin: 15px 0;">
                            <button id="webpicr-update-phoenix" class="button button-primary" style="margin-right: 10px;">
                                <?php 
            esc_html_e( 'Update Phoenix Media Rename', 'webp-image-converter-replacer' );
            ?>
                            </button>
                            <a href="https://wordpress.org/plugins/phoenix-media-rename/" target="_blank" class="button button-secondary">
                                <?php 
            esc_html_e( 'View Update Details', 'webp-image-converter-replacer' );
            ?>
                            </a>
                        </div>
                        
                        <div style="background: rgba(255,255,255,0.7); padding: 10px; border-radius: 3px; font-size: 13px;">
                            <strong><?php 
            esc_html_e( 'What you\'ll get with the update:', 'webp-image-converter-replacer' );
            ?></strong>
                            <ul style="margin: 5px 0 0 0; padding-left: 20px;">
                                <li><?php 
            esc_html_e( 'Automatic database URL updates for WebP conversions', 'webp-image-converter-replacer' );
            ?></li>
                                <li><?php 
            esc_html_e( 'Enhanced file extension changing capabilities', 'webp-image-converter-replacer' );
            ?></li>
                                <li><?php 
            esc_html_e( 'Seamless integration with our WebP converter', 'webp-image-converter-replacer' );
            ?></li>
                                <li><?php 
            esc_html_e( 'Latest bug fixes and improvements', 'webp-image-converter-replacer' );
            ?></li>
                            </ul>
                        </div>
                    </div>
                </div>
                
                <!-- Update progress (hidden by default) -->
                <div id="webpicr-phoenix-update-progress" style="display: none; margin-top: 15px; padding: 10px; background: rgba(255,255,255,0.8); border-radius: 3px;">
                    <div style="display: flex; align-items: center; gap: 10px;">
                        <span class="spinner is-active" style="float: none; margin: 0;"></span>
                        <span id="webpicr-phoenix-update-status"><?php 
            esc_html_e( 'Updating Phoenix Media Rename...', 'webp-image-converter-replacer' );
            ?></span>
                    </div>
                </div>
            </div>
            
            <script type="text/javascript">
            jQuery(document).ready(function($) {
                $('#webpicr-update-phoenix').on('click', function(e) {
                    e.preventDefault();
                    
                    const $button = $(this);
                    const $progress = $('#webpicr-phoenix-update-progress');
                    const $status = $('#webpicr-phoenix-update-status');
                    
                    // Show progress, disable button
                    $button.prop('disabled', true);
                    $progress.show();
                    
                    // Update Phoenix
                    $.ajax({
                        url: ajaxurl,
                        type: 'POST',
                        data: {
                            action: 'webpicr_update_phoenix',
                            nonce: '<?php 
            echo esc_js( wp_create_nonce( 'webpicr_update_phoenix_nonce' ) );
            ?>'
                        },
                        success: function(response) {
                            if (response.success) {
                                $status.html('<span style="color: #0f5132;">✅ ' + response.data.message + '</span>');
                                
                                // Reload page after 2 seconds to show the success status
                                setTimeout(function() {
                                    window.location.reload();
                                }, 2000);
                            } else {
                                $status.html('<span style="color: #dc3545;">❌ ' + response.data.message + '</span>');
                                $button.prop('disabled', false);
                            }
                        },
                        error: function() {
                            $status.html('<span style="color: #dc3545;">❌ <?php 
            esc_html_e( 'Update failed. Please try again.', 'webp-image-converter-replacer' );
            ?></span>');
                            $button.prop('disabled', false);
                        }
                    });
                });
            });
            </script>
            <?php 
        } elseif ( $phoenix_installed && !$phoenix_activated ) {
            // Phoenix is installed but not activated - show activate button
            ?>
            <div class="webpicr-phoenix-activate" style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px; padding: 15px; margin: 15px 0;">
                <div style="display: flex; align-items: flex-start; gap: 15px;">
                    <span style="color: #856404; font-size: 18px; margin-top: 2px;">⚡</span>
                    <div style="flex: 1;">
                        <h4 style="margin: 0 0 10px 0; color: #856404;"><?php 
            esc_html_e( 'Phoenix Media Rename Ready to Activate', 'webp-image-converter-replacer' );
            ?></h4>
                        <p style="margin: 0 0 15px 0; color: #856404;">
                            <?php 
            esc_html_e( 'Phoenix Media Rename is installed but not activated. Activate it to enable automatic database URL updates for your WebP conversions.', 'webp-image-converter-replacer' );
            ?>
                        </p>
                        
                        <div style="margin: 15px 0;">
                            <button id="webpicr-activate-phoenix" class="button button-primary" style="margin-right: 10px;">
                                <?php 
            esc_html_e( 'Activate Phoenix Media Rename', 'webp-image-converter-replacer' );
            ?>
                            </button>
                            <a href="https://wordpress.org/plugins/phoenix-media-rename/" target="_blank" class="button button-secondary">
                                <?php 
            esc_html_e( 'Learn More', 'webp-image-converter-replacer' );
            ?>
                            </a>
                        </div>
                    </div>
                </div>
                
                <!-- Activation progress (hidden by default) -->
                <div id="webpicr-phoenix-activate-progress" style="display: none; margin-top: 15px; padding: 10px; background: rgba(255,255,255,0.8); border-radius: 3px;">
                    <div style="display: flex; align-items: center; gap: 10px;">
                        <span class="spinner is-active" style="float: none; margin: 0;"></span>
                        <span id="webpicr-phoenix-activate-status"><?php 
            esc_html_e( 'Activating Phoenix Media Rename...', 'webp-image-converter-replacer' );
            ?></span>
                    </div>
                </div>
            </div>
            
            <script type="text/javascript">
            jQuery(document).ready(function($) {
                $('#webpicr-activate-phoenix').on('click', function(e) {
                    e.preventDefault();
                    
                    const $button = $(this);
                    const $progress = $('#webpicr-phoenix-activate-progress');
                    const $status = $('#webpicr-phoenix-activate-status');
                    
                    // Show progress, disable button
                    $button.prop('disabled', true);
                    $progress.show();
                    
                    // Activate Phoenix
                    $.ajax({
                        url: ajaxurl,
                        type: 'POST',
                        data: {
                            action: 'webpicr_activate_phoenix',
                            nonce: '<?php 
            echo esc_js( wp_create_nonce( 'webpicr_activate_phoenix_nonce' ) );
            ?>'
                        },
                        success: function(response) {
                            if (response.success) {
                                $status.html('<span style="color: #0f5132;">✅ ' + response.data.message + '</span>');
                                
                                // Reload page after 2 seconds to show the success status
                                setTimeout(function() {
                                    window.location.reload();
                                }, 2000);
                            } else {
                                $status.html('<span style="color: #dc3545;">❌ ' + response.data.message + '</span>');
                                $button.prop('disabled', false);
                            }
                        },
                        error: function() {
                            $status.html('<span style="color: #dc3545;">❌ <?php 
            esc_html_e( 'Activation failed. Please try again.', 'webp-image-converter-replacer' );
            ?></span>');
                            $button.prop('disabled', false);
                        }
                    });
                });
            });
            </script>
            <?php 
        } else {
            // Phoenix not installed - show call to action
            ?>
            <div class="webpicr-phoenix-cta" style="background: #f0f6fc; border: 1px solid #c7d2fe; border-radius: 4px; padding: 15px; margin: 15px 0;">
                <div style="display: flex; align-items: flex-start; gap: 15px;">
                    <span style="color: #3858e9; font-size: 18px; margin-top: 2px;">🔧</span>
                    <div style="flex: 1;">
                        <h4 style="margin: 0 0 10px 0; color: #1e40af;"><?php 
            esc_html_e( 'Enhance Your WebP Conversions with Phoenix Media Rename', 'webp-image-converter-replacer' );
            ?></h4>
                        <p style="margin: 0 0 15px 0; color: #1e40af;">
                            <?php 
            esc_html_e( 'Phoenix Media Rename will automatically update all database references when converting images to WebP, ensuring your content links stay intact.', 'webp-image-converter-replacer' );
            ?>
                        </p>
                        
                        <div style="margin: 15px 0;">
                            <button id="webpicr-install-phoenix" class="button button-primary" style="margin-right: 10px;">
                                <?php 
            esc_html_e( 'Install Phoenix Media Rename', 'webp-image-converter-replacer' );
            ?>
                            </button>
                            <a href="https://wordpress.org/plugins/phoenix-media-rename/" target="_blank" class="button button-secondary">
                                <?php 
            esc_html_e( 'Learn More', 'webp-image-converter-replacer' );
            ?>
                            </a>
                        </div>
                        
                        <div style="background: rgba(255,255,255,0.7); padding: 10px; border-radius: 3px; font-size: 13px;">
                            <strong><?php 
            esc_html_e( 'Benefits:', 'webp-image-converter-replacer' );
            ?></strong>
                            <ul style="margin: 5px 0 0 0; padding-left: 20px;">
                                <li><?php 
            esc_html_e( 'Automatic database URL updates', 'webp-image-converter-replacer' );
            ?></li>
                                <li><?php 
            esc_html_e( 'Safer file operations', 'webp-image-converter-replacer' );
            ?></li>
                                <li><?php 
            esc_html_e( 'No broken links in your content', 'webp-image-converter-replacer' );
            ?></li>
                                <li><?php 
            esc_html_e( 'Professional-grade media management', 'webp-image-converter-replacer' );
            ?></li>
                            </ul>
                        </div>
                    </div>
                </div>
                
                <!-- Installation progress (hidden by default) -->
                <div id="webpicr-phoenix-install-progress" style="display: none; margin-top: 15px; padding: 10px; background: rgba(255,255,255,0.8); border-radius: 3px;">
                    <div style="display: flex; align-items: center; gap: 10px;">
                        <span class="spinner is-active" style="float: none; margin: 0;"></span>
                        <span id="webpicr-phoenix-install-status"><?php 
            esc_html_e( 'Installing Phoenix Media Rename...', 'webp-image-converter-replacer' );
            ?></span>
                    </div>
                </div>
            </div>
            
            <script type="text/javascript">
            jQuery(document).ready(function($) {
                $('#webpicr-install-phoenix').on('click', function(e) {
                    e.preventDefault();
                    
                    const $button = $(this);
                    const $progress = $('#webpicr-phoenix-install-progress');
                    const $status = $('#webpicr-phoenix-install-status');
                    
                    // Show progress, hide button
                    $button.prop('disabled', true);
                    $progress.show();
                    
                    // Install Phoenix
                    $.ajax({
                        url: ajaxurl,
                        type: 'POST',
                        data: {
                            action: 'webpicr_install_phoenix',
                            nonce: '<?php 
            echo esc_js( wp_create_nonce( 'webpicr_install_phoenix_nonce' ) );
            ?>'
                        },
                        success: function(response) {
                            if (response.success) {
                                $status.html('<span style="color: #0f5132;">✅ ' + response.data.message + '</span>');
                                
                                // Reload page after 2 seconds to show the success status
                                setTimeout(function() {
                                    window.location.reload();
                                }, 2000);
                            } else {
                                $status.html('<span style="color: #dc3545;">❌ ' + response.data.message + '</span>');
                                $button.prop('disabled', false);
                            }
                        },
                        error: function() {
                            $status.html('<span style="color: #dc3545;">❌ <?php 
            esc_html_e( 'Installation failed. Please try again.', 'webp-image-converter-replacer' );
            ?></span>');
                            $button.prop('disabled', false);
                        }
                    });
                });
            });
            </script>
            <?php 
        }
    }

    /**
     * AJAX handler for Phoenix Media Rename installation
     */
    function webpicr_ajax_install_phoenix() {
        // Verify nonce
        $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
        if ( !wp_verify_nonce( $nonce, 'webpicr_install_phoenix_nonce' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Security check failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Check user permissions
        if ( !current_user_can( 'install_plugins' ) ) {
            wp_send_json_error( array(
                'message' => __( 'You do not have permission to install plugins.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Check if Phoenix is already installed
        if ( class_exists( 'Phoenix_Media_Rename' ) ) {
            wp_send_json_success( array(
                'message' => __( 'Phoenix Media Rename is already installed and active!', 'webp-image-converter-replacer' ),
            ) );
        }
        // Include required WordPress files
        if ( !function_exists( 'plugins_api' ) ) {
            require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
        }
        if ( !class_exists( 'WP_Upgrader' ) ) {
            require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
        }
        if ( !class_exists( 'Plugin_Upgrader' ) ) {
            require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
        }
        if ( !function_exists( 'activate_plugin' ) ) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        // Get plugin information
        $plugin_slug = 'phoenix-media-rename';
        $api = plugins_api( 'plugin_information', array(
            'slug'   => $plugin_slug,
            'fields' => array(
                'short_description' => false,
                'sections'          => false,
                'requires'          => false,
                'rating'            => false,
                'ratings'           => false,
                'downloaded'        => false,
                'last_updated'      => false,
                'added'             => false,
                'tags'              => false,
                'compatibility'     => false,
                'homepage'          => false,
                'donate_link'       => false,
            ),
        ) );
        if ( is_wp_error( $api ) ) {
            wp_send_json_error( array(
                'message' => __( 'Could not retrieve plugin information.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Install the plugin
        $upgrader = new Plugin_Upgrader(new WP_Ajax_Upgrader_Skin());
        $install_result = $upgrader->install( $api->download_link );
        if ( is_wp_error( $install_result ) ) {
            wp_send_json_error( array(
                'message' => $install_result->get_error_message(),
            ) );
        }
        if ( !$install_result ) {
            wp_send_json_error( array(
                'message' => __( 'Plugin installation failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Activate the plugin
        $plugin_file = $plugin_slug . '/' . $plugin_slug . '.php';
        $activate_result = activate_plugin( $plugin_file );
        if ( is_wp_error( $activate_result ) ) {
            wp_send_json_error( array(
                'message' => $activate_result->get_error_message(),
            ) );
        }
        wp_send_json_success( array(
            'message' => __( 'Phoenix Media Rename installed and activated successfully!', 'webp-image-converter-replacer' ),
        ) );
    }

    add_action( 'wp_ajax_webpicr_install_phoenix', 'webpicr_ajax_install_phoenix' );
    /**
     * Add Settings link to plugin list page
     */
    function webpicr_add_plugin_settings_link(  $links  ) {
        $settings_link = '<a href="' . esc_url( admin_url( 'options-media.php#webpicr-bulk-optimize-all-section' ) ) . '">' . esc_html__( 'Settings', 'webp-image-converter-replacer' ) . '</a>';
        array_unshift( $links, $settings_link );
        return $links;
    }

    add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'webpicr_add_plugin_settings_link' );
    /**
     * Get Phoenix Media Rename version
     */
    function webpicr_get_phoenix_version() {
        if ( !function_exists( 'get_plugin_data' ) ) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        $phoenix_file = WP_PLUGIN_DIR . '/phoenix-media-rename/phoenix-media-rename.php';
        if ( file_exists( $phoenix_file ) ) {
            $plugin_data = get_plugin_data( $phoenix_file );
            return $plugin_data['Version'] ?? 'unknown';
        }
        return 'unknown';
    }

    /**
     * AJAX handler for Phoenix Media Rename update
     */
    function webpicr_ajax_update_phoenix() {
        // Verify nonce
        $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
        if ( !wp_verify_nonce( $nonce, 'webpicr_update_phoenix_nonce' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Security check failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Check user permissions
        if ( !current_user_can( 'update_plugins' ) ) {
            wp_send_json_error( array(
                'message' => __( 'You do not have permission to update plugins.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Check if Phoenix is installed
        if ( !class_exists( 'Phoenix_Media_Rename' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Phoenix Media Rename is not installed.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Include required WordPress files
        if ( !function_exists( 'plugins_api' ) ) {
            require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
        }
        if ( !class_exists( 'WP_Upgrader' ) ) {
            require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
        }
        if ( !class_exists( 'Plugin_Upgrader' ) ) {
            require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
        }
        // Get plugin information for latest version
        $plugin_slug = 'phoenix-media-rename';
        $api = plugins_api( 'plugin_information', array(
            'slug'   => $plugin_slug,
            'fields' => array(
                'short_description' => false,
                'sections'          => false,
                'requires'          => false,
                'rating'            => false,
                'ratings'           => false,
                'downloaded'        => false,
                'last_updated'      => false,
                'added'             => false,
                'tags'              => false,
                'compatibility'     => false,
                'homepage'          => false,
                'donate_link'       => false,
            ),
        ) );
        if ( is_wp_error( $api ) ) {
            wp_send_json_error( array(
                'message' => __( 'Could not retrieve plugin update information.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Update the plugin
        $plugin_file = $plugin_slug . '/' . $plugin_slug . '.php';
        $upgrader = new Plugin_Upgrader(new WP_Ajax_Upgrader_Skin());
        $update_result = $upgrader->upgrade( $plugin_file );
        if ( is_wp_error( $update_result ) ) {
            wp_send_json_error( array(
                'message' => $update_result->get_error_message(),
            ) );
        }
        if ( !$update_result ) {
            wp_send_json_error( array(
                'message' => __( 'Plugin update failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        wp_send_json_success( array(
            'message' => __( 'Phoenix Media Rename updated successfully!', 'webp-image-converter-replacer' ),
        ) );
    }

    add_action( 'wp_ajax_webpicr_update_phoenix', 'webpicr_ajax_update_phoenix' );
    /**
     * AJAX handler for Phoenix Media Rename activation
     */
    function webpicr_ajax_activate_phoenix() {
        // Verify nonce
        $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
        if ( !wp_verify_nonce( $nonce, 'webpicr_activate_phoenix_nonce' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Security check failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Check user permissions
        if ( !current_user_can( 'activate_plugins' ) ) {
            wp_send_json_error( array(
                'message' => __( 'You do not have permission to activate plugins.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Check if Phoenix is already activated
        if ( class_exists( 'Phoenix_Media_Rename' ) ) {
            wp_send_json_success( array(
                'message' => __( 'Phoenix Media Rename is already active!', 'webp-image-converter-replacer' ),
            ) );
        }
        // Find the Phoenix plugin file
        $phoenix_plugin_path = webpicr_is_phoenix_installed();
        if ( !$phoenix_plugin_path ) {
            wp_send_json_error( array(
                'message' => __( 'Phoenix Media Rename is not installed.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Activate the plugin
        $activate_result = activate_plugin( $phoenix_plugin_path );
        if ( is_wp_error( $activate_result ) ) {
            wp_send_json_error( array(
                'message' => $activate_result->get_error_message(),
            ) );
        }
        wp_send_json_success( array(
            'message' => __( 'Phoenix Media Rename activated successfully!', 'webp-image-converter-replacer' ),
        ) );
    }

    add_action( 'wp_ajax_webpicr_activate_phoenix', 'webpicr_ajax_activate_phoenix' );
    /**
     * Auto-convert eligible images on upload
     */
    function webpicr_auto_convert_on_upload(  $metadata, $attachment_id  ) {
        // Skip if we're in a manual conversion Ajax request
        if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'webpicr_convert_image_to_webp' ) {
            // Silently skip - we're already converting this via manual action
            return $metadata;
        }
        // Prevent infinite loops - check if we're already processing this attachment
        $processing_key = '_webpicr_processing_' . $attachment_id;
        $is_processing = get_transient( $processing_key );
        webpicr_debug_log( "[WEBPICR DEBUG] Transient check for {$processing_key}: " . (( $is_processing ? 'FOUND (skipping)' : 'NOT FOUND (proceeding)' )) );
        if ( $is_processing ) {
            webpicr_debug_log( "[WEBPICR DEBUG] Auto-convert already processing attachment ID: {$attachment_id}, skipping to prevent loop" );
            return $metadata;
        }
        // Mark this attachment as being processed (expires in 60 seconds as failsafe)
        $transient_set = set_transient( $processing_key, time(), 60 );
        webpicr_debug_log( "[WEBPICR DEBUG] Marked attachment {$attachment_id} as processing - transient set result: " . (( $transient_set ? 'SUCCESS' : 'FAILED' )) );
        // Debug logging
        webpicr_debug_log( "[WEBPICR DEBUG] Auto-convert hook triggered for attachment ID: {$attachment_id}" );
        // Only proceed if auto-convert is enabled and user is premium
        $auto_convert_enabled = get_option( 'webpicr_auto_convert_uploads', false );
        webpicr_debug_log( "[WEBPICR DEBUG] Auto-convert enabled: " . (( $auto_convert_enabled ? 'YES' : 'NO' )) );
        if ( !$auto_convert_enabled ) {
            webpicr_debug_log( "[WEBPICR DEBUG] Auto-convert disabled, skipping" );
            delete_transient( $processing_key );
            return $metadata;
        }
        $is_premium = function_exists( 'webpicr_fs' ) && webpicr_fs()->can_use_premium_code__premium_only();
        webpicr_debug_log( "[WEBPICR DEBUG] Premium user: " . (( $is_premium ? 'YES' : 'NO' )) );
        if ( !$is_premium ) {
            webpicr_debug_log( "[WEBPICR DEBUG] Not premium user, skipping auto-convert" );
            delete_transient( $processing_key );
            return $metadata;
        }
        // Check if attachment is eligible for conversion
        $is_eligible = webpicr_is_attachment_eligible_for_conversion( $attachment_id );
        webpicr_debug_log( "[WEBPICR DEBUG] Attachment eligible: " . (( $is_eligible ? 'YES' : 'NO' )) );
        if ( !$is_eligible ) {
            webpicr_debug_log( "[WEBPICR DEBUG] Attachment not eligible, skipping conversion" );
            delete_transient( $processing_key );
            return $metadata;
        }
        // Prevent re-conversion if already successfully converted
        $already_converted = get_post_meta( $attachment_id, '_webpicr_converted_successfully', true );
        webpicr_debug_log( "[WEBPICR DEBUG] Already converted: " . (( $already_converted ? 'YES' : 'NO' )) );
        if ( $already_converted ) {
            webpicr_debug_log( "[WEBPICR DEBUG] Already converted, skipping" );
            delete_transient( $processing_key );
            return $metadata;
        }
        webpicr_debug_log( "[WEBPICR DEBUG] Starting silent conversion for attachment ID: {$attachment_id}" );
        // CRITICAL: Remove our auto-convert hook BEFORE starting conversion to prevent infinite loops
        remove_filter( 'wp_generate_attachment_metadata', 'webpicr_auto_convert_on_upload', 10 );
        webpicr_debug_log( "[WEBPICR DEBUG] Temporarily removed auto-convert hook to prevent loops" );
        // Perform the conversion (reuse existing conversion logic)
        webpicr_convert_attachment_silently( $attachment_id );
        // Re-add our auto-convert hook after conversion is complete
        add_filter(
            'wp_generate_attachment_metadata',
            'webpicr_auto_convert_on_upload',
            10,
            2
        );
        webpicr_debug_log( "[WEBPICR DEBUG] Restored auto-convert hook after conversion" );
        // Return fresh metadata (WordPress will use the updated attachment)
        $fresh_metadata = wp_get_attachment_metadata( $attachment_id );
        webpicr_debug_log( "[WEBPICR DEBUG] Auto-convert completed for attachment ID: {$attachment_id}" );
        // Clear the processing flag
        delete_transient( $processing_key );
        return $fresh_metadata;
    }

    // Only add auto-convert hook for premium users
    if ( function_exists( 'webpicr_fs' ) && webpicr_fs()->can_use_premium_code__premium_only() ) {
        add_filter(
            'wp_generate_attachment_metadata',
            'webpicr_auto_convert_on_upload',
            10,
            2
        );
    }
    /**
     * Check if attachment is eligible for WebP conversion
     */
    function webpicr_is_attachment_eligible_for_conversion(  $attachment_id  ) {
        $post = get_post( $attachment_id );
        if ( !$post || $post->post_type !== 'attachment' ) {
            return false;
        }
        // Check MIME type - only convert supported formats
        $mime_type = get_post_mime_type( $attachment_id );
        $supported_types = array(
            'image/jpeg',
            'image/jpg',
            'image/png',
            'image/gif'
        );
        if ( !in_array( $mime_type, $supported_types, true ) ) {
            return false;
        }
        // For GIFs, check if animated (preserve animated GIFs)
        if ( $mime_type === 'image/gif' ) {
            $file_path = get_attached_file( $attachment_id );
            if ( $file_path ) {
                $is_static = webpicr_is_gif_animated_imagick( $file_path );
                if ( $is_static !== true ) {
                    // Animated or check failed
                    return false;
                    // Don't convert animated GIFs or failed checks
                }
            }
        }
        return true;
    }

    /**
     * Convert attachment silently (used for auto-conversion)
     */
    function webpicr_convert_attachment_silently(  $attachment_id  ) {
        // Reuse the existing conversion logic but without AJAX response
        // This essentially duplicates the core conversion logic from webpicr_ajax_convert_image_to_webp
        // but without the wp_send_json_* calls
        // Check for server support first
        if ( !webpicr_is_webp_supported() ) {
            update_post_meta( $attachment_id, '_webp_conversion_failed', 'no_editor_support' );
            // Increment the total media failed counter
            $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
            update_option( 'webpicr_total_media_failed', $total_failed + 1 );
            return false;
        }
        // Get original file path
        $original_file_path = get_attached_file( $attachment_id, true );
        if ( !$original_file_path || !file_exists( $original_file_path ) ) {
            update_post_meta( $attachment_id, '_webp_conversion_failed', 'file_missing' );
            // Increment the total media failed counter
            $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
            update_option( 'webpicr_total_media_failed', $total_failed + 1 );
            return false;
        }
        // Define temporary WebP path
        $path_parts = pathinfo( $original_file_path );
        $temp_webp_path = $path_parts['dirname'] . '/' . $path_parts['filename'] . '_temp.webp';
        // Convert to WebP
        $conversion_success = webpicr_convert_image_to_webp( $original_file_path, $temp_webp_path );
        // Clean up any existing failed conversion meta
        delete_post_meta( $attachment_id, '_webp_conversion_failed' );
        delete_post_meta( $attachment_id, '_webp_original_size' );
        delete_post_meta( $attachment_id, '_webp_generated_size' );
        if ( !$conversion_success || !file_exists( $temp_webp_path ) ) {
            update_post_meta( $attachment_id, '_webp_conversion_failed', 'conversion_error' );
            // Increment the total media failed counter
            $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
            update_option( 'webpicr_total_media_failed', $total_failed + 1 );
            if ( file_exists( $temp_webp_path ) ) {
                wp_delete_file( $temp_webp_path );
            }
            return false;
        }
        // Compare file sizes
        $original_metadata = wp_get_attachment_metadata( $attachment_id );
        $total_original_bytes = 0;
        $total_final_bytes = 0;
        // Calculate original sizes
        if ( $original_metadata && isset( $original_metadata['sizes'] ) ) {
            foreach ( $original_metadata['sizes'] as $size_name => $size_data ) {
                if ( isset( $size_data['file'] ) ) {
                    $size_file_path = dirname( $original_file_path ) . '/' . $size_data['file'];
                    if ( file_exists( $size_file_path ) ) {
                        $total_original_bytes += filesize( $size_file_path );
                    }
                }
            }
        }
        // Add main file size
        $original_main_filesize = filesize( $original_file_path );
        $total_original_bytes += $original_main_filesize;
        // Get WebP main file size
        $temp_webp_size = filesize( $temp_webp_path );
        $total_final_bytes = $temp_webp_size;
        // We'll add thumbnail sizes after conversion
        // Check if WebP main file is smaller
        if ( $temp_webp_size < $original_main_filesize ) {
            // Continue with full file replacement process
            // --- Phoenix Integration (if available) ---
            if ( class_exists( 'Phoenix_Media_Rename' ) && method_exists( 'Phoenix_Media_Rename', 'do_rename' ) ) {
                webpicr_debug_log( "[WEBPICR AUTO] Phoenix available - using Phoenix for extension change" );
                // Get current filename without extension
                $current_filename = pathinfo( $original_file_path, PATHINFO_FILENAME );
                // Call Phoenix to change extension to .webp (Phoenix handles all database updates)
                $phoenix_result = Phoenix_Media_Rename::do_rename(
                    $attachment_id,
                    $current_filename,
                    // Keep same filename
                    0,
                    // Don't retitle
                    0,
                    // Don't get title from post
                    0,
                    // Don't get name from post
                    false,
                    // Don't check post parent
                    false,
                    // Don't force lowercase
                    false,
                    // Don't force serialization
                    true,
                    // $rename = true (Phoenix handles file operations)
                    'webp'
                );
                if ( $phoenix_result === 1 ) {
                    webpicr_debug_log( "[WEBPICR AUTO] Phoenix successfully changed extension to .webp" );
                    // Get the new WebP file path that Phoenix created
                    $phoenix_webp_path = get_attached_file( $attachment_id );
                    // Replace Phoenix's file with our optimized WebP content
                    global $wp_filesystem;
                    if ( empty( $wp_filesystem ) ) {
                        require_once ABSPATH . 'wp-admin/includes/file.php';
                        WP_Filesystem();
                    }
                    $replace_success = $wp_filesystem->move( $temp_webp_path, $phoenix_webp_path, true );
                    if ( $replace_success ) {
                        webpicr_debug_log( "[WEBPICR AUTO] Successfully replaced Phoenix file with optimized WebP" );
                        // Regenerate metadata for the optimized WebP
                        $new_metadata = wp_generate_attachment_metadata( $attachment_id, $phoenix_webp_path );
                        if ( !is_wp_error( $new_metadata ) && $new_metadata ) {
                            wp_update_attachment_metadata( $attachment_id, $new_metadata );
                            webpicr_debug_log( "[WEBPICR AUTO] Metadata regenerated for optimized WebP" );
                        }
                        // Phoenix handled everything - finish with success
                        update_post_meta( $attachment_id, '_webpicr_converted_successfully', time() );
                        delete_post_meta( $attachment_id, '_webpicr_status' );
                        update_post_meta( $attachment_id, '_webpicr_status', 'converted' );
                        // Update counters
                        $total_converted = (int) get_option( 'webpicr_total_media_converted', 0 );
                        update_option( 'webpicr_total_media_converted', $total_converted + 1 );
                        // Clear statistics cache after successful conversion
                        webpicr_clear_statistics_cache();
                        $current_total_saved = (int) get_option( 'webpicr_total_bytes_saved', 0 );
                        $savings = $original_main_filesize - $temp_webp_size;
                        update_option( 'webpicr_total_bytes_saved', $current_total_saved + $savings );
                        webpicr_debug_log( "[WEBPICR AUTO] Phoenix conversion completed successfully" );
                        return true;
                        // Phoenix handled everything successfully
                    } else {
                        webpicr_debug_log( "[WEBPICR AUTO] Failed to replace Phoenix file - falling back to manual process" );
                        // Fall through to manual process
                    }
                } else {
                    webpicr_debug_log( "[WEBPICR AUTO] Phoenix failed with result: " . wp_json_encode( $phoenix_result ) . " - falling back to manual process" );
                    // Fall through to manual process
                }
            }
            // --- Manual Process (fallback when Phoenix not available or fails) ---
            webpicr_debug_log( "[WEBPICR AUTO] Using manual process for file operations" );
            // --- Step 1: Create backup of original file ---
            global $wp_filesystem;
            if ( empty( $wp_filesystem ) ) {
                require_once ABSPATH . 'wp-admin/includes/file.php';
                WP_Filesystem();
            }
            $backup_created = false;
            $backup_file_path = $original_file_path . '.webpicr_backup';
            if ( file_exists( $original_file_path ) ) {
                $backup_created = $wp_filesystem->copy( $original_file_path, $backup_file_path, true );
            }
            // --- Step 2: Delete original file ---
            $original_deleted = false;
            if ( file_exists( $original_file_path ) ) {
                $original_deleted = wp_delete_file( $original_file_path );
            } else {
                $original_deleted = true;
            }
            if ( !$original_deleted ) {
                // Failed to delete original, restore backup and fail
                if ( $backup_created ) {
                    $wp_filesystem->move( $backup_file_path, $original_file_path, true );
                }
                wp_delete_file( $temp_webp_path );
                update_post_meta( $attachment_id, '_webp_conversion_failed', 'unlink_original_failed' );
                // Increment the total media failed counter
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                update_option( 'webpicr_total_media_failed', $total_failed + 1 );
                return false;
            }
            // --- Step 3: Rename temp WebP to final WebP path ---
            $path_parts = pathinfo( $original_file_path );
            $final_webp_path = $path_parts['dirname'] . '/' . $path_parts['filename'] . '.webp';
            $renamed = $wp_filesystem->move( $temp_webp_path, $final_webp_path, true );
            if ( !$renamed ) {
                // Critical error: original deleted, rename failed. Try restoring backup.
                if ( $backup_created ) {
                    $wp_filesystem->move( $backup_file_path, $original_file_path, true );
                }
                wp_delete_file( $temp_webp_path );
                update_post_meta( $attachment_id, '_webp_conversion_failed', 'rename_webp_failed' );
                // Increment the total media failed counter
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                update_option( 'webpicr_total_media_failed', $total_failed + 1 );
                return false;
            }
            // --- Step 4: Update post mime type and attached file meta ---
            wp_update_post( array(
                'ID'             => $attachment_id,
                'post_mime_type' => 'image/webp',
            ) );
            // Update _wp_attached_file meta with the new relative .webp path
            $uploads = wp_get_upload_dir();
            $relative_webp_path = ltrim( str_replace( $uploads['basedir'], '', $final_webp_path ), '/' );
            update_post_meta( $attachment_id, '_wp_attached_file', $relative_webp_path );
            // --- Step 5: Regenerate metadata and thumbnails for the new WebP file ---
            $new_metadata = wp_generate_attachment_metadata( $attachment_id, $final_webp_path );
            if ( false === $new_metadata || is_wp_error( $new_metadata ) ) {
                // Metadata generation failed. Restore original file!
                if ( $backup_created ) {
                    wp_delete_file( $final_webp_path );
                    $restored = $wp_filesystem->move( $backup_file_path, $original_file_path, true );
                    if ( $restored ) {
                        // Restore original mime type & attached file meta
                        $original_mime = mime_content_type( $original_file_path );
                        if ( $original_mime ) {
                            wp_update_post( array(
                                'ID'             => $attachment_id,
                                'post_mime_type' => $original_mime,
                            ) );
                            $relative_original_path = ltrim( str_replace( $uploads['basedir'], '', $original_file_path ), '/' );
                            update_post_meta( $attachment_id, '_wp_attached_file', $relative_original_path );
                        }
                    }
                }
                update_post_meta( $attachment_id, '_webpicr_conversion_failed', 'metadata_error' );
                update_post_meta( $attachment_id, '_webpicr_status', 'failed' );
                // Increment the total media failed counter
                $total_failed = (int) get_option( 'webpicr_total_media_failed', 0 );
                update_option( 'webpicr_total_media_failed', $total_failed + 1 );
                return false;
            }
            // --- Step 6: Update metadata in database ---
            wp_update_attachment_metadata( $attachment_id, $new_metadata );
            // --- Step 6.5: Force MIME type update again (wp_generate_attachment_metadata may have overwritten it) ---
            wp_update_post( array(
                'ID'             => $attachment_id,
                'post_mime_type' => 'image/webp',
            ) );
            // --- Step 7: Calculate final total size from new metadata ---
            $final_metadata = wp_get_attachment_metadata( $attachment_id );
            $total_final_bytes = 0;
            if ( !empty( $final_metadata['filesize'] ) ) {
                $total_final_bytes += (int) $final_metadata['filesize'];
            }
            if ( !empty( $final_metadata['sizes'] ) && is_array( $final_metadata['sizes'] ) ) {
                $final_webp_path_current = get_attached_file( $attachment_id );
                $final_basedir = dirname( $final_webp_path_current );
                $counted_final_files = array();
                foreach ( $final_metadata['sizes'] as $size => $size_info ) {
                    if ( empty( $size_info['file'] ) ) {
                        continue;
                    }
                    $filename = $size_info['file'];
                    if ( in_array( $filename, $counted_final_files, true ) ) {
                        continue;
                    }
                    if ( !empty( $size_info['filesize'] ) ) {
                        $total_final_bytes += (int) $size_info['filesize'];
                        $counted_final_files[] = $filename;
                    } else {
                        // Fallback if filesize meta is missing
                        $webp_thumb_path = $final_basedir . '/' . $size_info['file'];
                        if ( file_exists( $webp_thumb_path ) ) {
                            $thumb_size = filesize( $webp_thumb_path );
                            if ( $thumb_size !== false ) {
                                $total_final_bytes += $thumb_size;
                                $counted_final_files[] = $filename;
                            }
                        }
                    }
                }
            }
            // --- Step 8: Store size metadata and update global counters ---
            update_post_meta( $attachment_id, '_webpicr_total_original_size', $total_original_bytes );
            update_post_meta( $attachment_id, '_webpicr_total_final_size', $total_final_bytes );
            // Update global savings tracker
            $saved_bytes = $total_original_bytes - $total_final_bytes;
            if ( $saved_bytes < 0 ) {
                $saved_bytes = 0;
            }
            $total_saved = (int) get_option( 'webpicr_total_bytes_saved', 0 );
            $new_total_saved = $total_saved + $saved_bytes;
            update_option( 'webpicr_total_bytes_saved', $new_total_saved );
            // Increment the total media converted counter
            $total_converted = (int) get_option( 'webpicr_total_media_converted', 0 );
            update_option( 'webpicr_total_media_converted', $total_converted + 1 );
            // Clear statistics cache after successful conversion
            webpicr_clear_statistics_cache();
            // Mark as successfully converted
            update_post_meta( $attachment_id, '_webp_converted_successfully', '1' );
            // Clean up backup file
            if ( $backup_created && file_exists( $backup_file_path ) ) {
                wp_delete_file( $backup_file_path );
            }
            return true;
        } else {
            // WebP main file not smaller, delete temp file and mark as skipped
            wp_delete_file( $temp_webp_path );
            update_post_meta( $attachment_id, '_webp_conversion_failed', 'webp_not_smaller' );
            update_post_meta( $attachment_id, '_webpicr_original_main_size', $original_main_filesize );
            update_post_meta( $attachment_id, '_webpicr_generated_webp_size', $temp_webp_size );
            // Increment the total media skipped counter
            $total_skipped = (int) get_option( 'webpicr_total_media_skipped', 0 );
            update_option( 'webpicr_total_media_skipped', $total_skipped + 1 );
            return false;
        }
    }

    /**
     * Settings section callback - displays the bulk optimize interface
     */
    function webpicr_bulk_optimize_section_callback() {
        // Check if we should start bulk processing (via AJAX)
        $should_start = false;
        $bulk_all_ids = array();
        // Note: Actual start is now handled via AJAX, not GET parameters
        // Get statistics
        $stats = webpicr_get_bulk_all_statistics();
        // Get total savings for display
        $total_saved = (int) get_option( 'webpicr_total_bytes_saved', 0 );
        $formatted_savings = webpicr_format_bytes( $total_saved );
        ?>
        <div id="webpicr-bulk-optimize-all-section">
            <p><?php 
        esc_html_e( 'Convert all eligible images in your media library to WebP format.', 'webp-image-converter-replacer' );
        ?></p>
            
            <!-- Phoenix Media Rename Integration Status -->
            <?php 
        webpicr_render_phoenix_integration_status();
        ?>
            
            <!-- Fix WebP MIME Types Utility -->
            <?php 
        webpicr_render_fix_mime_types_utility();
        ?>
            
            <!-- Statistics Overview - Available to ALL users -->
            <div class="webpicr-bulk-stats" style="background: #f9f9f9; padding: 15px; border-radius: 4px; margin: 15px 0;">
                <h4 style="margin-top: 0;"><?php 
        esc_html_e( 'Optimization Overview', 'webp-image-converter-replacer' );
        ?></h4>
                <ul style="margin-bottom: 0;">
                    <li><strong><?php 
        echo esc_html( number_format( $stats['total_images'] ) );
        ?></strong> <?php 
        esc_html_e( 'Total convertible images (JPGs, PNGs, static GIFs)', 'webp-image-converter-replacer' );
        ?></li>
                    <li><strong><?php 
        echo esc_html( number_format( $stats['already_converted'] ) );
        ?></strong> <?php 
        esc_html_e( 'Already converted', 'webp-image-converter-replacer' );
        ?></li>
                    <li><strong><?php 
        echo esc_html( number_format( $stats['eligible'] ) );
        ?></strong> <?php 
        esc_html_e( 'Remaining to convert', 'webp-image-converter-replacer' );
        ?></li>
                    <li><strong><?php 
        echo esc_html( number_format( $stats['skipped'] ) );
        ?></strong> <?php 
        esc_html_e( 'Total skipped', 'webp-image-converter-replacer' );
        ?></li>
                    <li><strong><?php 
        echo esc_html( number_format( $stats['failed'] ) );
        ?></strong> <?php 
        esc_html_e( 'Total failed', 'webp-image-converter-replacer' );
        ?></li>
                    <li><strong><?php 
        echo esc_html( $formatted_savings );
        ?></strong> <?php 
        esc_html_e( 'Total space saved', 'webp-image-converter-replacer' );
        ?></li>
                </ul>
            </div>
            
            <?php 
        if ( function_exists( 'webpicr_fs' ) && webpicr_fs()->can_use_premium_code__premium_only() ) {
            ?>
                
                <!-- Auto-convert on upload setting -->
                <div class="webpicr-auto-convert-setting" style="background: #f0f6fc; border: 1px solid #c7d2fe; border-radius: 4px; padding: 15px; margin: 15px 0;">
                    <h4 style="margin-top: 0;"><?php 
            esc_html_e( 'Auto-Convert on Upload', 'webp-image-converter-replacer' );
            ?></h4>
                    
                    <label style="display: flex; align-items: flex-start; gap: 10px; cursor: pointer;">
                        <input type="checkbox" 
                               id="webpicr_auto_convert_uploads" 
                               name="webpicr_auto_convert_uploads" 
                               value="1" 
                               <?php 
            checked( get_option( 'webpicr_auto_convert_uploads', false ) );
            ?>
                               style="margin-top: 2px;" />
                        <div>
                            <strong><?php 
            esc_html_e( 'Automatically convert eligible images when uploaded', 'webp-image-converter-replacer' );
            ?></strong>
                            <p style="margin: 5px 0 0 0; color: #666; font-size: 13px;">
                                <?php 
            esc_html_e( 'New images will be converted to WebP automatically if the WebP version is smaller than the original. Supported formats: JPEG, PNG, and static GIF. Animated GIFs are preserved. This happens seamlessly during upload - editors will automatically receive the WebP version.', 'webp-image-converter-replacer' );
            ?>
                            </p>
                        </div>
                    </label>
                </div>
                
                <?php 
            if ( $stats['eligible'] > 0 ) {
                ?>
                    <div class="webpicr-bulk-warning" style="background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 15px 0;">
                        <h4 style="margin-top: 0; color: #856404;"><?php 
                esc_html_e( 'Important Notice', 'webp-image-converter-replacer' );
                ?></h4>
                        <ul style="margin-bottom: 0; color: #856404;">
                            <li><?php 
                esc_html_e( 'Keep this browser tab open during the entire process', 'webp-image-converter-replacer' );
                ?></li>
                            <li><?php 
                esc_html_e( 'The process can be paused and resumed if needed', 'webp-image-converter-replacer' );
                ?></li>
                            <li><?php 
                esc_html_e( 'Progress will be saved automatically', 'webp-image-converter-replacer' );
                ?></li>
                            <li><?php 
                esc_html_e( 'Large libraries may take considerable time', 'webp-image-converter-replacer' );
                ?></li>
                        </ul>
                    </div>

                    <p>
                        <button type="button" id="webpicr-start-bulk-all-btn" class="button button-primary">
                            <?php 
                esc_html_e( 'Start Bulk Optimization', 'webp-image-converter-replacer' );
                ?>
                        </button>
                    </p>
                <?php 
            } else {
                ?>
                    <div class="notice notice-info inline">
                        <p><?php 
                esc_html_e( 'All eligible images have already been converted!', 'webp-image-converter-replacer' );
                ?></p>
                    </div>
                <?php 
            }
            ?>

            <?php 
        } else {
            ?>
                <!-- Auto-Convert on Upload Premium Upsell -->
                <div class="webpicr-auto-convert-upsell" style="background: #f0f6fc; border: 1px solid #c7d2fe; border-radius: 4px; padding: 20px; margin: 15px 0;">
                    <div style="display: flex; align-items: flex-start; gap: 15px;">
                        <span style="color: #3858e9; font-size: 24px; margin-top: 5px;">⚡</span>
                        <div style="flex: 1; text-align: left;">
                            <h3 style="margin: 0 0 10px 0; color: #1e40af;"><?php 
            esc_html_e( 'Auto-Convert on Upload - Premium Feature', 'webp-image-converter-replacer' );
            ?></h3>
                            <p style="margin: 0 0 15px 0; color: #1e40af;">
                                <?php 
            esc_html_e( 'Automatically convert new uploads to WebP format! Every image you upload will be instantly optimized if the WebP version is smaller, saving you time and storage space.', 'webp-image-converter-replacer' );
            ?>
                            </p>
                            
                            <div style="background: rgba(255,255,255,0.7); padding: 12px; border-radius: 3px; font-size: 14px; margin-bottom: 15px;">
                                <strong><?php 
            esc_html_e( 'Premium Benefits:', 'webp-image-converter-replacer' );
            ?></strong>
                                <ul style="margin: 8px 0 0 0; padding-left: 20px;">
                                    <li><?php 
            esc_html_e( 'Automatic conversion on every upload', 'webp-image-converter-replacer' );
            ?></li>
                                    <li><?php 
            esc_html_e( 'Seamless editor integration', 'webp-image-converter-replacer' );
            ?></li>
                                    <li><?php 
            esc_html_e( 'Instant space savings', 'webp-image-converter-replacer' );
            ?></li>
                                    <li><?php 
            esc_html_e( 'No manual intervention needed', 'webp-image-converter-replacer' );
            ?></li>
                                </ul>
                            </div>
                            
                            <?php 
            if ( function_exists( 'webpicr_fs' ) ) {
                ?>
                                <a href="<?php 
                echo esc_url( webpicr_fs()->get_upgrade_url() );
                ?>" class="button button-primary" target="_blank" style="margin-right: 10px;">
                                    <?php 
                esc_html_e( 'Upgrade to Premium', 'webp-image-converter-replacer' );
                ?>
                                </a>
                            <?php 
            }
            ?>
                        </div>
                    </div>
                </div>

                <!-- Bulk Optimize All Premium Upsell -->
                <div class="webpicr-premium-upsell" style="background: #f0f6fc; border: 1px solid #c7d2fe; border-radius: 4px; padding: 20px; text-align: center;">
                    <h3 style="margin-top: 0;"><?php 
            esc_html_e( 'Bulk Optimize All - Premium Feature', 'webp-image-converter-replacer' );
            ?></h3>
                    <p><?php 
            esc_html_e( 'Convert all your images with one click! This premium feature processes your entire media library automatically.', 'webp-image-converter-replacer' );
            ?></p>
                    
                    <div style="margin: 20px 0;">
                        <strong><?php 
            echo esc_html( number_format( $stats['eligible'] ) );
            ?></strong> 
                        <?php 
            esc_html_e( 'images ready to convert', 'webp-image-converter-replacer' );
            ?>
                    </div>

                    <?php 
            if ( function_exists( 'webpicr_fs' ) ) {
                ?>
                        <a href="<?php 
                echo esc_url( webpicr_fs()->get_upgrade_url() );
                ?>" class="button button-primary" target="_blank">
                            <?php 
                esc_html_e( 'Upgrade to Premium', 'webp-image-converter-replacer' );
                ?>
                        </a>
                    <?php 
            }
            ?>
                </div>
            <?php 
        }
        ?>
        </div>

        <script type="text/javascript">
            // Always pass the AJAX configuration for settings page
            var webpicr_bulk_all_vars = {
                webpicrStartBulkAll: false, // Will be set to true when button is clicked
                webpicrBulkAllIds: [], // Will be populated via AJAX when starting
                ajaxurl: '<?php 
        echo esc_url( admin_url( 'admin-ajax.php' ) );
        ?>',
                nonce: '<?php 
        echo esc_js( wp_create_nonce( 'webpicr_ajax_convert_nonce' ) );
        ?>',
                get_ids_nonce: '<?php 
        echo esc_js( wp_create_nonce( 'webpicr_get_bulk_ids_nonce' ) );
        ?>'
            };
        </script>
        <?php 
    }

    /**
     * Get statistics for bulk optimize all feature
     * 
     * @return array Array with stats: 
     *   - total_images: Total convertible images (JPEGs, PNGs, static GIFs) - excludes animated GIFs, etc.
     *   - already_converted: Successfully converted images
     *   - eligible: Currently eligible for conversion
     *   - skipped: Images that were skipped (animated GIFs, WebP not smaller, etc.)
     *   - failed: Images that failed to convert
     */
    function webpicr_get_bulk_all_statistics() {
        global $wpdb;
        // Use the same filtering as the actual bulk converter for consistency
        // Calculate total convertible images by counting:
        // 1. Already converted images (now WebP)
        // 2. Currently eligible images (JPEGs, PNGs, static GIFs)
        // 3. Skipped/failed images (were convertible but didn't convert)
        // This gives us the true count of "convertible" images (excluding animated GIFs, etc.)
        // Get already converted using the tracked counter (with fallback for legacy)
        $already_converted = get_option( 'webpicr_total_media_converted', false );
        if ( $already_converted === false ) {
            // Fallback for legacy installations - calculate from database using new status system with caching
            $cache_key = 'webpicr_legacy_converted_count';
            $already_converted = wp_cache_get( $cache_key );
            if ( $already_converted === false ) {
                $already_converted = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                     INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                     WHERE p.post_type = 'attachment' \n                     AND p.post_mime_type = 'image/webp'\n                     AND pm.meta_key = '_webpicr_status' AND pm.meta_value = 'converted'" );
                // Cache for 5 minutes
                wp_cache_set(
                    $cache_key,
                    $already_converted,
                    '',
                    300
                );
            }
        }
        $already_converted = (int) $already_converted;
        // Get failed conversions using global counter (with fallback for legacy)
        $failed = get_option( 'webpicr_total_media_failed', false );
        if ( $failed === false ) {
            // Fallback for legacy installations - calculate from database using new status system with caching
            $cache_key = 'webpicr_legacy_failed_count';
            $failed = wp_cache_get( $cache_key );
            if ( $failed === false ) {
                $failed = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                     INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                     WHERE p.post_type = 'attachment' \n                     AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                     AND pm.meta_key = '_webpicr_status' AND pm.meta_value = 'failed'" );
                // Cache for 5 minutes
                wp_cache_set(
                    $cache_key,
                    $failed,
                    '',
                    300
                );
            }
        }
        $failed = (int) $failed;
        // Get skipped conversions using global counter (with fallback for legacy)
        $skipped = get_option( 'webpicr_total_media_skipped', false );
        if ( $skipped === false ) {
            // Fallback for legacy installations - calculate from database using new status system with caching
            $cache_key = 'webpicr_legacy_skipped_count';
            $skipped = wp_cache_get( $cache_key );
            if ( $skipped === false ) {
                $skipped = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                     INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                     WHERE p.post_type = 'attachment' \n                     AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                     AND pm.meta_key = '_webpicr_status' AND pm.meta_value = 'skipped'" );
                // Cache for 5 minutes
                wp_cache_set(
                    $cache_key,
                    $skipped,
                    '',
                    300
                );
            }
        }
        $skipped = (int) $skipped;
        // Calculate remaining to convert using actual eligibility check for accuracy
        // This ensures statistics match what bulk convert will actually find
        $eligible_ids = webpicr_get_all_eligible_attachments();
        $eligible = count( $eligible_ids );
        // Calculate total convertible images: converted + eligible + skipped + failed
        // This excludes animated GIFs, unsupported formats, etc.
        $total_convertible = $already_converted + $eligible + $skipped + $failed;
        return array(
            'total_images'      => (int) $total_convertible,
            'already_converted' => (int) $already_converted,
            'eligible'          => (int) $eligible,
            'skipped'           => (int) $skipped,
            'failed'            => (int) $failed,
        );
    }

    /**
     * Get all attachment IDs that are eligible for WebP conversion
     * 
     * @return array Array of attachment IDs
     */
    function webpicr_get_all_eligible_attachments() {
        global $wpdb;
        // Check cache first
        $cache_key = 'webpicr_eligible_attachments_raw';
        $results = wp_cache_get( $cache_key );
        if ( $results === false ) {
            // Get all image attachments that haven't been processed using new status system
            $sql = $wpdb->prepare( "SELECT p.ID FROM {$wpdb->posts} p\n                    LEFT JOIN {$wpdb->postmeta} pm_status ON p.ID = pm_status.post_id AND pm_status.meta_key = %s\n                    WHERE p.post_type = %s\n                    AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                    AND pm_status.meta_value IS NULL\n                    ORDER BY p.post_date DESC", '_webpicr_status', 'attachment' );
            $results = $wpdb->get_col( $sql );
            // Cache for 2 minutes (shorter cache since this changes frequently during bulk operations)
            wp_cache_set(
                $cache_key,
                $results,
                '',
                120
            );
        }
        // Filter to only include actual image files that are truly convertible
        $eligible_ids = array();
        foreach ( $results as $id ) {
            if ( wp_attachment_is_image( $id ) ) {
                $file_path = get_attached_file( $id );
                if ( $file_path && file_exists( $file_path ) ) {
                    $mime_type = get_post_mime_type( $id );
                    // Only include supported convertible formats (exclude WebP)
                    $supported_types = array(
                        'image/jpeg',
                        'image/jpg',
                        'image/png',
                        'image/gif'
                    );
                    if ( in_array( $mime_type, $supported_types, true ) ) {
                        // Check if image exceeds WebP format limits (16,383 x 16,383)
                        $image_info = @getimagesize( $file_path );
                        if ( $image_info ) {
                            list( $width, $height ) = $image_info;
                            $webp_max_dimension = 16383;
                            // Skip if image exceeds WebP limits
                            if ( $width > $webp_max_dimension || $height > $webp_max_dimension ) {
                                continue;
                                // Skip this image
                            }
                        }
                        // For GIFs, exclude animated ones (preserve animated GIFs)
                        if ( $mime_type === 'image/gif' ) {
                            $is_static = webpicr_is_gif_animated_imagick( $file_path );
                            if ( $is_static === true ) {
                                // Static GIF (not animated)
                                $eligible_ids[] = (int) $id;
                                // Only non-animated GIFs
                            }
                            // Skip if animated ($is_static === false) or check failed ($is_static === null)
                        } else {
                            $eligible_ids[] = (int) $id;
                            // JPEG/PNG are always eligible
                        }
                    }
                }
            }
        }
        return $eligible_ids;
    }

    /**
     * AJAX handler to get eligible attachment IDs for bulk optimization
     */
    function webpicr_ajax_get_bulk_all_ids() {
        global $wpdb;
        // Security checks
        if ( !check_ajax_referer( 'webpicr_get_bulk_ids_nonce', 'nonce', false ) ) {
            wp_send_json_error( array(
                'message' => __( 'Security check failed.', 'webp-image-converter-replacer' ),
            ) );
        }
        if ( !current_user_can( 'upload_files' ) ) {
            wp_send_json_error( array(
                'message' => __( 'Insufficient permissions.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Premium check
        if ( !function_exists( 'webpicr_fs' ) || !webpicr_fs()->can_use_premium_code__premium_only() ) {
            wp_send_json_error( array(
                'message' => __( 'Premium feature only.', 'webp-image-converter-replacer' ),
            ) );
        }
        // Get eligible IDs
        $eligible_ids = webpicr_get_all_eligible_attachments();
        // Debug logging
        webpicr_debug_log( "[WEBPICR DEBUG] Eligible IDs count: " . count( $eligible_ids ) );
        webpicr_debug_log( "[WEBPICR DEBUG] First 5 eligible IDs: " . implode( ', ', array_slice( $eligible_ids, 0, 5 ) ) );
        // Generate nonces for each attachment
        $nonces = array();
        foreach ( $eligible_ids as $attachment_id ) {
            $nonces[$attachment_id] = wp_create_nonce( 'webpicr_convert_image_' . $attachment_id );
        }
        webpicr_debug_log( "[WEBPICR DEBUG] Nonces generated for: " . count( $nonces ) . " attachments" );
        // Get current total savings for display
        $current_total_savings = (int) get_option( 'webpicr_total_bytes_saved', 0 );
        $formatted_savings = webpicr_format_bytes( $current_total_savings );
        // Get current total converted count (initialize if doesn't exist yet)
        $current_converted_count = get_option( 'webpicr_total_media_converted', false );
        // Smart initialization: Only calculate if option doesn't exist AND we have byte savings (legacy users)
        if ( $current_converted_count === false && $current_total_savings > 0 ) {
            $cache_key = 'webpicr_init_converted_count';
            $current_converted_count = wp_cache_get( $cache_key );
            if ( $current_converted_count === false ) {
                $current_converted_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                     INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                     WHERE p.post_type = 'attachment' \n                     AND p.post_mime_type = 'image/webp'\n                     AND pm.meta_key = '_webp_converted_successfully'" );
                // Cache for 5 minutes
                wp_cache_set(
                    $cache_key,
                    $current_converted_count,
                    '',
                    300
                );
            }
            // Initialize the option for future use (even if 0, so we don't query again)
            update_option( 'webpicr_total_media_converted', $current_converted_count );
        } elseif ( $current_converted_count === false ) {
            // New installation with no conversions yet - set to 0
            $current_converted_count = 0;
            update_option( 'webpicr_total_media_converted', 0 );
        }
        $current_converted_count = (int) $current_converted_count;
        // Get current total skipped count (initialize if doesn't exist yet)
        $current_skipped_count = get_option( 'webpicr_total_media_skipped', false );
        // Smart initialization: Only calculate if option doesn't exist AND we have byte savings (legacy users)
        if ( $current_skipped_count === false && $current_total_savings > 0 ) {
            $cache_key = 'webpicr_init_skipped_count';
            $current_skipped_count = wp_cache_get( $cache_key );
            if ( $current_skipped_count === false ) {
                $current_skipped_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                     INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                     WHERE p.post_type = 'attachment' \n                     AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                     AND pm.meta_key = '_webp_conversion_failed' AND pm.meta_value = 'webp_not_smaller'" );
                // Cache for 5 minutes
                wp_cache_set(
                    $cache_key,
                    $current_skipped_count,
                    '',
                    300
                );
            }
            // Initialize the option for future use (even if 0, so we don't query again)
            update_option( 'webpicr_total_media_skipped', $current_skipped_count );
        } elseif ( $current_skipped_count === false ) {
            // New installation with no conversions yet - set to 0
            $current_skipped_count = 0;
            update_option( 'webpicr_total_media_skipped', 0 );
        }
        $current_skipped_count = (int) $current_skipped_count;
        // Get current total failed count (initialize if doesn't exist yet)
        $current_failed_count = get_option( 'webpicr_total_media_failed', false );
        // Smart initialization: Only calculate if option doesn't exist AND we have byte savings (legacy users)
        if ( $current_failed_count === false && $current_total_savings > 0 ) {
            $cache_key = 'webpicr_init_failed_count';
            $current_failed_count = wp_cache_get( $cache_key );
            if ( $current_failed_count === false ) {
                $current_failed_count = $wpdb->get_var( "SELECT COUNT(DISTINCT p.ID) FROM {$wpdb->posts} p\n                     INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id\n                     WHERE p.post_type = 'attachment' \n                     AND p.post_mime_type IN ('image/jpeg', 'image/jpg', 'image/png', 'image/gif')\n                     AND pm.meta_key = '_webp_conversion_failed' AND pm.meta_value != 'webp_not_smaller'" );
                // Cache for 5 minutes
                wp_cache_set(
                    $cache_key,
                    $current_failed_count,
                    '',
                    300
                );
            }
            // Initialize the option for future use (even if 0, so we don't query again)
            update_option( 'webpicr_total_media_failed', $current_failed_count );
        } elseif ( $current_failed_count === false ) {
            // New installation with no conversions yet - set to 0
            $current_failed_count = 0;
            update_option( 'webpicr_total_media_failed', 0 );
        }
        $current_failed_count = (int) $current_failed_count;
        // For progress bar, use the count of eligible images (what we're actually processing)
        // This gives users realistic progress: "Converting 1 of 900" not "Converting 1 of 4000"
        $total_to_process = count( $eligible_ids );
        // Debug logging right before response
        webpicr_debug_log( "[WEBPICR DEBUG] Final eligible IDs count before response: " . count( $eligible_ids ) );
        webpicr_debug_log( "[WEBPICR DEBUG] Final eligible IDs: " . implode( ', ', array_slice( $eligible_ids, 0, 10 ) ) );
        webpicr_debug_log( "[WEBPICR DEBUG] Total to process: " . $total_to_process );
        wp_send_json_success( array(
            'attachment_ids'          => $eligible_ids,
            'nonces'                  => $nonces,
            'count'                   => $total_to_process,
            'total_convertible'       => (int) $total_to_process,
            'current_total_savings'   => $current_total_savings,
            'formatted_savings'       => $formatted_savings,
            'current_converted_count' => (int) $current_converted_count,
            'current_skipped_count'   => (int) $current_skipped_count,
            'current_failed_count'    => (int) $current_failed_count,
            'debug_timestamp'         => time(),
            'debug_first_5_ids'       => array_slice( $eligible_ids, 0, 5 ),
        ) );
    }

    add_action( 'wp_ajax_webpicr_get_bulk_all_ids', 'webpicr_ajax_get_bulk_all_ids' );
    // Schedule backup cleanup on plugin activation
    if ( function_exists( 'register_activation_hook' ) ) {
        register_activation_hook( __FILE__, function () {
            if ( !wp_next_scheduled( 'webpicr_cleanup_old_backups' ) ) {
                wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'webpicr_cleanup_old_backups' );
            }
        } );
        register_deactivation_hook( __FILE__, function () {
            wp_clear_scheduled_hook( 'webpicr_cleanup_old_backups' );
        } );
    }
    // Optional hygiene: purge any leftover backup options on uninstall
    // Use Freemius uninstall hook instead of WordPress core hook to allow proper tracking
    if ( function_exists( 'webpicr_fs' ) ) {
        webpicr_fs()->add_action( 'after_uninstall', 'webpicr_uninstall_cleanup' );
    }
    if ( !function_exists( 'webpicr_uninstall_cleanup' ) ) {
        function webpicr_uninstall_cleanup() {
            global $wpdb;
            // Check cache first
            $cache_key = 'webpicr_backup_options_list';
            $rows = wp_cache_get( $cache_key );
            if ( $rows === false ) {
                $prefix = 'webpicr_backup_';
                $option_pattern = $wpdb->esc_like( $prefix ) . '%';
                $rows = $wpdb->get_results( $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", $option_pattern ), ARRAY_A );
                // Cache for 10 minutes (backup options don't change frequently)
                wp_cache_set(
                    $cache_key,
                    $rows,
                    '',
                    600
                );
            }
            if ( empty( $rows ) ) {
                return;
            }
            foreach ( $rows as $row ) {
                delete_option( $row['option_name'] );
            }
        }

    }
    /**
     * One-time migration to implement the new _webpicr_status system
     * This function:
     * 1. Renames old _webp_ meta keys to _webpicr_ for proper namespacing
     * 2. Sets _webpicr_status based on existing conversion data
     * 3. Handles animated GIF detection and status setting
     */
    if ( !function_exists( 'webpicr_migrate_to_status_system' ) ) {
        function webpicr_migrate_to_status_system() {
            global $wpdb;
            // Check if migration already completed
            if ( get_option( 'webpicr_status_migration_completed', false ) ) {
                return;
            }
            webpicr_debug_log( '[WEBPICR MIGRATION] Starting status system migration...' );
            // Check if migration steps have already been completed (acts as caching mechanism)
            $migration_step1_done = get_option( 'webpicr_migration_step1_done', false );
            // Step 1: Rename old meta keys for proper namespacing
            if ( !$migration_step1_done ) {
                // phpcs:disable WordPress.DB.DirectDatabaseQuery -- One-time migration operation
                $wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_key = '_webpicr_converted_successfully' WHERE meta_key = '_webp_converted_successfully'" );
                $wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_key = '_webpicr_conversion_failed' WHERE meta_key = '_webp_conversion_failed'" );
                // Clean up deprecated keys (these were replaced with _webpicr_total_* keys)
                $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE meta_key IN ('_webp_original_size', '_webp_generated_size', '_webp_final_size')" );
                // phpcs:enable WordPress.DB.DirectDatabaseQuery
                update_option( 'webpicr_migration_step1_done', true );
            }
            webpicr_debug_log( '[WEBPICR MIGRATION] Renamed meta keys for proper namespacing' );
            // Check if status migration steps have already been completed
            $migration_step2_done = get_option( 'webpicr_migration_step2_done', false );
            // Step 2: Set status for successfully converted images
            if ( !$migration_step2_done ) {
                // phpcs:disable WordPress.DB.DirectDatabaseQuery -- One-time migration operation
                $converted_count = $wpdb->query( "\n            INSERT IGNORE INTO {$wpdb->postmeta} (post_id, meta_key, meta_value)\n            SELECT post_id, '_webpicr_status', 'converted'\n            FROM {$wpdb->postmeta} \n            WHERE meta_key = '_webpicr_converted_successfully'\n        " );
                // Step 3: Set status for failed conversions (excluding webp_not_smaller which is skipped)
                $failed_count = $wpdb->query( "\n            INSERT IGNORE INTO {$wpdb->postmeta} (post_id, meta_key, meta_value)\n            SELECT post_id, '_webpicr_status', 'failed'\n            FROM {$wpdb->postmeta} \n            WHERE meta_key = '_webpicr_conversion_failed' \n            AND meta_value != 'webp_not_smaller'\n        " );
                // Step 4: Set status for skipped conversions (webp_not_smaller)
                $skipped_count = $wpdb->query( "\n            INSERT IGNORE INTO {$wpdb->postmeta} (post_id, meta_key, meta_value)\n            SELECT post_id, '_webpicr_status', 'skipped'\n            FROM {$wpdb->postmeta} \n            WHERE meta_key = '_webpicr_conversion_failed' \n            AND meta_value = 'webp_not_smaller'\n        " );
                // phpcs:enable WordPress.DB.DirectDatabaseQuery
                update_option( 'webpicr_migration_step2_done', true );
            } else {
                // Steps already completed, set counts to 0 for logging
                $converted_count = 0;
                $failed_count = 0;
                $skipped_count = 0;
            }
            // Step 5: Handle animated GIFs - mark them as skipped
            if ( extension_loaded( 'imagick' ) ) {
                // Check cache first
                $cache_key = 'webpicr_gif_attachments_migration';
                $gif_attachments = wp_cache_get( $cache_key );
                if ( $gif_attachments === false ) {
                    // Get all GIF attachments that don't have a status yet
                    $gif_attachments = $wpdb->get_results( "\n                SELECT p.ID, pm_file.meta_value as file_path\n                FROM {$wpdb->posts} p\n                INNER JOIN {$wpdb->postmeta} pm_file ON p.ID = pm_file.post_id AND pm_file.meta_key = '_wp_attached_file'\n                LEFT JOIN {$wpdb->postmeta} pm_status ON p.ID = pm_status.post_id AND pm_status.meta_key = '_webpicr_status'\n                WHERE p.post_type = 'attachment' \n                AND p.post_mime_type = 'image/gif'\n                AND pm_status.meta_value IS NULL\n            " );
                    // Cache for 5 minutes (this is for migration, so temporary)
                    wp_cache_set(
                        $cache_key,
                        $gif_attachments,
                        '',
                        300
                    );
                }
                $animated_gif_count = 0;
                $upload_dir = wp_get_upload_dir();
                foreach ( $gif_attachments as $attachment ) {
                    $file_path = $upload_dir['basedir'] . '/' . $attachment->file_path;
                    if ( file_exists( $file_path ) ) {
                        $is_static = webpicr_is_gif_animated_imagick( $file_path );
                        if ( $is_static === false ) {
                            // Animated GIF - mark as skipped
                            // phpcs:disable WordPress.DB.DirectDatabaseQuery -- One-time migration operation for animated GIFs
                            $wpdb->insert( $wpdb->postmeta, array(
                                'post_id'    => $attachment->ID,
                                'meta_key'   => '_webpicr_status',
                                'meta_value' => 'skipped',
                            ) );
                            $wpdb->insert( $wpdb->postmeta, array(
                                'post_id'    => $attachment->ID,
                                'meta_key'   => '_webpicr_conversion_failed',
                                'meta_value' => 'animated_gif',
                            ) );
                            // phpcs:enable WordPress.DB.DirectDatabaseQuery
                            $animated_gif_count++;
                        }
                        // Note: Static GIFs without existing status remain unprocessed (eligible)
                    }
                }
                webpicr_debug_log( "[WEBPICR MIGRATION] Marked {$animated_gif_count} animated GIFs as skipped" );
            }
            // Step 6: Clean up any duplicate status entries (WordPress sometimes creates duplicates)
            // phpcs:disable WordPress.DB.DirectDatabaseQuery -- One-time migration cleanup operation
            $duplicate_cleanup = $wpdb->query( "\n        DELETE pm1 FROM {$wpdb->postmeta} pm1\n        INNER JOIN {$wpdb->postmeta} pm2 \n        WHERE pm1.meta_key = '_webpicr_status' \n        AND pm2.meta_key = '_webpicr_status'\n        AND pm1.post_id = pm2.post_id \n        AND pm1.meta_id > pm2.meta_id\n    " );
            // phpcs:enable WordPress.DB.DirectDatabaseQuery
            if ( $duplicate_cleanup > 0 ) {
                webpicr_debug_log( "[WEBPICR MIGRATION] Cleaned up {$duplicate_cleanup} duplicate status entries" );
            }
            // Mark migration as completed
            update_option( 'webpicr_status_migration_completed', true );
            update_option( 'webpicr_status_migration_timestamp', time() );
            webpicr_debug_log( "[WEBPICR MIGRATION] Migration completed! Converted: {$converted_count}, Failed: {$failed_count}, Skipped: {$skipped_count}" );
        }

    }
    // Run migration on admin_init (only once)
    add_action( 'admin_init', 'webpicr_migrate_to_status_system' );
    /**
     * Force refresh statistics cache after bulk operations
     */
    if ( !function_exists( 'webpicr_force_refresh_statistics' ) ) {
        function webpicr_force_refresh_statistics() {
            // Clear any WordPress object cache for our statistics
            wp_cache_delete( 'webpicr_bulk_all_statistics', 'webpicr' );
            wp_cache_delete( 'webpicr_eligible_count', 'webpicr' );
            wp_cache_delete( 'webpicr_converted_count', 'webpicr' );
            wp_cache_delete( 'webpicr_skipped_count', 'webpicr' );
            wp_cache_delete( 'webpicr_failed_count', 'webpicr' );
            // Also clear transients that might be caching statistics
            delete_transient( 'webpicr_statistics_cache' );
            delete_transient( 'webpicr_bulk_statistics' );
            webpicr_debug_log( "[WEBPICR CACHE] Forced refresh of all statistics caches" );
        }

    }
    /**
     * AJAX handler to refresh statistics after bulk operations complete
     */
    if ( !function_exists( 'webpicr_ajax_refresh_statistics' ) ) {
        function webpicr_ajax_refresh_statistics() {
            // Verify nonce for security
            $nonce = ( isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '' );
            if ( !wp_verify_nonce( $nonce, 'webpicr_refresh_stats_nonce' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'Security check failed.', 'webp-image-converter-replacer' ),
                ) );
            }
            if ( !current_user_can( 'upload_files' ) ) {
                wp_send_json_error( array(
                    'message' => __( 'You do not have permission to refresh statistics.', 'webp-image-converter-replacer' ),
                ) );
            }
            // Force refresh all statistics
            webpicr_force_refresh_statistics();
            // Get fresh statistics
            $stats = webpicr_get_bulk_all_statistics();
            wp_send_json_success( array(
                'message' => __( 'Statistics refreshed successfully.', 'webp-image-converter-replacer' ),
                'stats'   => $stats,
            ) );
        }

    }
    add_action( 'wp_ajax_webpicr_refresh_statistics', 'webpicr_ajax_refresh_statistics' );
    /**
     * Add inline script with nonce for statistics refresh
     */
    if ( !function_exists( 'webpicr_add_refresh_stats_nonce' ) ) {
        function webpicr_add_refresh_stats_nonce() {
            if ( is_admin() ) {
                $nonce = wp_create_nonce( 'webpicr_refresh_stats_nonce' );
                echo "<script type='text/javascript'>\n            window.webpicrRefreshStatsNonce = '{$nonce}';\n            </script>";
            }
        }

    }
    add_action( 'admin_head', 'webpicr_add_refresh_stats_nonce' );
    // Register settings section for ALL users (free and premium) - moved outside premium checks
    add_action( 'admin_init', 'webpicr_register_settings_section' );
    // Handle attachment deletion to update statistics and cleanup
    add_action( 'delete_attachment', 'webpicr_cleanup_meta_on_delete' );
}