//PixRefiner v3.4
// Helper function for formatting file sizes
function formatBytes($bytes, $precision = 2) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$bytes = max($bytes, 0);
$pow = ($bytes > 0) ? floor(log($bytes) / log(1024)) : 0;
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
// Limit default WordPress sizes to thumbnail only when auto-conversion is enabled
function wpturbo_limit_image_sizes($sizes) {
if (wpturbo_get_disable_auto_conversion()) {
return $sizes;
}
return isset($sizes['thumbnail']) ? ['thumbnail' => $sizes['thumbnail']] : $sizes;return ['thumbnail' => $sizes['thumbnail']];
}
//Global override for default sizes
add_filter('intermediate_image_sizes_advanced', function($sizes) {
if (!wpturbo_get_disable_auto_conversion()) {
return ['thumbnail' => [
'width' => 150,
'height' => 150,
'crop' => true
]];
}
return $sizes;
}, 99);
add_filter('intermediate_image_sizes_advanced', 'wpturbo_limit_image_sizes');
// Set thumbnail size to 150x150
function wpturbo_set_thumbnail_size() {
update_option('thumbnail_size_w', 150);
update_option('thumbnail_size_h', 150);
update_option('thumbnail_crop', 1);
}
add_action('admin_init', 'wpturbo_set_thumbnail_size');
// Register custom sizes (up to 3 additional sizes beyond the main one)
add_action('after_setup_theme', 'wpturbo_register_custom_sizes');
function wpturbo_register_custom_sizes() {
$mode = wpturbo_get_resize_mode();
if ($mode === 'width') {
$max_values = wpturbo_get_max_widths();
$additional_values = array_slice($max_values, 1, 3);
foreach ($additional_values as $width) {
add_image_size("custom-$width", $width, 0, false);
}
} else {
$max_values = wpturbo_get_max_heights();
$additional_values = array_slice($max_values, 1, 3);
foreach ($additional_values as $height) {
add_image_size("custom-$height", 0, $height, false);
}
}
}
// Get or set max widths (default to mobile-friendly set, limit to 4)
function wpturbo_get_max_widths() {
$value = get_option('webp_max_widths', '1920,1200,600,300');
$widths = array_map('absint', array_filter(explode(',', $value)));
$widths = array_filter($widths, function($w) { return $w > 0 && $w <= 9999; });
return array_slice($widths, 0, 4);
}
// Get or set max heights (default to mobile-friendly set, limit to 4)
function wpturbo_get_max_heights() {
$value = get_option('webp_max_heights', '1080,720,480,360');
$heights = array_map('absint', array_filter(explode(',', $value)));
$heights = array_filter($heights, function($h) { return $h > 0 && $h <= 9999; });
return array_slice($heights, 0, 4);
}
// Get or set resize mode
function wpturbo_get_resize_mode() {
return get_option('webp_resize_mode', 'width');
}
// Get or set quality (0-100)
function wpturbo_get_quality() {
return (int) get_option('webp_quality', 80);
}
// Get or set batch size
function wpturbo_get_batch_size() {
return (int) get_option('webp_batch_size', 5);
}
// Get or set preserve originals
function wpturbo_get_preserve_originals() {
return (bool) get_option('webp_preserve_originals', false);
}
// Get or set disable auto-conversion on upload
function wpturbo_get_disable_auto_conversion() {
return (bool) get_option('webp_disable_auto_conversion', false);
}
// Get or set minimum size threshold in KB (default to 0, meaning no minimum)
function wpturbo_get_min_size_kb() {
return (int) get_option('webp_min_size_kb', 0);
}
// Get or set whether to use AVIF instead of WebP
function wpturbo_get_use_avif() {
return (bool) get_option('webp_use_avif', false);
}
// Get excluded image IDs
function wpturbo_get_excluded_images() {
$excluded = get_option('webp_excluded_images', []);
return is_array($excluded) ? array_map('absint', $excluded) : [];
}
// Add an image to the excluded list
function wpturbo_add_excluded_image($attachment_id) {
$attachment_id = absint($attachment_id);
$excluded = wpturbo_get_excluded_images();
if (!in_array($attachment_id, $excluded)) {
$excluded[] = $attachment_id;
update_option('webp_excluded_images', array_unique($excluded));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Excluded image added: Attachment ID %d', 'wpturbo'), $attachment_id);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Remove an image from the excluded list
function wpturbo_remove_excluded_image($attachment_id) {
$attachment_id = absint($attachment_id);
$excluded = wpturbo_get_excluded_images();
$index = array_search($attachment_id, $excluded);
if ($index !== false) {
unset($excluded[$index]);
update_option('webp_excluded_images', array_values($excluded));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Excluded image removed: Attachment ID %d', 'wpturbo'), $attachment_id);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Ensure MIME types are supported in .htaccess (Apache only)
function wpturbo_ensure_mime_types() {
$htaccess_file = ABSPATH . '.htaccess';
if (!file_exists($htaccess_file) || !is_writable($htaccess_file)) {
return false;
}
$content = file_get_contents($htaccess_file);
$webp_mime = "AddType image/webp .webp";
$avif_mime = "AddType image/avif .avif";
if (strpos($content, $webp_mime) === false || strpos($content, $avif_mime) === false) {
$new_content = "# BEGIN WebP Converter MIME Types\n";
if (strpos($content, $webp_mime) === false) {
$new_content .= "$webp_mime\n";
}
if (strpos($content, $avif_mime) === false) {
$new_content .= "$avif_mime\n";
}
$new_content .= "# END WebP Converter MIME Types\n";
$content .= "\n" . $new_content;
file_put_contents($htaccess_file, $content);
return true;
}
return true;
}
// Core conversion function (supports WebP or AVIF)
function wpturbo_convert_to_format($file_path, $dimension, &$log = null, $attachment_id = null, $suffix = '') {
$use_avif = wpturbo_get_use_avif();
$format = $use_avif ? 'image/avif' : 'image/webp';
$extension = $use_avif ? '.avif' : '.webp';
$path_info = pathinfo($file_path);
$new_file_path = $path_info['dirname'] . '/' . $path_info['filename'] . $suffix . $extension;
$quality = wpturbo_get_quality();
$mode = wpturbo_get_resize_mode();
if (!(extension_loaded('imagick') || extension_loaded('gd'))) {
if ($log !== null) $log[] = sprintf(__('Error: No image library (Imagick/GD) available for %s', 'wpturbo'), basename($file_path));
return false;
}
$has_avif_support = (extension_loaded('imagick') && in_array('AVIF', Imagick::queryFormats())) || (extension_loaded('gd') && function_exists('imageavif'));
if ($use_avif && !$has_avif_support) {
if ($log !== null) $log[] = sprintf(__('Error: AVIF not supported on this server for %s', 'wpturbo'), basename($file_path));
return false;
}
$editor = wp_get_image_editor($file_path);
if (is_wp_error($editor)) {
if ($log !== null) $log[] = sprintf(__('Error: Image editor failed for %s - %s', 'wpturbo'), basename($file_path), $editor->get_error_message());
return false;
}
$dimensions = $editor->get_size();
$resized = false;
if ($mode === 'width' && $dimensions['width'] > $dimension) {
$editor->resize($dimension, null, false);
$resized = true;
} elseif ($mode === 'height' && $dimensions['height'] > $dimension) {
$editor->resize(null, $dimension, false);
$resized = true;
}
$result = $editor->save($new_file_path, $format, ['quality' => $quality]);
if (is_wp_error($result)) {
if ($log !== null) $log[] = sprintf(__('Error: Conversion failed for %s - %s', 'wpturbo'), basename($file_path), $result->get_error_message());
return false;
}
if ($log !== null) {
$log[] = sprintf(
__('Converted: %s → %s %s', 'wpturbo'),
basename($file_path),
basename($new_file_path),
$resized ? sprintf(__('(resized to %dpx %s, quality %d)', 'wpturbo'), $dimension, $mode, $quality) : sprintf(__('(quality %d)', 'wpturbo'), $quality)
);
}
return $new_file_path;
}
// Handle new uploads with format conversion
add_filter('wp_handle_upload', 'wpturbo_handle_upload_convert_to_format', 10, 1);
function wpturbo_handle_upload_convert_to_format($upload) {
if (wpturbo_get_disable_auto_conversion()) {
return $upload;
}
$file_extension = strtolower(pathinfo($upload['file'], PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'];
if (!in_array($file_extension, $allowed_extensions)) {
return $upload;
}
$use_avif = wpturbo_get_use_avif();
$format = $use_avif ? 'image/avif' : 'image/webp';
$extension = $use_avif ? '.avif' : '.webp';
$file_path = $upload['file'];
$uploads_dir = dirname($file_path);
$log = get_option('webp_conversion_log', []);
// Check if uploads directory is writable
if (!is_writable($uploads_dir)) {
$log[] = sprintf(__('Error: Uploads directory %s is not writable', 'wpturbo'), $uploads_dir);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
$file_size_kb = filesize($file_path) / 1024;
$min_size_kb = wpturbo_get_min_size_kb();
if ($min_size_kb > 0 && $file_size_kb < $min_size_kb) {
$log[] = sprintf(__('Skipped: %s (size %s KB < %d KB)', 'wpturbo'), basename($file_path), round($file_size_kb, 2), $min_size_kb);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$attachment_id = attachment_url_to_postid($upload['url']);
$new_files = [];
$success = true;
// Get original image dimensions
$editor = wp_get_image_editor($file_path);
if (is_wp_error($editor)) {
$log[] = sprintf(__('Error: Image editor failed for %s - %s', 'wpturbo'), basename($file_path), $editor->get_error_message());
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
$dimensions = $editor->get_size();
$original_width = $dimensions['width'];
// Convert only for sizes smaller than or equal to original width (in width mode)
$valid_max_values = $max_values;
if ($mode === 'width') {
$valid_max_values = array_filter($max_values, function($width, $index) use ($original_width) {
// Always include the first size (original) or sizes smaller than original width
return $index === 0 || $width <= $original_width;
}, ARRAY_FILTER_USE_BOTH);
}
// Convert all valid sizes and rollback if any fail
foreach ($valid_max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-{$dimension}";
$new_file_path = wpturbo_convert_to_format($file_path, $dimension, $log, $attachment_id, $suffix);
if ($new_file_path) {
if ($index === 0) {
$upload['file'] = $new_file_path;
$upload['url'] = str_replace(basename($file_path), basename($new_file_path), $upload['url']);
$upload['type'] = $format;
}
$new_files[] = $new_file_path;
} else {
$success = false;
break;
}
}
// Generate thumbnail
if ($success) {
$editor = wp_get_image_editor($file_path);
if (!is_wp_error($editor)) {
$editor->resize(150, 150, true);
$thumbnail_path = dirname($file_path) . '/' . pathinfo($file_path, PATHINFO_FILENAME) . '-150x150' . $extension;
$saved = $editor->save($thumbnail_path, $format, ['quality' => wpturbo_get_quality()]);
if (!is_wp_error($saved)) {
$log[] = sprintf(__('Generated thumbnail: %s', 'wpturbo'), basename($thumbnail_path));
$new_files[] = $thumbnail_path;
} else {
$success = false;
}
} else {
$success = false;
}
}
// Rollback if any conversion failed
if (!$success) {
foreach ($new_files as $file) {
if (file_exists($file)) @unlink($file);
}
$log[] = sprintf(__('Error: Conversion failed for %s, rolling back', 'wpturbo'), basename($file_path));
$log[] = sprintf(__('Original preserved: %s', 'wpturbo'), basename($file_path));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
// Update metadata only if all conversions succeeded
if ($attachment_id && !empty($new_files)) {
$metadata = wp_generate_attachment_metadata($attachment_id, $upload['file']);
if (!is_wp_error($metadata)) {
$base_name = pathinfo($file_path, PATHINFO_FILENAME);
$dirname = dirname($file_path);
// Add custom sizes
foreach ($valid_max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = "$dirname/$base_name-$dimension$extension";
if (file_exists($size_file)) {
$metadata['sizes']["custom-$dimension"] = [
'file' => "$base_name-$dimension$extension",
'width' => ($mode === 'width') ? $dimension : 0,
'height' => ($mode === 'height') ? $dimension : 0,
'mime-type' => $format
];
}
}
// Ensure thumbnail metadata is always updated
$thumbnail_file = "$dirname/$base_name-150x150$extension";
if (file_exists($thumbnail_file)) {
$metadata['sizes']['thumbnail'] = [
'file' => "$base_name-150x150$extension",
'width' => 150,
'height' => 150,
'mime-type' => $format
];
} else {
// Regenerate thumbnail if missing
$editor = wp_get_image_editor($upload['file']);
if (!is_wp_error($editor)) {
$editor->resize(150, 150, true);
$saved = $editor->save($thumbnail_file, $format, ['quality' => wpturbo_get_quality()]);
if (!is_wp_error($saved)) {
$metadata['sizes']['thumbnail'] = [
'file' => "$base_name-150x150$extension",
'width' => 150,
'height' => 150,
'mime-type' => $format
];
$log[] = sprintf(__('Regenerated missing thumbnail: %s', 'wpturbo'), basename($thumbnail_file));
}
}
}
$metadata['webp_quality'] = wpturbo_get_quality();
$metadata['pixrefiner_stamp'] = [
'format' => wpturbo_get_use_avif() ? 'avif' : 'webp',
'quality' => wpturbo_get_quality(),
'resize_mode' => wpturbo_get_resize_mode(),
'max_values' => array_values($valid_max_values), // Use valid sizes in stamp
];
update_attached_file($attachment_id, $upload['file']);
wp_update_post(['ID' => $attachment_id, 'post_mime_type' => $format]);
wp_update_attachment_metadata($attachment_id, $metadata);
if (!empty($metadata['pixrefiner_stamp'])) {
$log[] = "Stamp check for Attachment ID {$attachment_id}:";
$log[] = "Expected stamp: " . json_encode($metadata['pixrefiner_stamp']);
$log[] = "Existing stamp: none (new upload)";
}
} else {
$log[] = sprintf(__('Error: Metadata regeneration failed for %s - %s', 'wpturbo'), basename($file_path), $metadata->get_error_message());
}
}
// Delete original only if all conversions succeeded and not preserved
if ($file_extension !== ($use_avif ? 'avif' : 'webp') && file_exists($file_path) && !wpturbo_get_preserve_originals()) {
$attempts = 0;
$chmod_failed = false;
while ($attempts < 5 && file_exists($file_path)) {
if (!is_writable($file_path)) {
@chmod($file_path, 0644);
if (!is_writable($file_path)) {
if ($chmod_failed) {
$log[] = sprintf(__('Error: Cannot make %s writable after retry - skipping deletion', 'wpturbo'), basename($file_path));
break;
}
$chmod_failed = true;
}
}
if (@unlink($file_path)) {
$log[] = sprintf(__('Deleted original: %s', 'wpturbo'), basename($file_path));
break;
}
$attempts++;
sleep(1);
}
if (file_exists($file_path)) {
$log[] = sprintf(__('Error: Failed to delete original %s after 5 retries', 'wpturbo'), basename($file_path));
}
}
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
// Fix metadata for converted images
add_filter('wp_generate_attachment_metadata', 'wpturbo_fix_format_metadata', 10, 2);
function wpturbo_fix_format_metadata($metadata, $attachment_id) {
$use_avif = wpturbo_get_use_avif();
$extension = $use_avif ? 'avif' : 'webp';
$format = $use_avif ? 'image/avif' : 'image/webp';
$file = get_attached_file($attachment_id);
if (pathinfo($file, PATHINFO_EXTENSION) !== $extension) {
return $metadata;
}
$uploads = wp_upload_dir();
$file_path = $file;
$file_name = basename($file_path);
$dirname = dirname($file_path);
$base_name = pathinfo($file_name, PATHINFO_FILENAME);
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$metadata['file'] = str_replace($uploads['basedir'] . '/', '', $file_path);
$metadata['mime_type'] = $format;
foreach ($max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = "$dirname/$base_name-$dimension.$extension";
if (file_exists($size_file)) {
$metadata['sizes']["custom-$dimension"] = [
'file' => "$base_name-$dimension.$extension",
'width' => ($mode === 'width') ? $dimension : 0,
'height' => ($mode === 'height') ? $dimension : 0,
'mime-type' => $format
];
}
}
$thumbnail_file = "$dirname/$base_name-150x150.$extension";
if (file_exists($thumbnail_file)) {
$metadata['sizes']['thumbnail'] = [
'file' => "$base_name-150x150.$extension",
'width' => 150,
'height' => 150,
'mime-type' => $format
];
}
// Add stamp
$metadata['pixrefiner_stamp'] = [
'format' => $use_avif ? 'avif' : 'webp',
'quality' => wpturbo_get_quality(),
'resize_mode' => $mode,
'max_values' => $max_values,
];
// Log stamp
$log = get_option('webp_conversion_log', []);
$log[] = "Stamp set via metadata hook for Attachment ID {$attachment_id}:";
$log[] = "Stamp: " . json_encode($metadata['pixrefiner_stamp']);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $metadata;
}
//
function wpturbo_convert_single_image_checker($attachments) {
if (empty($attachments) || !is_array($attachments)) {
return;
}
$log = [];
foreach ($attachments as $attachment_id) {
$file_path = get_attached_file($attachment_id);
$ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
if (!file_exists($file_path) || in_array($ext, ['jpg', 'jpeg', 'png'])) {
$log[] = sprintf(__('Skipped: Missing or original format (%s) for Attachment ID %d', 'wpturbo'), $ext, $attachment_id);
continue;
}
$metadata = wp_get_attachment_metadata($attachment_id);
// Build the expected stamp from current settings
$expected_stamp = [
'format' => wpturbo_get_use_avif() ? 'avif' : 'webp',
'quality' => wpturbo_get_quality(),
'resize_mode' => wpturbo_get_resize_mode(),
'max_values' => (wpturbo_get_resize_mode() === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights(),
];
$existing_stamp = isset($metadata['pixrefiner_stamp']) ? $metadata['pixrefiner_stamp'] : null;
// Stamp comparison log
$log[] = "Stamp check for Attachment ID {$attachment_id}:";
$log[] = "Expected stamp: " . json_encode($expected_stamp);
$log[] = "Existing stamp: " . ($existing_stamp ? json_encode($existing_stamp) : 'none');
if (!empty($existing_stamp) && $existing_stamp !== $expected_stamp && empty($_GET['force_reconvert'])) {
foreach ($expected_stamp as $key => $value) {
if (!isset($existing_stamp[$key]) || $existing_stamp[$key] !== $value) {
$log[] = "Mismatch in stamp key '$key': expected " . json_encode($value) . " but got " . json_encode($existing_stamp[$key] ?? null);
}
}
}
// If already optimized and no force reconvert
if (!empty($existing_stamp) && $existing_stamp === $expected_stamp && empty($_GET['force_reconvert'])) {
$log[] = sprintf(__('Skipped: Already optimized Attachment ID %d', 'wpturbo'), $attachment_id);
continue;
}
// Proceed with conversion
$conversion_result = wpturbo_convert_image($file_path, $attachment_id); // <-- your custom image converter
if (!$conversion_result) {
$log[] = sprintf(__('Failed to convert Attachment ID %d.', 'wpturbo'), $attachment_id);
continue;
}
// If successful, update metadata with the new stamp
if (!empty($metadata)) {
$metadata['pixrefiner_stamp'] = $expected_stamp;
wp_update_attachment_metadata($attachment_id, $metadata);
}
$log[] = sprintf(__('Converted Attachment ID %d successfully.', 'wpturbo'), $attachment_id);
}
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $log;
}
function wpturbo_convert_single_image() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options') || !isset($_POST['offset'])) {
wp_send_json_error(__('Permission denied or invalid offset', 'wpturbo'));
}
$offset = absint($_POST['offset']);
$batch_size = wpturbo_get_batch_size();
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$current_ext = wpturbo_get_use_avif() ? 'avif' : 'webp';
$format = wpturbo_get_use_avif() ? 'image/avif' : 'image/webp';
$current_qual = wpturbo_get_quality();
wp_raise_memory_limit('image');
set_time_limit(max(30, 10 * $batch_size));
$attachments = get_posts([
'post_type' => 'attachment',
'post_mime_type' => ['image/jpeg', 'image/png', 'image/webp', 'image/avif'],
'posts_per_page' => $batch_size,
'offset' => $offset,
'fields' => 'ids',
'post__not_in' => wpturbo_get_excluded_images(),
]);
$log = get_option('webp_conversion_log', []);
if (empty($attachments)) {
update_option('webp_conversion_complete', true);
$log[] = "" . __('Conversion Complete', 'wpturbo') . ' : ' . __('No more images to process', 'wpturbo');
update_option('webp_conversion_log', array_slice((array) $log, -500));
wp_send_json_success(['complete' => true]);
}
foreach ($attachments as $attachment_id) {
$file_path = get_attached_file($attachment_id);
if (!file_exists($file_path)) continue;
// Skip if already optimized and settings match
$meta = wp_get_attachment_metadata($attachment_id);
$expected_stamp = [
'format' => $current_ext,
'quality' => $current_qual,
'resize_mode' => $mode,
'max_values' => $max_values,
];
$existing_stamp = isset($meta['pixrefiner_stamp']) ? $meta['pixrefiner_stamp'] : null;
if (!empty($existing_stamp) && $existing_stamp === $expected_stamp && empty($_GET['force_reconvert'])) {
$log[] = sprintf(__('Skipped: Already optimized Attachment ID %d', 'wpturbo'), $attachment_id);
continue;
}
$dirname = dirname($file_path);
$base_name = pathinfo($file_path, PATHINFO_FILENAME);
$ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
$new_files = [];
$success = true;
// DELETE OUTDATED or DUPLICATE SIZES FROM FILESYSTEM AND METADATA
$old_sizes = isset($meta['sizes']) ? $meta['sizes'] : [];
$main_size = $max_values[0] ?? null;
$meta['sizes'] = []; // Initialize sizes to empty to clear outdated entries
foreach ($old_sizes as $size_key => $size_data) {
if (preg_match('/custom-(\d+)/', $size_key, $m)) {
$old_dim = (int) $m[1];
$is_redundant = (
!in_array($old_dim, $max_values)
|| ($main_size && $old_dim === $main_size)
);
if ($is_redundant) {
$old_file = "$dirname/$base_name-$old_dim.$current_ext";
if (file_exists($old_file)) {
@unlink($old_file);
$log[] = sprintf(__('Deleted duplicate or outdated size: %s', 'wpturbo'), basename($old_file));
}
} else {
// Preserve valid sizes that still exist
$meta['sizes'][$size_key] = $size_data;
}
} else if ($size_key === 'thumbnail') {
// Always preserve thumbnail if it exists
$meta['sizes']['thumbnail'] = $size_data;
}
}
// Get original image dimensions
$editor = wp_get_image_editor($file_path);
if (is_wp_error($editor)) {
$log[] = sprintf(__('Error: Image editor failed for %s - %s', 'wpturbo'), basename($file_path), $editor->get_error_message());
continue;
}
$dimensions = $editor->get_size();
$original_width = $dimensions['width'];
// Filter max_values to include only sizes less than or equal to original width
$valid_max_values = $max_values;
if ($mode === 'width') {
$valid_max_values = array_filter($max_values, function($width, $index) use ($original_width) {
return $index === 0 || $width <= $original_width;
}, ARRAY_FILTER_USE_BOTH);
// Log skipped sizes for debugging
if (count($valid_max_values) < count($max_values)) {
$skipped = array_diff($max_values, $valid_max_values);
$log[] = sprintf(__('Skipped sizes %s for %s (original width %dpx)', 'wpturbo'), implode(', ', $skipped), basename($file_path), $original_width);
}
}
// GENERATE NEW SIZES
foreach ($valid_max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-$dimension";
$output = wpturbo_convert_to_format($file_path, $dimension, $log, $attachment_id, $suffix);
if ($output) {
if ($index === 0) {
update_attached_file($attachment_id, $output);
wp_update_post(['ID' => $attachment_id, 'post_mime_type' => $format]);
}
$new_files[] = $output;
} else {
$success = false;
break;
}
}
// GENERATE THUMBNAIL
$thumb_path = "$dirname/$base_name-150x150.$current_ext";
if (!file_exists($thumb_path)) {
$editor = wp_get_image_editor($file_path);
if (!is_wp_error($editor)) {
$editor->resize(150, 150, true);
$saved = $editor->save($thumb_path, $format, ['quality' => $current_qual]);
if (!is_wp_error($saved)) {
$new_files[] = $thumb_path;
$log[] = sprintf(__('Generated thumbnail: %s', 'wpturbo'), basename($thumb_path));
} else {
$success = false;
}
} else {
$success = false;
}
}
if (!$success) {
foreach ($new_files as $f) if (file_exists($f)) @unlink($f);
$log[] = sprintf(__('Error: Conversion failed for %s, rolled back.', 'wpturbo'), basename($file_path));
continue;
}
// UPDATE METADATA & STAMP
if (!empty($new_files)) {
$meta = wp_generate_attachment_metadata($attachment_id, $new_files[0]);
if (!is_wp_error($meta)) {
$meta['sizes'] = []; // Clear sizes again to ensure only new sizes are included
foreach ($valid_max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = "$dirname/$base_name-$dimension.$current_ext";
if (file_exists($size_file)) {
$meta['sizes']["custom-$dimension"] = [
'file' => "$base_name-$dimension.$current_ext",
'width' => ($mode === 'width') ? $dimension : 0,
'height' => ($mode === 'height') ? $dimension : 0,
'mime-type' => $format,
];
}
}
if (file_exists($thumb_path)) {
$meta['sizes']['thumbnail'] = [
'file' => "$base_name-150x150.$current_ext",
'width' => 150,
'height' => 150,
'mime-type' => $format,
];
}
$meta['webp_quality'] = $current_qual;
$meta['pixrefiner_stamp'] = $expected_stamp;
wp_update_attachment_metadata($attachment_id, $meta);
}
}
// DELETE ORIGINAL IF NOT PRESERVED
if (!wpturbo_get_preserve_originals() && file_exists($file_path) && $ext !== $current_ext) {
@unlink($file_path);
$log[] = sprintf(__('Deleted original: %s', 'wpturbo'), basename($file_path));
}
$log[] = sprintf(__('Converted Attachment ID %d successfully.', 'wpturbo'), $attachment_id);
}
update_option('webp_conversion_log', array_slice((array)$log, -500));
wp_send_json_success([
'complete' => false,
'offset' => $offset + $batch_size
]);
}
// Progress tracking via AJAX
function wpturbo_webp_conversion_status() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wpturbo'));
}
$total = wp_count_posts('attachment')->inherit;
$per_page = 50; // Chunk size for pagination
$converted = 0;
$skipped = 0;
// Validate total count
if ($total < 0) {
$log = get_option('webp_conversion_log', []);
$log[] = __('Error: Invalid attachment count detected', 'wpturbo');
update_option('webp_conversion_log', array_slice((array)$log, -500));
wp_send_json_error(__('Invalid attachment count', 'wpturbo'));
}
// Count converted images in chunks
for ($offset = 0; $offset < $total; $offset += $per_page) {
$chunk_result = get_posts([
'post_type' => 'attachment',
'post_mime_type' => wpturbo_get_use_avif() ? 'image/avif' : 'image/webp',
'posts_per_page' => $per_page,
'offset' => $offset,
'fields' => 'ids',
]);
$converted += count($chunk_result);
}
// Count skipped images in chunks
for ($offset = 0; $offset < $total; $offset += $per_page) {
$chunk_result = get_posts([
'post_type' => 'attachment',
'post_mime_type' => ['image/jpeg', 'image/png'],
'posts_per_page' => $per_page,
'offset' => $offset,
'fields' => 'ids',
]);
$skipped += count($chunk_result);
}
$remaining = $total - $converted - $skipped;
$excluded_images = wpturbo_get_excluded_images();
$excluded_data = [];
foreach ($excluded_images as $id) {
$thumbnail = wp_get_attachment_image_src($id, 'thumbnail');
$excluded_data[] = [
'id' => $id,
'title' => get_the_title($id),
'thumbnail' => $thumbnail ? $thumbnail[0] : ''
];
}
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
wp_send_json([
'total' => $total,
'converted' => $converted,
'skipped' => $skipped,
'remaining' => $remaining,
'excluded' => count($excluded_images),
'excluded_images' => $excluded_data,
'log' => get_option('webp_conversion_log', []),
'complete' => get_option('webp_conversion_complete', false),
'resize_mode' => $mode,
'max_values' => implode(', ', $max_values),
'max_widths' => implode(', ', wpturbo_get_max_widths()),
'max_heights' => implode(', ', wpturbo_get_max_heights()),
'quality' => wpturbo_get_quality(),
'preserve_originals' => wpturbo_get_preserve_originals(),
'disable_auto_conversion' => wpturbo_get_disable_auto_conversion(),
'min_size_kb' => wpturbo_get_min_size_kb(),
'use_avif' => wpturbo_get_use_avif()
]);
}
// Clear log
function wpturbo_clear_log() {
if (!isset($_GET['clear_log']) || !current_user_can('manage_options')) {
return false;
}
update_option('webp_conversion_log', [__('Log cleared', 'wpturbo')]);
return true;
}
// Reset to defaults
function wpturbo_reset_defaults() {
if (!isset($_GET['reset_defaults']) || !current_user_can('manage_options')) {
return false;
}
update_option('webp_max_widths', '1920,1200,600,300');
update_option('webp_max_heights', '1080,720,480,360');
update_option('webp_resize_mode', 'width');
update_option('webp_quality', 80);
update_option('webp_batch_size', 5);
update_option('webp_preserve_originals', false);
update_option('webp_disable_auto_conversion', false);
update_option('webp_min_size_kb', 0);
update_option('webp_use_avif', false);
$log = get_option('webp_conversion_log', []);
$log[] = __('Settings reset to defaults', 'wpturbo');
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
// Set max widths
function wpturbo_set_max_widths() {
if (!isset($_GET['set_max_width']) || !current_user_can('manage_options') || !isset($_GET['max_width'])) {
return false;
}
$max_widths = sanitize_text_field($_GET['max_width']);
$width_array = array_filter(array_map('absint', explode(',', $max_widths)));
$width_array = array_filter($width_array, function($w) { return $w > 0 && $w <= 9999; });
$width_array = array_slice($width_array, 0, 4);
if (!empty($width_array)) {
update_option('webp_max_widths', implode(',', $width_array));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Max widths set to: %spx', 'wpturbo'), implode(', ', $width_array));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set max heights
function wpturbo_set_max_heights() {
if (!isset($_GET['set_max_height']) || !current_user_can('manage_options') || !isset($_GET['max_height'])) {
return false;
}
$max_heights = sanitize_text_field($_GET['max_height']);
$height_array = array_filter(array_map('absint', explode(',', $max_heights)));
$height_array = array_filter($height_array, function($h) { return $h > 0 && $h <= 9999; });
$height_array = array_slice($height_array, 0, 4);
if (!empty($height_array)) {
update_option('webp_max_heights', implode(',', $height_array));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Max heights set to: %spx', 'wpturbo'), implode(', ', $height_array));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set resize mode
function wpturbo_set_resize_mode() {
if (!isset($_GET['set_resize_mode']) || !current_user_can('manage_options') || !isset($_GET['resize_mode'])) {
return false;
}
$mode = sanitize_text_field($_GET['resize_mode']);
if (in_array($mode, ['width', 'height'])) {
$current_mode = get_option('webp_resize_mode', 'width');
if ($current_mode !== $mode) {
update_option('webp_resize_mode', $mode);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Resize mode set to: %s', 'wpturbo'), $mode);
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
return true;
}
return false;
}
// Set quality
function wpturbo_set_quality() {
if (!isset($_GET['set_quality']) || !current_user_can('manage_options') || !isset($_GET['quality'])) {
return false;
}
$quality = absint($_GET['quality']);
if ($quality >= 0 && $quality <= 100) {
$current_quality = (int) get_option('webp_quality', 80);
if ($current_quality !== $quality) {
update_option('webp_quality', $quality);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Quality set to: %d', 'wpturbo'), $quality);
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
return true;
}
return false;
}
// Set batch size
function wpturbo_set_batch_size() {
if (!isset($_GET['set_batch_size']) || !current_user_can('manage_options') || !isset($_GET['batch_size'])) {
return false;
}
$batch_size = absint($_GET['batch_size']);
if ($batch_size > 0 && $batch_size <= 50) {
update_option('webp_batch_size', $batch_size);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Batch size set to: %d', 'wpturbo'), $batch_size);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set preserve originals
function wpturbo_set_preserve_originals() {
if (!isset($_GET['set_preserve_originals']) || !current_user_can('manage_options') || !isset($_GET['preserve_originals'])) {
return false;
}
$preserve = rest_sanitize_boolean($_GET['preserve_originals']);
$current_preserve = wpturbo_get_preserve_originals();
if ($current_preserve !== $preserve) {
update_option('webp_preserve_originals', $preserve);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Preserve originals set to: %s', 'wpturbo'), $preserve ? __('Yes', 'wpturbo') : __('No', 'wpturbo'));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set disable auto-conversion on upload
function wpturbo_set_disable_auto_conversion() {
if (!isset($_GET['set_disable_auto_conversion']) || !current_user_can('manage_options') || !isset($_GET['disable_auto_conversion'])) {
return false;
}
$disable = rest_sanitize_boolean($_GET['disable_auto_conversion']);
$current_disable = wpturbo_get_disable_auto_conversion();
if ($current_disable !== $disable) {
update_option('webp_disable_auto_conversion', $disable);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Auto-conversion on upload set to: %s', 'wpturbo'), $disable ? __('Disabled', 'wpturbo') : __('Enabled', 'wpturbo'));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set minimum size threshold
function wpturbo_set_min_size_kb() {
if (!isset($_GET['set_min_size_kb']) || !current_user_can('manage_options') || !isset($_GET['min_size_kb'])) {
return false;
}
$min_size = absint($_GET['min_size_kb']);
if ($min_size >= 0) {
$current_min_size = wpturbo_get_min_size_kb();
if ($current_min_size !== $min_size) {
update_option('webp_min_size_kb', $min_size);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Minimum size threshold set to: %d KB', 'wpturbo'), $min_size);
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
return true;
}
return false;
}
// Set use AVIF option and ensure MIME types
function wpturbo_set_use_avif() {
if (!isset($_GET['set_use_avif']) || !current_user_can('manage_options') || !isset($_GET['use_avif'])) {
return false;
}
$use_avif = rest_sanitize_boolean($_GET['use_avif']);
$current_use_avif = wpturbo_get_use_avif();
if ($current_use_avif !== $use_avif) {
update_option('webp_use_avif', $use_avif);
wpturbo_ensure_mime_types(); // Ensure MIME types are updated
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Conversion format set to: %s', 'wpturbo'), $use_avif ? 'AVIF' : 'WebP');
$log[] = __('Please reconvert all images to ensure consistency after changing formats.', 'wpturbo');
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Enhanced cleanup of leftover originals and alternate formats
function wpturbo_cleanup_leftover_originals() {
if (!isset($_GET['cleanup_leftover_originals']) || !current_user_can('manage_options')) {
return false;
}
$log = get_option('webp_conversion_log', []);
$uploads_dir = wp_upload_dir()['basedir'];
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($uploads_dir));
$deleted = 0;
$failed = 0;
$preserve_originals = wpturbo_get_preserve_originals();
$use_avif = wpturbo_get_use_avif();
$current_extension = $use_avif ? 'avif' : 'webp';
$alternate_extension = $use_avif ? 'webp' : 'avif';
$attachments = get_posts([
'post_type' => 'attachment',
'posts_per_page' => -1,
'fields' => 'ids',
'post_mime_type' => ['image/jpeg', 'image/png', 'image/webp', 'image/avif'],
]);
$active_files = [];
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$excluded_images = wpturbo_get_excluded_images();
foreach ($attachments as $attachment_id) {
$file = get_attached_file($attachment_id);
$metadata = wp_get_attachment_metadata($attachment_id);
$dirname = dirname($file);
$base_name = pathinfo($file, PATHINFO_FILENAME);
if (in_array($attachment_id, $excluded_images)) {
if ($file && file_exists($file)) $active_files[$file] = true;
$possible_extensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'];
foreach ($possible_extensions as $ext) {
$potential_file = "$dirname/$base_name.$ext";
if (file_exists($potential_file)) $active_files[$potential_file] = true;
}
foreach ($max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-{$dimension}";
foreach (['webp', 'avif'] as $ext) {
$file_path = "$dirname/$base_name$suffix.$ext";
if (file_exists($file_path)) $active_files[$file_path] = true;
}
}
$thumbnail_files = ["$dirname/$base_name-150x150.webp", "$dirname/$base_name-150x150.avif"];
foreach ($thumbnail_files as $thumbnail_file) {
if (file_exists($thumbnail_file)) $active_files[$thumbnail_file] = true;
}
if ($metadata && isset($metadata['sizes'])) {
foreach ($metadata['sizes'] as $size_data) {
$size_file = "$dirname/" . $size_data['file'];
if (file_exists($size_file)) $active_files[$size_file] = true;
}
}
continue;
}
if ($file && file_exists($file)) {
$active_files[$file] = true;
foreach ($max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-{$dimension}";
$current_file = "$dirname/$base_name$suffix.$current_extension";
if (file_exists($current_file)) $active_files[$current_file] = true;
}
$thumbnail_file = "$dirname/$base_name-150x150.$current_extension";
if (file_exists($thumbnail_file)) $active_files[$thumbnail_file] = true;
}
}
if (!$preserve_originals) {
foreach ($files as $file) {
if ($file->isDir()) continue;
$file_path = $file->getPathname();
$extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
if (!in_array($extension, ['webp', 'avif', 'jpg', 'jpeg', 'png'])) continue;
$relative_path = str_replace($uploads_dir . '/', '', $file_path);
$path_parts = explode('/', $relative_path);
$is_valid_path = (count($path_parts) === 1) || (count($path_parts) === 3 && is_numeric($path_parts[0]) && is_numeric($path_parts[1]));
if (!$is_valid_path || isset($active_files[$file_path])) continue;
if (in_array($extension, ['jpg', 'jpeg', 'png']) || $extension === $alternate_extension) {
$attempts = 0;
while ($attempts < 5 && file_exists($file_path)) {
if (!is_writable($file_path)) {
@chmod($file_path, 0644);
if (!is_writable($file_path)) {
$log[] = sprintf(__('Error: Cannot make %s writable - skipping deletion', 'wpturbo'), basename($file_path));
$failed++;
break;
}
}
if (@unlink($file_path)) {
$log[] = sprintf(__('Cleanup: Deleted %s', 'wpturbo'), basename($file_path));
$deleted++;
break;
}
$attempts++;
sleep(1);
}
if (file_exists($file_path)) {
$log[] = sprintf(__('Cleanup: Failed to delete %s', 'wpturbo'), basename($file_path));
$failed++;
}
}
}
}
$log[] = "" . __('Cleanup Complete', 'wpturbo') . " : " . sprintf(__('Deleted %d files, %d failed', 'wpturbo'), $deleted, $failed);
update_option('webp_conversion_log', array_slice((array)$log, -500));
foreach ($attachments as $attachment_id) {
if (in_array($attachment_id, $excluded_images)) continue;
$file_path = get_attached_file($attachment_id);
if (file_exists($file_path) && strtolower(pathinfo($file_path, PATHINFO_EXTENSION)) === $current_extension) {
$metadata = wp_get_attachment_metadata($attachment_id);
$thumbnail_file = $uploads_dir . '/' . dirname($metadata['file']) . '/' . pathinfo($file_path, PATHINFO_FILENAME) . '-150x150.' . $current_extension;
if (!file_exists($thumbnail_file)) {
$metadata = wp_generate_attachment_metadata($attachment_id, $file_path);
if (!is_wp_error($metadata)) {
wp_update_attachment_metadata($attachment_id, $metadata);
$log[] = sprintf(__('Regenerated thumbnail for %s', 'wpturbo'), basename($file_path));
}
}
}
}
$log[] = "" . __('Thumbnail Regeneration Complete', 'wpturbo') . " ";
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
// AJAX handlers for exclusion
add_action('wp_ajax_webp_add_excluded_image', 'wpturbo_add_excluded_image_ajax');
function wpturbo_add_excluded_image_ajax() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options') || !isset($_POST['attachment_id'])) {
wp_send_json_error(__('Permission denied or invalid attachment ID', 'wpturbo'));
}
$attachment_id = absint($_POST['attachment_id']);
if (wpturbo_add_excluded_image($attachment_id)) {
wp_send_json_success(['message' => __('Image excluded successfully', 'wpturbo')]);
} else {
wp_send_json_error(__('Image already excluded or invalid ID', 'wpturbo'));
}
}
add_action('wp_ajax_webp_remove_excluded_image', 'wpturbo_remove_excluded_image_ajax');
function wpturbo_remove_excluded_image_ajax() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options') || !isset($_POST['attachment_id'])) {
wp_send_json_error(__('Permission denied or invalid attachment ID', 'wpturbo'));
}
$attachment_id = absint($_POST['attachment_id']);
if (wpturbo_remove_excluded_image($attachment_id)) {
wp_send_json_success(['message' => __('Image removed from exclusion list', 'wpturbo')]);
} else {
wp_send_json_error(__('Image not in exclusion list', 'wpturbo'));
}
}
// Convert post content image URLs to current format
add_action('wp_ajax_convert_post_images_to_webp', 'wpturbo_convert_post_images_to_format');
function wpturbo_convert_post_images_to_format() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wpturbo'));
}
$log = get_option('webp_conversion_log', []);
function add_log_entry($message) {
global $log;
$log[] = "[" . date("Y-m-d H:i:s") . "] " . $message;
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
$use_avif = wpturbo_get_use_avif();
$extension = $use_avif ? 'avif' : 'webp';
add_log_entry(sprintf(__('Starting post/page/FSE-template image conversion to %s...', 'wpturbo'), $use_avif ? 'AVIF' : 'WebP'));
$public_post_types = get_post_types(['public' => true], 'names');
$fse_post_types = ['wp_template', 'wp_template_part', 'wp_block'];
$post_types = array_unique(array_merge($public_post_types, $fse_post_types));
$args = [
'post_type' => $post_types,
'posts_per_page' => -1,
'fields' => 'ids'
];
$posts = get_posts($args);
if (!$posts) {
add_log_entry(__('No posts/pages/FSE-templates found', 'wpturbo'));
wp_send_json_success(['message' => __('No posts/pages/FSE-templates found', 'wpturbo')]);
}
$upload_dir = wp_upload_dir();
$upload_baseurl = $upload_dir['baseurl'];
$upload_basedir = $upload_dir['basedir'];
$updated_count = 0;
$checked_images = 0;
foreach ($posts as $post_id) {
$content = get_post_field('post_content', $post_id);
$original_content = $content;
$content = preg_replace_callback(
'/ ]+src=["\']([^"\']+\.(?:jpg|jpeg|png))["\'][^>]*>/i',
function ($matches) use (&$checked_images, $upload_baseurl, $upload_basedir, $extension) {
$original_url = $matches[1];
if (strpos($original_url, $upload_baseurl) !== 0) {
add_log_entry("Skipping (external): {$original_url}");
return $matches[0];
}
$checked_images++;
$dirname = pathinfo($original_url, PATHINFO_DIRNAME);
$filename = pathinfo($original_url, PATHINFO_FILENAME);
$new_url = $dirname . '/' . $filename . '.' . $extension;
$scaled_url = $dirname . '/' . $filename . '-scaled.' . $extension;
$new_path = str_replace($upload_baseurl, $upload_basedir, $new_url);
$scaled_path = str_replace($upload_baseurl, $upload_basedir, $scaled_url);
if (file_exists($scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $scaled_url));
return str_replace($original_url, $scaled_url, $matches[0]);
}
if (file_exists($new_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $new_url));
return str_replace($original_url, $new_url, $matches[0]);
}
$base_name = preg_replace('/(-\d+x\d+|-scaled)$/', '', $filename);
$fallback_url = $dirname . '/' . $base_name . '.' . $extension;
$fallback_scaled_url = $dirname . '/' . $base_name . '-scaled.' . $extension;
$fallback_path = str_replace($upload_baseurl, $upload_basedir, $fallback_url);
$fallback_scaled_path = str_replace($upload_baseurl, $upload_basedir, $fallback_scaled_url);
if (file_exists($fallback_scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_scaled_url));
return str_replace($original_url, $fallback_scaled_url, $matches[0]);
}
if (file_exists($fallback_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_url));
return str_replace($original_url, $fallback_url, $matches[0]);
}
return $matches[0];
},
$content
);
$content = preg_replace_callback(
'/background-image\s*:\s*url\(\s*[\'"]?([^\'"]+\.(?:jpg|jpeg|png))[\'"]?\s*\)/i',
function ($matches) use (&$checked_images, $upload_baseurl, $upload_basedir, $extension) {
$original_url = $matches[1];
if (strpos($original_url, $upload_baseurl) !== 0) {
add_log_entry("Skipping BG (external): {$original_url}");
return $matches[0];
}
$checked_images++;
$dirname = pathinfo($original_url, PATHINFO_DIRNAME);
$filename = pathinfo($original_url, PATHINFO_FILENAME);
$new_url = $dirname . '/' . $filename . '.' . $extension;
$scaled_url = $dirname . '/' . $filename . '-scaled.' . $extension;
$new_path = str_replace($upload_baseurl, $upload_basedir, $new_url);
$scaled_path = str_replace($upload_baseurl, $upload_basedir, $scaled_url);
if (file_exists($scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $scaled_url));
return str_replace($original_url, $scaled_url, $matches[0]);
}
if (file_exists($new_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $new_url));
return str_replace($original_url, $new_url, $matches[0]);
}
$base_name = preg_replace('/(-\d+x\d+|-scaled)$/', '', $filename);
$fallback_url = $dirname . '/' . $base_name . '.' . $extension;
$fallback_scaled_url = $dirname . '/' . $base_name . '-scaled.' . $extension;
$fallback_path = str_replace($upload_baseurl, $upload_basedir, $fallback_url);
$fallback_scaled_path = str_replace($upload_baseurl, $upload_basedir, $fallback_scaled_url);
if (file_exists($fallback_scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_scaled_url));
return str_replace($original_url, $fallback_scaled_url, $matches[0]);
}
if (file_exists($fallback_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_url));
return str_replace($original_url, $fallback_url, $matches[0]);
}
return $matches[0];
},
$content
);
if ($content !== $original_content) {
wp_update_post(['ID' => $post_id, 'post_content' => $content]);
$updated_count++;
}
$thumbnail_id = get_post_thumbnail_id($post_id);
if ($thumbnail_id && !in_array($thumbnail_id, wpturbo_get_excluded_images())) {
$thumbnail_path = get_attached_file($thumbnail_id);
if ($thumbnail_path && !str_ends_with($thumbnail_path, '.' . $extension)) {
$new_path = preg_replace('/\.(jpg|jpeg|png)$/i', '.' . $extension, $thumbnail_path);
if (file_exists($new_path)) {
update_attached_file($thumbnail_id, $new_path);
wp_update_post(['ID' => $thumbnail_id, 'post_mime_type' => $use_avif ? 'image/avif' : 'image/webp']);
$metadata = wp_generate_attachment_metadata($thumbnail_id, $new_path);
wp_update_attachment_metadata($thumbnail_id, $metadata);
add_log_entry(sprintf(__('Updated thumbnail: %s → %s', 'wpturbo'), basename($thumbnail_path), basename($new_path)));
}
}
}
}
add_log_entry(sprintf(__('Checked %d images (including BG), updated %d items', 'wpturbo'), $checked_images, $updated_count));
wp_send_json_success(['message' => sprintf(__('Checked %d images (including BG), updated %d items', 'wpturbo'), $checked_images, $updated_count)]);
}
// Export all media as a ZIP file
add_action('wp_ajax_webp_export_media_zip', 'wpturbo_export_media_zip');
function wpturbo_export_media_zip() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wpturbo'));
}
wp_raise_memory_limit('admin');
set_time_limit(0);
$args = [
'post_type' => 'attachment',
'post_mime_type' => 'image',
'posts_per_page' => -1,
'fields' => 'ids',
];
$attachments = get_posts($args);
if (empty($attachments)) {
wp_send_json_error(__('No media files found', 'wpturbo'));
}
$temp_file = tempnam(sys_get_temp_dir(), 'webp_media_export_');
if (!$temp_file) {
wp_send_json_error(__('Failed to create temporary file', 'wpturbo'));
}
$zip = new ZipArchive();
if ($zip->open($temp_file, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
@unlink($temp_file);
wp_send_json_error(__('Failed to create ZIP archive', 'wpturbo'));
}
$upload_dir = wp_upload_dir()['basedir'];
$log = get_option('webp_conversion_log', []);
$possible_extensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'];
foreach ($attachments as $attachment_id) {
$file_path = get_attached_file($attachment_id);
if (!$file_path || !file_exists($file_path)) {
$log[] = sprintf(__('Skipped: Main file not found for Attachment ID %d', 'wpturbo'), $attachment_id);
continue;
}
$dirname = dirname($file_path);
$base_name = pathinfo($file_path, PATHINFO_FILENAME);
$relative_dir = str_replace($upload_dir . '/', '', $dirname);
// Add main file
$relative_path = $relative_dir . '/' . basename($file_path);
$zip->addFile($file_path, $relative_path);
$log[] = sprintf(__('Added to ZIP: %s (Attachment ID %d)', 'wpturbo'), basename($file_path), $attachment_id);
// Add metadata sizes
$metadata = wp_get_attachment_metadata($attachment_id);
if ($metadata && isset($metadata['sizes'])) {
foreach ($metadata['sizes'] as $size => $size_data) {
$size_file = $dirname . '/' . $size_data['file'];
if (file_exists($size_file)) {
$relative_size_path = $relative_dir . '/' . $size_data['file'];
$zip->addFile($size_file, $relative_size_path);
$log[] = sprintf(__('Added to ZIP: %s (size: %s, Attachment ID %d)', 'wpturbo'), $size_data['file'], $size, $attachment_id);
}
}
}
// Add all related files with the same base name
foreach ($possible_extensions as $ext) {
// Check for base file with different extensions (e.g., image.jpg, image.png)
$related_file = "$dirname/$base_name.$ext";
if (file_exists($related_file) && $related_file !== $file_path) {
$relative_related_path = $relative_dir . '/' . "$base_name.$ext";
$zip->addFile($related_file, $relative_related_path);
$log[] = sprintf(__('Added to ZIP: Related file %s (Attachment ID %d)', 'wpturbo'), "$base_name.$ext", $attachment_id);
}
// Check for sized versions (e.g., image-500.jpg, image-150x150.png)
$pattern = "$dirname/$base_name-*.$ext";
$related_files = glob($pattern);
foreach ($related_files as $related_file) {
// Skip if already added as main file or metadata size
if ($related_file === $file_path || in_array(basename($related_file), array_column($metadata['sizes'] ?? [], 'file'))) {
continue;
}
$relative_related_path = $relative_dir . '/' . basename($related_file);
$zip->addFile($related_file, $relative_related_path);
$log[] = sprintf(__('Added to ZIP: Related size %s (Attachment ID %d)', 'wpturbo'), basename($related_file), $attachment_id);
}
}
}
$zip->close();
update_option('webp_conversion_log', array_slice((array)$log, -500));
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="media_export_' . date('Y-m-d_H-i-s') . '.zip"');
header('Content-Length: ' . filesize($temp_file));
readfile($temp_file);
flush();
@unlink($temp_file);
exit;
}
// Custom srcset to include all sizes in current format
add_filter('wp_calculate_image_srcset', 'wpturbo_custom_srcset', 10, 5);
function wpturbo_custom_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) {
if (in_array($attachment_id, wpturbo_get_excluded_images())) {
return $sources;
}
$use_avif = wpturbo_get_use_avif();
$extension = $use_avif ? '.avif' : '.webp';
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$upload_dir = wp_upload_dir();
$base_path = $upload_dir['basedir'] . '/' . dirname($image_meta['file']);
$base_name = pathinfo($image_meta['file'], PATHINFO_FILENAME);
$base_url = $upload_dir['baseurl'] . '/' . dirname($image_meta['file']);
foreach ($max_values as $index => $dimension) {
if ($index === 0) continue;
$file = "$base_path/$base_name-$dimension$extension";
if (file_exists($file)) {
$size_key = "custom-$dimension";
$width = ($mode === 'width') ? $dimension : (isset($image_meta['sizes'][$size_key]['width']) ? $image_meta['sizes'][$size_key]['width'] : 0);
$sources[$width] = [
'url' => "$base_url/$base_name-$dimension$extension",
'descriptor' => 'w',
'value' => $width
];
}
}
$thumbnail_file = "$base_path/$base_name-150x150$extension";
if (file_exists($thumbnail_file)) {
$sources[150] = [
'url' => "$base_url/$base_name-150x150$extension",
'descriptor' => 'w',
'value' => 150
];
}
return $sources;
}
function wpturbo_convert_single_image_stamp_check($attachment_id) {
// Your existing settings - you might already have these defined elsewhere
$use_avif = false; // or however you detect AVIF
$current_quality = 80; // your WebP/AVIF quality setting
$mode = 'width'; // resize mode: width, height, or auto
$max_values = [1920, 1200, 600, 300]; // your target sizes
// 1. Load the current metadata
$metadata = wp_get_attachment_metadata($attachment_id);
if (!$metadata) {
return; // Can't process without metadata
}
// 2. Build the expected stamp
$expected_stamp = [
'format' => $use_avif ? 'avif' : 'webp',
'quality' => $current_quality,
'resize_mode' => $mode,
'max_values' => $max_values,
];
// 3. Check existing stamp
$stamp = isset($metadata['pixrefiner_stamp']) ? $metadata['pixrefiner_stamp'] : null;
// 4. Compare — if matches and no force, skip
if ($stamp === $expected_stamp && empty($_GET['force_reconvert'])) {
return; // Already converted correctly, no need to reprocess
}
// 5. If no match — continue normal conversion
// Now here you do your actual conversion logic like:
// - Resize images
// - Generate WebP / AVIF
// - Compress
// etc.
// (This part is your existing code that does the heavy work.)
// 6. After conversion, update the stamp
$metadata['pixrefiner_stamp'] = $expected_stamp;
wp_update_attachment_metadata($attachment_id, $metadata);
}
// Admin interface
add_action('admin_menu', function() {
add_media_page(
__('PixRefiner', 'wpturbo'),
__('PixRefiner', 'wpturbo'),
'manage_options',
'webp-converter',
'wpturbo_webp_converter_page'
);
});
function wpturbo_webp_converter_page() {
wp_enqueue_media();
wp_enqueue_script('media-upload');
wp_enqueue_style('media');
if (isset($_GET['set_max_width'])) wpturbo_set_max_widths();
if (isset($_GET['set_max_height'])) wpturbo_set_max_heights();
if (isset($_GET['set_resize_mode'])) wpturbo_set_resize_mode();
if (isset($_GET['set_quality'])) wpturbo_set_quality();
if (isset($_GET['set_batch_size'])) wpturbo_set_batch_size();
if (isset($_GET['set_preserve_originals'])) wpturbo_set_preserve_originals();
if (isset($_GET['set_disable_auto_conversion'])) wpturbo_set_disable_auto_conversion();
if (isset($_GET['set_min_size_kb'])) wpturbo_set_min_size_kb();
if (isset($_GET['set_use_avif'])) wpturbo_set_use_avif();
if (isset($_GET['cleanup_leftover_originals'])) wpturbo_cleanup_leftover_originals();
if (isset($_GET['clear_log'])) wpturbo_clear_log();
if (isset($_GET['reset_defaults'])) wpturbo_reset_defaults();
$has_image_library = extension_loaded('imagick') || extension_loaded('gd');
$has_avif_support = (extension_loaded('imagick') && in_array('AVIF', Imagick::queryFormats())) || (extension_loaded('gd') && function_exists('imageavif'));
$htaccess_file = ABSPATH . '.htaccess';
// Original check kept as comment for reference:
// $mime_configured = file_exists($htaccess_file) && strpos(file_get_contents($htaccess_file), 'AddType image/webp .webp') !== false;
$mime_configured = true; // Force to true to suppress the MIME type warning
?>
1. Resize Mode:
2. Set Max Sizes:
3. Min Size for Conversion:
4. Conversion Format:
5. Preserve Originals:
6. Disable Auto-Conversion:
7. Upload:
1. Repeat:
2. Run All:
1. Repeat:
2. Convert:
3. Cleanup:
4. Fix Links:
a) Usability:
b) Backups:
c) Export Media:
d) Reset Defaults:
e) Speed:
f) Log Wait:
g) Stop Anytime:
h) AVIF Needs:
i) Old Browsers:
j) MIME Types:
k) Rollback:
' . __('Conversion started. Monitor progress in Media.', 'wpturbo') . '
';
}
if (isset($_GET['set_max_width']) && wpturbo_set_max_widths()) {
echo '' . __('Max widths updated.', 'wpturbo') . '
';
}
if (isset($_GET['set_max_height']) && wpturbo_set_max_heights()) {
echo '' . __('Max heights updated.', 'wpturbo') . '
';
}
if (isset($_GET['reset_defaults']) && wpturbo_reset_defaults()) {
echo '' . __('Settings reset to defaults.', 'wpturbo') . '
';
}
if (isset($_GET['set_min_size_kb']) && wpturbo_set_min_size_kb()) {
echo '' . __('Minimum size threshold updated.', 'wpturbo') . '
';
}
if (isset($_GET['set_use_avif']) && wpturbo_set_use_avif()) {
echo '' . __('Conversion format updated. Please reconvert all images.', 'wpturbo') . '
';
}
});
// Custom image size names
add_filter('image_size_names_choose', 'wpturbo_disable_default_sizes', 999);
function wpturbo_disable_default_sizes($sizes) {
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$custom_sizes = ['thumbnail' => __('Thumbnail (150x150)', 'wpturbo')];
$additional_values = array_slice($max_values, 1, 3);
foreach ($additional_values as $value) {
$custom_sizes["custom-$value"] = ($mode === 'width') ? sprintf(__('Custom %dpx Width', 'wpturbo'), $value) : sprintf(__('Custom %dpx Height', 'wpturbo'), $value);
}
return $custom_sizes;
}
// Disable scaling
add_filter('big_image_size_threshold', '__return_false', 999);
// Clean up attachment files on deletion
add_action('wp_delete_attachment', 'wpturbo_delete_attachment_files', 10, 1);
function wpturbo_delete_attachment_files($attachment_id) {
if (in_array($attachment_id, wpturbo_get_excluded_images())) return;
$file = get_attached_file($attachment_id);
if ($file && file_exists($file)) @unlink($file);
$metadata = wp_get_attachment_metadata($attachment_id);
if ($metadata && isset($metadata['sizes'])) {
$upload_dir = wp_upload_dir()['basedir'];
foreach ($metadata['sizes'] as $size) {
$size_file = $upload_dir . '/' . dirname($metadata['file']) . '/' . $size['file'];
if (file_exists($size_file)) @unlink($size_file);
}
}
}
// Ensure MIME types on plugin activation or format switch
register_activation_hook(__FILE__, 'wpturbo_ensure_mime_types');
add_action('update_option_webp_use_avif', 'wpturbo_ensure_mime_types');
// Stop Processed Images from being Processed again unless Settings Change
add_action('admin_init', function () {
if (!current_user_can('manage_options') || !isset($_GET['patch_pixrefiner_stamp'])) return;
$attachments = get_posts([
'post_type' => 'attachment',
'post_mime_type' => ['image/webp', 'image/avif'],
'posts_per_page' => -1,
'fields' => 'ids',
]);
$expected_stamp = [
'format' => wpturbo_get_use_avif() ? 'avif' : 'webp',
'quality' => wpturbo_get_quality(),
'resize_mode' => wpturbo_get_resize_mode(),
'max_values' => (wpturbo_get_resize_mode() === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights(),
];
foreach ($attachments as $id) {
$meta = wp_get_attachment_metadata($id);
if (empty($meta['pixrefiner_stamp'])) {
$meta['pixrefiner_stamp'] = $expected_stamp;
wp_update_attachment_metadata($id, $meta);
}
}
echo " PixRefiner stamp patch complete.
";
});