// 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); // Moved up to prevent array out-of-bounds
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ‚ ‚ . $units[$pow];
}
// Limit default WordPress sizes to thumbnail only
function wpturbo_limit_image_sizes($sizes) {
return [‚thumbnail‘ => $sizes[‚thumbnail‘]];
}
add_filter(‚intermediate_image_sizes_advanced‘, ‚wpturbo_limit_image_sizes‘);
// Set thumbnail size to 150×150
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); // Up to 3 additional sizes
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; }); // Validate range
return array_slice($widths, 0, 4); // Up to 4 sizes
}
// 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; }); // Validate range
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 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($log, -100));
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($log, -100));
return true;
}
return false;
}
// Core WebP conversion function
function wpturbo_convert_to_webp($file_path, $dimension, &$log = null, $attachment_id = null, $suffix = “) {
$path_info = pathinfo($file_path);
$new_file_path = $path_info[‚dirname‘] . ‚/‘ . $path_info[‚filename‘] . $suffix . ‚.webp‘;
$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;
}
$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, ‚image/webp‘, [‚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: Convert to WebP, generate sizes, update metadata
add_filter(‚wp_handle_upload‘, ‚wpturbo_handle_upload_convert_to_webp‘, 10, 1);
function wpturbo_handle_upload_convert_to_webp($upload) {
$file_extension = strtolower(pathinfo($upload[‚file‘], PATHINFO_EXTENSION));
$allowed_extensions = [‚jpg‘, ‚jpeg‘, ‚png‘, ‚webp‘];
if (!in_array($file_extension, $allowed_extensions)) {
return $upload;
}
$file_path = $upload[‚file‘];
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === ‚width‘) ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$log = get_option(‚webp_conversion_log‘, []);
$attachment_id = attachment_url_to_postid($upload[‚url‘]);
$new_files = [];
// Convert to all specified sizes
foreach ($max_values as $index => $dimension) {
$suffix = ($index === 0) ? “ : „-{$dimension}“;
$new_file_path = wpturbo_convert_to_webp($file_path, $dimension, $log, $attachment_id, $suffix);
if ($new_file_path) {
if ($index === 0) {
$upload[‚file‘] = $new_file_path;
$upload[‚url‘] = str_replace(basename($upload[‚url‘]), basename($new_file_path), $upload[‚url‘]);
$upload[‚type‘] = ‚image/webp‘;
}
$new_files[] = $new_file_path;
}
}
// Generate 150×150 thumbnail
if ($attachment_id) {
$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) . ‚-150×150.webp‘;
$saved = $editor->save($thumbnail_path, ‚image/webp‘, [‚quality‘ => wpturbo_get_quality()]);
if (!is_wp_error($saved)) {
$log[] = sprintf(__(‚Generated thumbnail: %s‘, ‚wpturbo‘), basename($thumbnail_path));
$new_files[] = $thumbnail_path;
}
}
// Update metadata with all sizes
$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);
foreach ($max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = „$dirname/$base_name-$dimension.webp“;
if (file_exists($size_file)) {
$metadata[’sizes‘][„custom-$dimension“] = [
‚file‘ => „$base_name-$dimension.webp“,
‚width‘ => ($mode === ‚width‘) ? $dimension : 0,
‚height‘ => ($mode === ‚height‘) ? $dimension : 0,
‚mime-type‘ => ‚image/webp‘
];
}
}
$thumbnail_file = „$dirname/$base_name-150×150.webp“;
if (file_exists($thumbnail_file)) {
$metadata[’sizes‘][‚thumbnail‘] = [
‚file‘ => „$base_name-150×150.webp“,
‚width‘ => 150,
‚height‘ => 150,
‚mime-type‘ => ‚image/webp‘
];
}
$metadata[‚webp_quality‘] = wpturbo_get_quality();
update_attached_file($attachment_id, $upload[‚file‘]);
wp_update_post([‚ID‘ => $attachment_id, ‚post_mime_type‘ => ‚image/webp‘]);
wp_update_attachment_metadata($attachment_id, $metadata);
} else {
$log[] = sprintf(__(‚Error: Metadata regeneration failed for %s – %s‘, ‚wpturbo‘), basename($file_path), $metadata->get_error_message());
}
}
// Clean up original if not preserving
if ($file_extension !== ‚webp‘ && file_exists($file_path) && !wpturbo_get_preserve_originals()) {
$attempts = 0;
while ($attempts < 5 && file_exists($file_path)) {
if (!is_writable($file_path)) {
@chmod($file_path, 0644); // Use @ to suppress warnings
if (!is_writable($file_path)) {
$log[] = sprintf(__(‚Error: Cannot make %s writable – skipping deletion‘, ‚wpturbo‘), basename($file_path));
break;
}
}
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));
// Removed error_log to avoid server overload
}
}
update_option(‚webp_conversion_log‘, array_slice($log, -100));
return $upload;
}
// Fix metadata for WebP images
add_filter(‚wp_generate_attachment_metadata‘, ‚wpturbo_fix_webp_metadata‘, 10, 2);
function wpturbo_fix_webp_metadata($metadata, $attachment_id) {
$file = get_attached_file($attachment_id);
if (pathinfo($file, PATHINFO_EXTENSION) !== ‚webp‘) {
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‘] = ‚image/webp‘;
// Ensure all sizes are in metadata
foreach ($max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = „$dirname/$base_name-$dimension.webp“;
if (file_exists($size_file)) {
$metadata[’sizes‘][„custom-$dimension“] = [
‚file‘ => „$base_name-$dimension.webp“,
‚width‘ => ($mode === ‚width‘) ? $dimension : 0,
‚height‘ => ($mode === ‚height‘) ? $dimension : 0,
‚mime-type‘ => ‚image/webp‘
];
}
}
$thumbnail_file = „$dirname/$base_name-150×150.webp“;
if (file_exists($thumbnail_file)) {
$metadata[’sizes‘][‚thumbnail‘] = [
‚file‘ => „$base_name-150×150.webp“,
‚width‘ => 150,
‚height‘ => 150,
‚mime-type‘ => ‚image/webp‘
];
}
return $metadata;
}
// Batch convert existing images
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();
wp_raise_memory_limit(‚image‘);
set_time_limit(max(30, 10 * $batch_size)); // Dynamic timeout
$args = [
‚post_type‘ => ‚attachment‘,
‚post_mime_type‘ => [‚image/jpeg‘, ‚image/png‘, ‚image/webp‘],
‚posts_per_page‘ => $batch_size,
‚offset‘ => $offset,
‚fields‘ => ‚ids‘,
‚post__not_in‘ => wpturbo_get_excluded_images(),
];
$attachments = get_posts($args);
$log = get_option(‚webp_conversion_log‘, []);
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === ‚width‘) ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$current_quality = wpturbo_get_quality();
if (empty($attachments)) {
update_option(‚webp_conversion_complete‘, true);
$log[] = „<span style=’font-weight: bold; color: #281E5D;‘>“ . __(‚Conversion Complete‘, ‚wpturbo‘) . „</span>: “ . __(‚No more images to process‘, ‚wpturbo‘);
update_option(‚webp_conversion_log‘, array_slice($log, -100));
wp_send_json_success([‚complete‘ => true]);
}
foreach ($attachments as $attachment_id) {
$file_path = get_attached_file($attachment_id);
if (!file_exists($file_path)) {
$log[] = sprintf(__(‚Skipped: File not found for Attachment ID %d‘, ‚wpturbo‘), $attachment_id);
continue;
}
$metadata = wp_get_attachment_metadata($attachment_id);
$existing_quality = isset($metadata[‚webp_quality‘]) ? (int) $metadata[‚webp_quality‘] : null;
$is_webp = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)) === ‚webp‘;
$reprocess = !$is_webp || $existing_quality !== $current_quality;
if ($is_webp && !$reprocess) {
$editor = wp_get_image_editor($file_path);
if (!is_wp_error($editor)) {
$current_size = $editor->get_size();
$current_dimension = ($mode === ‚width‘) ? $current_size[‚width‘] : $current_size[‚height‘];
$reprocess = !in_array($current_dimension, $max_values);
}
}
if (!$reprocess) {
continue;
}
$new_files = [];
foreach ($max_values as $index => $dimension) {
$suffix = ($index === 0) ? “ : „-{$dimension}“;
$new_file_path = wpturbo_convert_to_webp($file_path, $dimension, $log, $attachment_id, $suffix);
if ($new_file_path) {
if ($index === 0) {
update_attached_file($attachment_id, $new_file_path);
wp_update_post([‚ID‘ => $attachment_id, ‚post_mime_type‘ => ‚image/webp‘]);
}
$new_files[] = $new_file_path;
}
}
$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) . ‚-150×150.webp‘;
$saved = $editor->save($thumbnail_path, ‚image/webp‘, [‚quality‘ => $current_quality]);
if (!is_wp_error($saved)) {
$log[] = sprintf(__(‚Generated thumbnail: %s‘, ‚wpturbo‘), basename($thumbnail_path));
$new_files[] = $thumbnail_path;
}
}
if ($attachment_id && !empty($new_files)) {
$metadata = wp_generate_attachment_metadata($attachment_id, $new_files[0]);
if (!is_wp_error($metadata)) {
$base_name = pathinfo($file_path, PATHINFO_FILENAME);
$dirname = dirname($file_path);
foreach ($max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = „$dirname/$base_name-$dimension.webp“;
if (file_exists($size_file)) {
$metadata[’sizes‘][„custom-$dimension“] = [
‚file‘ => „$base_name-$dimension.webp“,
‚width‘ => ($mode === ‚width‘) ? $dimension : 0,
‚height‘ => ($mode === ‚height‘) ? $dimension : 0,
‚mime-type‘ => ‚image/webp‘
];
}
}
$thumbnail_file = „$dirname/$base_name-150×150.webp“;
if (file_exists($thumbnail_file)) {
$metadata[’sizes‘][‚thumbnail‘] = [
‚file‘ => „$base_name-150×150.webp“,
‚width‘ => 150,
‚height‘ => 150,
‚mime-type‘ => ‚image/webp‘
];
}
$metadata[‚webp_quality‘] = $current_quality;
wp_update_attachment_metadata($attachment_id, $metadata);
} else {
$log[] = sprintf(__(‚Error: Metadata regeneration failed for %s‘, ‚wpturbo‘), basename($file_path));
}
}
if (!$is_webp && file_exists($file_path) && !wpturbo_get_preserve_originals()) {
$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));
break;
}
}
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));
// Removed error_log to avoid server overload
}
}
}
update_option(‚webp_conversion_log‘, array_slice($log, -100));
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;
$converted = count(get_posts([
‚post_type‘ => ‚attachment‘,
‚posts_per_page‘ => -1,
‚fields‘ => ‚ids‘,
‚post_mime_type‘ => ‚image/webp‘
]));
$skipped = count(get_posts([
‚post_type‘ => ‚attachment‘,
‚posts_per_page‘ => -1,
‚fields‘ => ‚ids‘,
‚post_mime_type‘ => [‚image/jpeg‘, ‚image/png‘]
]));
$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()), // Added
‚max_heights‘ => implode(‚, ‚, wpturbo_get_max_heights()), // Added
‚quality‘ => wpturbo_get_quality(),
‚preserve_originals‘ => wpturbo_get_preserve_originals()
]);
}
// 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);
$log = get_option(‚webp_conversion_log‘, []);
$log[] = __(‚Settings reset to defaults‘, ‚wpturbo‘);
update_option(‚webp_conversion_log‘, array_slice($log, -100));
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($log, -100));
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($log, -100));
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($log, -100));
}
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($log, -100));
}
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) { // Reasonable upper limit
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($log, -100));
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($log, -100));
return true;
}
return false;
}
// Cleanup leftover originals, preserving all WebP sizes
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();
$attachments = get_posts([
‚post_type‘ => ‚attachment‘,
‚posts_per_page‘ => -1,
‚fields‘ => ‚ids‘,
‚post_mime_type‘ => [‚image/jpeg‘, ‚image/png‘, ‚image/webp‘],
]);
$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‘];
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}“;
$webp_file = „$dirname/$base_name$suffix.webp“;
if (file_exists($webp_file)) $active_files[$webp_file] = true;
}
$thumbnail_file = „$dirname/$base_name-150×150.webp“;
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;
}
// Protect all WebP sizes
if ($file && file_exists($file)) {
$active_files[$file] = true;
foreach ($max_values as $index => $dimension) {
$suffix = ($index === 0) ? “ : „-{$dimension}“;
$webp_file = „$dirname/$base_name$suffix.webp“;
if (file_exists($webp_file)) $active_files[$webp_file] = true;
}
$thumbnail_file = „$dirname/$base_name-150×150.webp“;
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‘, ‚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;
$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++;
// Removed error_log to avoid server overload
}
}
}
$log[] = „<span style=’font-weight: bold; color: #281E5D;‘>“ . __(‚Cleanup Complete‘, ‚wpturbo‘) . „</span>: “ . sprintf(__(‚Deleted %d files, %d failed‘, ‚wpturbo‘), $deleted, $failed);
update_option(‚webp_conversion_log‘, array_slice($log, -100));
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)) === ‚webp‘) {
$metadata = wp_get_attachment_metadata($attachment_id);
$thumbnail_file = $uploads_dir . ‚/‘ . dirname($metadata[‚file‘]) . ‚/‘ . pathinfo($file_path, PATHINFO_FILENAME) . ‚-150×150.webp‘;
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[] = „<span style=’font-weight: bold; color: #281E5D;‘>“ . __(‚Thumbnail Regeneration Complete‘, ‚wpturbo‘) . „</span>“;
update_option(‚webp_conversion_log‘, array_slice($log, -100));
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 WebP
add_action(‚wp_ajax_convert_post_images_to_webp‘, ‚wpturbo_convert_post_images_to_webp‘);
function wpturbo_convert_post_images_to_webp() {
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($log, -100));
}
add_log_entry(__(‚Starting post image conversion to WebP…‘, ‚wpturbo‘));
$post_types = get_post_types([‚public‘ => true], ’names‘);
$args = [
‚post_type‘ => $post_types,
‚posts_per_page‘ => -1,
‚fields‘ => ‚ids‘
];
$posts = get_posts($args);
if (!$posts) {
add_log_entry(__(‚No posts found‘, ‚wpturbo‘));
wp_send_json_success([‚message‘ => __(‚No posts found‘, ‚wpturbo‘)]);
}
$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(‚/<img[^>]+src=[„\‘]([^“\‘]+\.(?:jpg|jpeg|png))[„\‘][^>]*>/i‘, function ($matches) use (&$checked_images) {
$original_url = $matches[1];
$checked_images++;
$webp_url = preg_replace(‚/\.(jpg|jpeg|png)$/i‘, ‚.webp‘, $original_url);
$webp_path = str_replace(site_url(), ABSPATH, $webp_url);
if (file_exists($webp_path)) {
add_log_entry(sprintf(__(‚Replacing: %s → %s‘, ‚wpturbo‘), $original_url, $webp_url));
return str_replace($original_url, $webp_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, ‚.webp‘)) {
$webp_path = preg_replace(‚/\.(jpg|jpeg|png)$/i‘, ‚.webp‘, $thumbnail_path);
if (file_exists($webp_path)) {
update_attached_file($thumbnail_id, $webp_path);
wp_update_post([‚ID‘ => $thumbnail_id, ‚post_mime_type‘ => ‚image/webp‘]);
$metadata = wp_generate_attachment_metadata($thumbnail_id, $webp_path);
wp_update_attachment_metadata($thumbnail_id, $metadata);
add_log_entry(sprintf(__(‚Updated thumbnail: %s → %s‘, ‚wpturbo‘), basename($thumbnail_path), basename($webp_path)));
}
}
}
}
add_log_entry(sprintf(__(‚Checked %d images, updated %d posts‘, ‚wpturbo‘), $checked_images, $updated_count));
wp_send_json_success([‚message‘ => sprintf(__(‚Checked %d images, updated %d posts‘, ‚wpturbo‘), $checked_images, $updated_count)]);
}
// Custom srcset to include all WebP sizes
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;
}
$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.webp“;
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.webp“,
‚descriptor‘ => ‚w‘,
‚value‘ => $width
];
}
}
$thumbnail_file = „$base_path/$base_name-150×150.webp“;
if (file_exists($thumbnail_file)) {
$sources[150] = [
‚url‘ => „$base_url/$base_name-150×150.webp“,
‚descriptor‘ => ‚w‘,
‚value‘ => 150
];
}
return $sources;
}
// Admin interface
add_action(‚admin_menu‘, function() {
add_media_page(
__(‚WebP Converter‘, ‚wpturbo‘),
__(‚WebP Converter‘, ‚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[‚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‘);
?>
<div class=“wrap“ style=“padding: 0; font-size: 14px;“>
<div style=“display: flex; gap: 1%; align-items: flex-start;“>
<!– Main Controls –>
<div style=“width: 48%; background: #FFFFFF; padding: 20px; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);“>
<h1 style=“font-size: 20px; font-weight: bold; color: #333; margin: -5px 0 15px 0;“><?php _e(‚WebP Converter – v2.1‘, ‚wpturbo‘); ?></h1>
<?php if (!$has_image_library): ?>
<div class=“notice notice-error“ style=“margin-bottom: 20px;“>
<p><?php _e(‚Warning: No image processing libraries (Imagick or GD) available. Conversion requires one of these.‘, ‚wpturbo‘); ?></p>
</div>
<?php endif; ?>
<?php if (current_user_can(‚manage_options‘)): ?>
<div style=“margin-bottom: 20px;“>
<label for=“resize-mode“ style=“font-weight: bold;“><?php _e(‚Resize Mode:‘, ‚wpturbo‘); ?></label><br>
<select id=“resize-mode“ style=“width: 150px; margin-right: 10px; padding: 5px;“>
<option value=“width“ <?php echo wpturbo_get_resize_mode() === ‚width‘ ? ’selected‘ : “; ?>><?php _e(‚Width‘, ‚wpturbo‘); ?></option>
<option value=“height“ <?php echo wpturbo_get_resize_mode() === ‚height‘ ? ’selected‘ : “; ?>><?php _e(‚Height‘, ‚wpturbo‘); ?></option>
</select>
</div>
<div style=“margin-bottom: 20px;“>
<label for=“max-width-input“ style=“font-weight: bold;“><?php _e(‚Max Widths (up to 4, e.g., 1920,1200,600,300):‘, ‚wpturbo‘); ?></label><br>
<input type=“text“ id=“max-width-input“ value=“<?php echo esc_attr(implode(‚, ‚, wpturbo_get_max_widths())); ?>“ style=“width: 200px; margin-right: 10px; padding: 5px;“ placeholder=“1920,1200,600,300″>
<button id=“set-max-width“ class=“button“><?php _e(‚Set Widths‘, ‚wpturbo‘); ?></button>
</div>
<div style=“margin-bottom: 20px;“>
<label for=“max-height-input“ style=“font-weight: bold;“><?php _e(‚Max Heights (up to 4, e.g., 1080,720,480,360):‘, ‚wpturbo‘); ?></label><br>
<input type=“text“ id=“max-height-input“ value=“<?php echo esc_attr(implode(‚, ‚, wpturbo_get_max_heights())); ?>“ style=“width: 200px; margin-right: 10px; padding: 5px;“ placeholder=“1080,720,480,360″>
<button id=“set-max-height“ class=“button“><?php _e(‚Set Heights‘, ‚wpturbo‘); ?></button>
</div>
<div style=“margin-bottom: 20px;“>
<label for=“quality-slider“ style=“font-weight: bold;“><?php _e(‚Quality (0-100):‘, ‚wpturbo‘); ?></label><br>
<input type=“range“ id=“quality-slider“ value=“<?php echo esc_attr(wpturbo_get_quality()); ?>“ min=“0″ max=“100″ style=“width: 200px; margin-right: 10px;“>
<span id=“quality-value“><?php echo wpturbo_get_quality(); ?></span>
</div>
<div style=“margin-bottom: 20px;“>
<label><input type=“checkbox“ id=“preserve-originals“ <?php echo wpturbo_get_preserve_originals() ? ‚checked‘ : “; ?>> <?php _e(‚Preserve Original Files‘, ‚wpturbo‘); ?></label>
</div>
<div style=“margin-bottom: 20px;“>
<button id=“start-conversion“ class=“button“><?php _e(‚Convert/Scale‘, ‚wpturbo‘); ?></button>
<button id=“cleanup-originals“ class=“button“><?php _e(‚Cleanup Images‘, ‚wpturbo‘); ?></button>
<button id=“convert-post-images“ class=“button“><?php _e(‚Fix URLs‘, ‚wpturbo‘); ?></button>
<button id=“run-all“ class=“button button-primary“><?php _e(‚Run All‘, ‚wpturbo‘); ?></button>
<button id=“stop-conversion“ class=“button“ style=“display: none;“><?php _e(‚Stop‘, ‚wpturbo‘); ?></button>
<button id=“reset-defaults“ class=“button“ style=“margin-left: 10px;“><?php _e(‚Reset Defaults‘, ‚wpturbo‘); ?></button>
</div>
<div style=“margin-bottom: 20px;“>
<button id=“clear-log“ class=“button“><?php _e(‚Clear Log‘, ‚wpturbo‘); ?></button>
</div>
<h3 style=“font-size: 16px; margin: 0 0 10px 0;“><?php _e(‚Log (Last 100 Entries)‘, ‚wpturbo‘); ?></h3>
<pre id=“log“ style=“background: #f9f9f9; padding: 15px; max-height: 400px; overflow-y: auto; border: 1px solid #ddd; border-radius: 5px;“></pre>
<?php else: ?>
<p><?php _e(‚You need manage_options permission to use this tool.‘, ‚wpturbo‘); ?></p>
<?php endif; ?>
</div>
<!– Exclude Images –>
<div style=“width: 22%; background: #FFFFFF; padding: 20px; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);“>
<h2 style=“font-size: 16px; margin: 0 0 15px 0;“><?php _e(‚Exclude Images‘, ‚wpturbo‘); ?></h2>
<button id=“open-media-library“ class=“button“ style=“margin-bottom: 20px;“><?php _e(‚Add from Media Library‘, ‚wpturbo‘); ?></button>
<div id=“excluded-images“>
<h3 style=“font-size: 14px; margin: 0 0 10px 0;“><?php _e(‚Excluded Images‘, ‚wpturbo‘); ?></h3>
<ul id=“excluded-images-list“ style=“list-style: none; padding: 0; max-height: 600px; overflow-y: auto;“></ul>
</div>
</div>
<!– Instructions –>
<div style=“width: 28%; background: #FFFFFF; padding: 20px; border-radius: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);“>
<h2 style=“font-size: 16px; margin: 0 0 15px 0;“><?php _e(‚How It Works‘, ‚wpturbo‘); ?></h2>
<p style=“line-height: 1.5;“>
<?php _e(‚Convert images to WebP with responsive sizes (e.g: 1920, 1200, 600, 300) and a 150×150 thumbnail to save on File storage. The original file will be deleted unless „Preserve“ is selected. The log will inform you when conversions are complete. ‚, ‚wpturbo‘); ?><br><br><br>
<b>Apply for New Uploads:</b> <?php _e(“, ‚wpturbo‘); ?><br>
<b>1. Resize Mode:</b> <?php _e(‚Select scaling is set on Width or Height.‘, ‚wpturbo‘); ?><br>
<b>2. Set Sizes:</b> <?php _e(‚Add preferred sizes (up to 4). No need to add 150.‘, ‚wpturbo‘); ?><br>
<b>3. Set Quality:</b> <?php _e(‚Slide for conversion levels. (Default is 80).‘, ‚wpturbo‘); ?><br>
<b>4. Keep Original:</b> <?php _e(‚Original image database files are not deleted.‘, ‚wpturbo‘); ?><br>
<b>5. Upload:</b> <?php _e(‚Upload within Media Library or via a widget/element.‘, ‚wpturbo‘); ?><br><br>
<b>Apply for Existing Images:</b> <?php _e(“, ‚wpturbo‘); ?><br>
<b>1. Repeat:</b> <?php _e(‚Follow Steps 1 to 4 from New Uploads‘, ‚wpturbo‘); ?><br>
<b>2. Run All:</b> <?php _e(‚Click to Execute the Full Sequence.‘, ‚wpturbo‘); ?><br><br>
<b>Apply Manually for Existing Images:</b> <?php _e(“, ‚wpturbo‘); ?><br>
<b>1. Repeat:</b> <?php _e(‚Follow Steps 1 to 4 from New Uploads‘, ‚wpturbo‘); ?><br>
<b>2. Convert/Scale:</b> <?php _e(‚Process existing images to WebP.‘, ‚wpturbo‘); ?><br>
<b>3. Cleanup Images:</b> <?php _e(‚Remove non-WebP files (unless preserved).‘, ‚wpturbo‘); ?><br>
<b>4. Fix URLs:</b> <?php _e(‚Update Media URLs to use WebP.‘, ‚wpturbo‘); ?><br><br>
<b>NOTE:</b> <?php _e(“, ‚wpturbo‘); ?><br>
<b>a) Apply No Conversion:</b> <?php _e(‚Deactivate Snippet before uploading images.‘, ‚wpturbo‘); ?><br>
<b>b) Backups:</b> <?php _e(‚Use a robust backup system before running any code/tool.‘, ‚wpturbo‘); ?><br>
<b>c) Processing Speed:</b> <?php _e(‚This depends on server, number of images.‘); ?><br>
<b>d) Log Delays:</b> <?php _e(‚Updates appear in batches of 50.‘); ?><br>
<b>e) Option to Stop:</b> <?php _e(‚Click Stop to stop the process.‘); ?>
</p>
</div>
</div>
</div>
<style>
:root {
–primary-color: #FF0050;
–hover-color: #444444;
}
#quality-slider {
-webkit-appearance: none;
height: 6px;
border-radius: 3px;
background: #ddd;
}
#quality-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
background: var(–primary-color);
border-radius: 50%;
cursor: pointer;
}
.button:not(.button-primary) {
background: #f7f7f7;
border: 1px solid #ccc;
transition: all 0.2s;
}
.button:not(.button-primary):hover {
background: #e1e1e1;
border-color: var(–primary-color);
}
.button.button-primary {
background: var(–primary-color);
border-color: var(–primary-color);
color: #fff;
}
.button.button-primary:hover {
background: var(–hover-color);
border-color: var(–hover-color);
}
#excluded-images-list li {
display: flex;
align-items: center;
margin-bottom: 10px;
}
#excluded-images-list img {
max-width: 50px;
margin-right: 10px;
}
</style>
<script>
document.addEventListener(‚DOMContentLoaded‘, function() {
let isConverting = false;
function updateStatus() {
fetch(‚<?php echo admin_url(‚admin-ajax.php?action=webp_status&nonce=‘ . wp_create_nonce(‚webp_converter_nonce‘)); ?>‘)
.then(response => response.json())
.then(data => {
document.getElementById(‚log‘).innerHTML = data.log.reverse().join(‚<br>‘);
document.getElementById(‚quality-slider‘).value = data.quality;
document.getElementById(‚quality-value‘).textContent = data.quality;
document.getElementById(‚resize-mode‘).value = data.resize_mode;
document.getElementById(‚max-width-input‘).value = data.max_widths; // Updated
document.getElementById(‚max-height-input‘).value = data.max_heights; // Updated
document.getElementById(‚preserve-originals‘).checked = data.preserve_originals;
updateExcludedImages(data.excluded_images);
updateSliderBackground(data.quality);
});
}
function updateSliderBackground(value) {
const slider = document.getElementById(‚quality-slider‘);
const percentage = (value – slider.min) / (slider.max – slider.min) * 100;
slider.style.background = `linear-gradient(to right, var(–primary-color) ${percentage}%, #ddd ${percentage}%)`;
}
function updateExcludedImages(excludedImages) {
const list = document.getElementById(‚excluded-images-list‘);
list.innerHTML = “;
excludedImages.forEach(image => {
const li = document.createElement(‚li‘);
li.innerHTML = `<img decoding=“async“ src=“${image.thumbnail}“ alt=“${image.title}“><span>${image.title} (ID: ${image.id})</span><button class=“remove-excluded button“ data-id=“${image.id}“><?php echo esc_html__(‚Remove‘, ‚wpturbo‘); ?></button>`;
list.appendChild(li);
});
document.querySelectorAll(‚.remove-excluded‘).forEach(button => {
button.addEventListener(‚click‘, () => {
fetch(‚<?php echo admin_url(‚admin-ajax.php?action=webp_remove_excluded_image&nonce=‘ . wp_create_nonce(‚webp_converter_nonce‘)); ?>‘, {
method: ‚POST‘,
headers: { ‚Content-Type‘: ‚application/x-www-form-urlencoded‘ },
body: ‚attachment_id=‘ + encodeURIComponent(button.getAttribute(‚data-id‘))
}).then(response => response.json()).then(data => {
if (data.success) updateStatus();
else alert(‚Error: ‚ + data.data);
});
});
});
}
function convertNextImage(offset) {
if (!isConverting) return;
fetch(‚<?php echo admin_url(‚admin-ajax.php?action=webp_convert_single&nonce=‘ . wp_create_nonce(‚webp_converter_nonce‘)); ?>‘, {
method: ‚POST‘,
headers: { ‚Content-Type‘: ‚application/x-www-form-urlencoded‘ },
body: ‚offset=‘ + encodeURIComponent(offset)
}).then(response => response.json()).then(data => {
if (data.success) {
updateStatus();
if (!data.data.complete && isConverting) convertNextImage(data.data.offset);
else document.getElementById(’stop-conversion‘).style.display = ’none‘;
}
});
}
<?php if (current_user_can(‚manage_options‘)): ?>
const mediaFrame = wp.media({
title: ‚<?php echo esc_js(__(‚Select Images to Exclude‘, ‚wpturbo‘)); ?>‘,
button: { text: ‚<?php echo esc_js(__(‚Add to Excluded List‘, ‚wpturbo‘)); ?>‘ },
multiple: true,
library: { type: ‚image‘ }
});
document.getElementById(‚open-media-library‘).addEventListener(‚click‘, () => mediaFrame.open());
mediaFrame.on(’select‘, () => {
const selection = mediaFrame.state().get(’selection‘);
selection.each(attachment => {
fetch(‚<?php echo admin_url(‚admin-ajax.php?action=webp_add_excluded_image&nonce=‘ . wp_create_nonce(‚webp_converter_nonce‘)); ?>‘, {
method: ‚POST‘,
headers: { ‚Content-Type‘: ‚application/x-www-form-urlencoded‘ },
body: ‚attachment_id=‘ + encodeURIComponent(attachment.id)
}).then(response => response.json()).then(data => {
if (data.success) updateStatus();
});
});
});
document.getElementById(’set-max-width‘).addEventListener(‚click‘, () => {
const maxWidths = document.getElementById(‚max-width-input‘).value;
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&set_max_width=1&max_width=‘); ?>‘ + encodeURIComponent(maxWidths))
.then(() => updateStatus());
});
document.getElementById(’set-max-height‘).addEventListener(‚click‘, () => {
const maxHeights = document.getElementById(‚max-height-input‘).value;
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&set_max_height=1&max_height=‘); ?>‘ + encodeURIComponent(maxHeights))
.then(() => updateStatus());
});
document.getElementById(‚resize-mode‘).addEventListener(‚change‘, () => {
const mode = document.getElementById(‚resize-mode‘).value;
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&set_resize_mode=1&resize_mode=‘); ?>‘ + encodeURIComponent(mode))
.then(() => updateStatus());
});
document.getElementById(‚quality-slider‘).addEventListener(‚input‘, () => {
const quality = document.getElementById(‚quality-slider‘).value;
document.getElementById(‚quality-value‘).textContent = quality;
updateSliderBackground(quality);
});
document.getElementById(‚quality-slider‘).addEventListener(‚change‘, () => {
const quality = document.getElementById(‚quality-slider‘).value;
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&set_quality=1&quality=‘); ?>‘ + encodeURIComponent(quality))
.then(() => updateStatus());
});
document.getElementById(‚preserve-originals‘).addEventListener(‚change‘, () => {
const preserve = document.getElementById(‚preserve-originals‘).checked;
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&set_preserve_originals=1&preserve_originals=‘); ?>‘ + encodeURIComponent(preserve ? 1 : 0))
.then(() => updateStatus());
});
document.getElementById(’start-conversion‘).addEventListener(‚click‘, () => {
isConverting = true;
document.getElementById(’stop-conversion‘).style.display = ‚inline-block‘;
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&convert_existing_images_to_webp=1′); ?>‘)
.then(() => { updateStatus(); convertNextImage(0); });
});
document.getElementById(‚cleanup-originals‘).addEventListener(‚click‘, () => {
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&cleanup_leftover_originals=1′); ?>‘)
.then(() => updateStatus());
});
document.getElementById(‚convert-post-images‘).addEventListener(‚click‘, () => {
if (confirm(‚<?php echo esc_js(__(‚Update all post images to WebP?‘, ‚wpturbo‘)); ?>‘)) {
fetch(‚<?php echo admin_url(‚admin-ajax.php?action=convert_post_images_to_webp&nonce=‘ . wp_create_nonce(‚webp_converter_nonce‘)); ?>‘, {
method: ‚POST‘,
headers: { ‚Content-Type‘: ‚application/x-www-form-urlencoded‘ }
}).then(response => response.json()).then(data => {
alert(data.success ? data.data.message : ‚Error: ‚ + data.data);
updateStatus();
});
}
});
document.getElementById(‚run-all‘).addEventListener(‚click‘, () => {
if (confirm(‚<?php echo esc_js(__(‚Run all steps?‘, ‚wpturbo‘)); ?>‘)) {
isConverting = true;
document.getElementById(’stop-conversion‘).style.display = ‚inline-block‘;
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&convert_existing_images_to_webp=1′); ?>‘)
.then(() => {
convertNextImage(0);
return new Promise(resolve => {
const checkComplete = setInterval(() => {
fetch(‚<?php echo admin_url(‚admin-ajax.php?action=webp_status&nonce=‘ . wp_create_nonce(‚webp_converter_nonce‘)); ?>‘)
.then(response => response.json())
.then(data => {
if (data.complete) {
clearInterval(checkComplete);
resolve();
}
});
}, 1000);
});
})
.then(() => fetch(‚<?php echo admin_url(‚admin-ajax.php?action=convert_post_images_to_webp&nonce=‘ . wp_create_nonce(‚webp_converter_nonce‘)); ?>‘, { method: ‚POST‘, headers: { ‚Content-Type‘: ‚application/x-www-form-urlencoded‘ } }))
.then(() => fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&cleanup_leftover_originals=1′); ?>‘))
.then(() => {
isConverting = false;
document.getElementById(’stop-conversion‘).style.display = ’none‘;
updateStatus();
alert(‚<?php echo esc_js(__(‚All steps completed!‘, ‚wpturbo‘)); ?>‘);
});
}
});
document.getElementById(’stop-conversion‘).addEventListener(‚click‘, () => {
isConverting = false;
document.getElementById(’stop-conversion‘).style.display = ’none‘;
});
document.getElementById(‚clear-log‘).addEventListener(‚click‘, () => {
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&clear_log=1′); ?>‘)
.then(() => updateStatus());
});
document.getElementById(‚reset-defaults‘).addEventListener(‚click‘, () => {
if (confirm(‚<?php echo esc_js(__(‚Reset all settings to defaults?‘, ‚wpturbo‘)); ?>‘)) {
fetch(‚<?php echo admin_url(‚admin.php?page=webp-converter&reset_defaults=1′); ?>‘)
.then(() => updateStatus());
}
});
<?php endif; ?>
updateStatus();
});
</script>
<?php
}
// Setup AJAX hooks
add_action(‚admin_init‘, function() {
add_action(‚wp_ajax_webp_status‘, ‚wpturbo_webp_conversion_status‘);
add_action(‚wp_ajax_webp_convert_single‘, ‚wpturbo_convert_single_image‘);
if (isset($_GET[‚convert_existing_images_to_webp‘]) && current_user_can(‚manage_options‘)) {
delete_option(‚webp_conversion_complete‘);
}
});
// Admin notices
add_action(‚admin_notices‘, function() {
if (isset($_GET[‚convert_existing_images_to_webp‘])) {
echo ‚<div class=“notice notice-success“><p>‘ . __(‚WebP conversion started. Monitor progress in Media > WebP Converter.‘, ‚wpturbo‘) . ‚</p></div>‘;
}
if (isset($_GET[’set_max_width‘]) && wpturbo_set_max_widths()) {
echo ‚<div class=“notice notice-success“><p>‘ . __(‚Max widths updated.‘, ‚wpturbo‘) . ‚</p></div>‘;
}
if (isset($_GET[’set_max_height‘]) && wpturbo_set_max_heights()) {
echo ‚<div class=“notice notice-success“><p>‘ . __(‚Max heights updated.‘, ‚wpturbo‘) . ‚</p></div>‘;
}
if (isset($_GET[‚reset_defaults‘]) && wpturbo_reset_defaults()) {
echo ‚<div class=“notice notice-success“><p>‘ . __(‚Settings reset to defaults.‘, ‚wpturbo‘) . ‚</p></div>‘;
}
});
// 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 (150×150)‘, ‚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);
}
}
}