zs-webp-convertor/0.2/zs-convert-to-webp.php

299 lines
11 KiB
PHP

<?php
/**
* Plugin Name: ZedSuite WebP Converter
* Description: Automatically converts uploaded JPEG and PNG images to WebP with 75% compression (or you can set your own compression), adds them to the media library, and deletes the original file.
* Version: 0.2
* Author: Ze'ev Schurmann
* License: GPL3 or later
*/
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
if (is_admin()) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
add_filter('wp_handle_upload', 'zs_convert_to_webp', 10, 2);
function zs_convert_to_webp($upload, $context) {
$file_path = $upload['file'];
$file_type = $upload['type'];
if (!in_array($file_type, ['image/jpeg', 'image/png'])) {
return $upload; // Skip non-JPEG/PNG files
}
if ($file_type === 'image/jpeg') {
$image = imagecreatefromjpeg($file_path);
} else {
$image = imagecreatefrompng($file_path);
// Force palette-based PNGs to truecolor (indexed → RGB)
if ($image && imageistruecolor($image) === false) {
$truecolor = imagecreatetruecolor(imagesx($image), imagesy($image));
imagecopy($truecolor, $image, 0, 0, 0, 0, imagesx($image), imagesy($image));
imagedestroy($image);
$image = $truecolor;
}
}
if (!$image) {
return $upload; // If image creation fails, return original upload
}
$webp_path = preg_replace('/\.(jpe?g|png)$/i', '.webp', $file_path);
if ($file_type === 'image/png') {
imagealphablending($image, false);
imagesavealpha($image, true);
}
// Get quality setting from wp_options
$quality = get_option('zedsuite_webpconv_quality', 75);
// If quality is 101 then save with lossless compression
$webp_saved = ($quality == 101)
? imagewebp($image, $webp_path, true)
: imagewebp($image, $webp_path, $quality);
if ($webp_saved) {
imagedestroy($image);
// Validate WebP file
if (file_exists($webp_path) && getimagesize($webp_path)['mime'] === 'image/webp') {
unlink($file_path); // Delete the original file
// Update media library to point to the WebP file
$upload['file'] = $webp_path;
$upload['type'] = 'image/webp';
$upload['url'] = preg_replace('/\.(jpe?g|png)$/i', '.webp', $upload['url']);
} else {
unlink($webp_path); // Remove invalid WebP file
add_action('admin_notices', function () {
echo '<div class="notice notice-error"><p><strong>Error:</strong> Image conversion to WebP failed. The original file has been kept.</p></div>';
});
}
}
return $upload;
}
add_action('admin_menu', 'zs_webp_settings_menu');
function zs_webp_settings_menu() {
add_submenu_page(
'upload.php', // Parent slug (Media menu)
'ZS WebP Settings', // Page title
'ZS WebP Settings', // Menu title
'manage_options', // Capability (admin only)
'zs-webp-settings', // Menu slug
'zs_webp_settings_page' // Callback to render page
);
}
function zs_webp_settings_page() {
if (!current_user_can('manage_options')) {
wp_die('Unauthorized user');
}
$option_key = 'zedsuite_webpconv_quality';
$default_quality = 75;
// Folder paths
$plugin_dir = plugin_dir_path(__FILE__);
$webp_dir = $plugin_dir . 'samples/'; // Your 10 images here
// Scan webp files
$webp_files = glob($webp_dir . '*.webp');
// Create option on first load
if (get_option($option_key) === false) {
add_option($option_key, $default_quality);
}
// Handle form actions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['zs_webp_reset'])) {
update_option($option_key, $default_quality);
} elseif (isset($_POST['zs_webp_save']) && isset($_POST['webp_quality'])) {
$q = intval($_POST['webp_quality']);
if ($q >= 0 && $q <= 101) {
update_option($option_key, $q);
}
}
}
$quality = intval(get_option($option_key));
$plugin_data = get_plugin_data(__FILE__);
$version = esc_html($plugin_data['Version']);
?>
<div class="wrap">
<h1>ZS WebP Converter Settings</h1>
<p><strong>Version:</strong> <?php echo $version; ?></p>
<p>This plugin automatically converts JPEG and PNG uploads to WebP format. You can adjust the quality of the output image below. Use a lower value for smaller files, or 101 for lossless compression.</p>
<form method="post">
<table class="form-table">
<tr>
<th scope="row">
<label for="webp_quality">WebP Quality</label>
</th>
<td>
<input style="width: 300px;" type="range" min="0" max="101" id="webp_quality" name="webp_quality" value="<?php echo $quality; ?>" oninput="this.nextElementSibling.value = this.value">
<output><?php echo $quality; ?></output>
<p class="description">0 = lowest quality, 101 = lossless</p>
</td>
</tr>
</table>
<div style="display: flex; justify-content: flex-start; gap: 10px;">
<button type="submit" name="zs_webp_reset" class="button button-secondary">Reset</button>
<button type="submit" name="zs_webp_save" class="button button-primary">Save</button>
</div>
</form>
</div>
<h2>Test</h2>
<div id="zs_webp_test_images" style="display:flex; flex-wrap: wrap; gap: 10px;">
<?php foreach ($webp_files as $webp_file):
$basename = basename($webp_file, '.webp');
$url = plugin_dir_url(__FILE__) . "samples/$basename.webp";
?>
<img src="<?php echo esc_url($url); ?>" data-basename="<?php echo esc_attr($basename); ?>" style="cursor:pointer; width: 100px; height: auto; border: 1px solid #ccc;" />
<?php endforeach; ?>
</div>
<?php
if (file_exists($png_path)) {
$sizeBytes = filesize($png_path); // Size in bytes
$PNGsizeKB = round($sizeBytes / 1024, 2); // Convert to KB, 2 decimal places
}
if (file_exists($webp_tmp_path)) {
$sizeBytes = filesize($webp_tmp_path); // Size in bytes
$WebPsizeKB = round($sizeBytes / 1024, 2); // Convert to KB, 2 decimal places
}
?>
<div id="zs_webp_test_slider_container" style="margin-top: 20px; display:none;">
<h3>Comparison</h3>
<div class="img-comp-labels" style="max-width: 600px; margin: auto;">
<div id="webp-label" class="img-comp-labels-child img-comp-labels-left">WebP [<?php echo esc_attr($WebPsizeKB); ?> KBytes]</div>
<div id="png-label" class="img-comp-labels-child img-comp-labels-right">PNG [<?php echo esc_attr($PNGsizeKB); ?> KBytes]</div>
</div>
<div id="zs_webp_slider" class="img-comp-container" style="max-width: 600px; margin: auto;">
<img id="before_img" src="" alt="Before Image" class="img-comp-img" />
<div class="img-comp-overlay">
<img id="after_img" src="" alt="After Image" class="img-comp-img" />
</div>
<div class="slider-handle">⇄</div>
</div>
<p id="zs_webp_source_info"></p>
</div>
</div>
<style>
#wpfooter {
position: relative !important;
margin-top: 800px !important; /* Adjust height as needed */
}
</style>
<?php
}
add_action('admin_enqueue_scripts', 'zs_enqueue_webp_test_scripts');
function zs_enqueue_webp_test_scripts($hook) {
if ($hook !== 'media_page_zs-webp-settings') return;
wp_enqueue_style('zs-webp-test-style', plugin_dir_url(__FILE__) . 'css/webp-test.css', [], '1.0');
wp_enqueue_script('zs-webp-test-script', plugin_dir_url(__FILE__) . 'js/webp-test.js', ['jquery'], '1.0', true);
// Pass ajax URL and nonce for PNG conversion
wp_localize_script('zs-webp-test-script', 'zsWebpTest', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('zs_webp_test_nonce'),
'quality' => intval(get_option('zedsuite_webpconv_quality', 75)),
'plugin_url' => plugin_dir_url(__FILE__),
]);
}
add_action('wp_ajax_zs_convert_png_to_webp', 'zs_ajax_convert_png_to_webp');
function zs_ajax_convert_png_to_webp() {
check_ajax_referer('zs_webp_test_nonce', 'nonce');
$basename = sanitize_file_name($_POST['basename'] ?? '');
#$quality = intval($_POST['quality'] ?? 75);
$quality = get_option('zedsuite_webpconv_quality', 75);
if ($basename === '') {
wp_send_json_error('Invalid basename');
}
$plugin_dir = plugin_dir_path(__FILE__);
$samples_dir = $plugin_dir . 'samples/';
$temp_dir = $plugin_dir . 'temp/';
$png_path = $samples_dir . $basename . '.png';
$webp_tmp_path = $temp_dir . $basename . '_temp.webp';
if (!file_exists($png_path)) {
wp_send_json_error('PNG file missing');
}
$image = imagecreatefrompng($png_path);
if (!$image) {
wp_send_json_error('Could not load PNG');
}
if ($quality === 101) {
$result = imagewebp($image, $webp_tmp_path, 100);
// Set lossless flag
// PHP GD does not natively support lossless, but imagick can.
// For simplicity, treat 101 as 100 quality here.
} else {
$result = imagewebp($image, $webp_tmp_path, $quality);
}
imagedestroy($image);
if (!$result) {
wp_send_json_error('Conversion failed');
}
$webp_url = plugin_dir_url(__FILE__) . "temp/{$basename}_temp.webp";
$png_url = plugin_dir_url(__FILE__) . "samples/{$basename}.png";
// Read NFO file content
$nfo_path = $samples_dir . $basename . '.nfo';
$source_info = '';
if (file_exists($nfo_path)) {
$source_info = trim(file_get_contents($nfo_path));
}
if (file_exists($png_path)) {
$sizeBytes = filesize($png_path); // Size in bytes
$PNGsizeKB = round($sizeBytes / 1024, 2); // Convert to KB, 2 decimal places
}
if (file_exists($webp_tmp_path)) {
$sizeBytes = filesize($webp_tmp_path); // Size in bytes
$WebPsizeKB = round($sizeBytes / 1024, 2); // Convert to KB, 2 decimal places
}
wp_send_json_success([
'webp_url' => $webp_url,
'webp_size' => $WebPsizeKB,
'png_url' => $png_url,
'png_size' => $PNGsizeKB,
'source_info' => $source_info,
]);
}