diff --git a/0.1.1/zs-convert-to-webp.php b/0.1.1/zs-convert-to-webp.php
new file mode 100644
index 0000000..f844c00
--- /dev/null
+++ b/0.1.1/zs-convert-to-webp.php
@@ -0,0 +1,53 @@
+
Error: Image conversion to WebP failed. The original file has been kept.
';
+ });
+ }
+ }
+
+ return $upload;
+}
+
+
diff --git a/0.2.1/css/webp-test.css b/0.2.1/css/webp-test.css
new file mode 100644
index 0000000..3cdc5eb
--- /dev/null
+++ b/0.2.1/css/webp-test.css
@@ -0,0 +1,56 @@
+.img-comp-container {
+ position: relative;
+ height: auto;
+ overflow: hidden;
+ display: none;
+}
+.img-comp-img {
+ width: auto;
+ height: 100%;
+ display: block;
+ position: relative;
+}
+.img-comp-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+ height: 100%;
+ width: 50%; /* Default */
+}
+/*.img-comp-overlay img {
+ width: 100%;
+ height: 100%;
+ display: block;
+ position: relative;
+}*/
+.slider-handle {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 24px;
+ background: rgba(255,255,255,0.5);
+ border: 1px solid #999;
+ cursor: ew-resize;
+ z-index: 10;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+}
+.img-comp-labels {
+ display: flex;
+ width: 100%; /* or any fixed width */
+ height: auto; /* example height */
+}
+.img-comp-labels-child {
+ flex: 1; /* both boxes take equal space */
+ padding: 20px;
+ box-sizing: border-box;
+}
+.img-comp-labels-left {
+ text-align: left;
+}
+.img-comp-labels-right {
+ text-align: right;
+}
diff --git a/0.2.1/js/webp-test.js b/0.2.1/js/webp-test.js
new file mode 100644
index 0000000..299e49b
--- /dev/null
+++ b/0.2.1/js/webp-test.js
@@ -0,0 +1,94 @@
+jQuery(document).ready(function($){
+ const sliderContainer = $('#zs_webp_test_slider_container');
+ const beforeImg = $('#before_img');
+ const afterImg = $('#after_img');
+ const sliderHandle = $('.slider-handle');
+ const overlay = $('.img-comp-overlay');
+ const sourceInfo = $('#zs_webp_source_info');
+ const labelWebP = $('#webp-label');
+ const labelPNG = $('#png-label');
+ let dragging = false;
+
+ function waitForImagesToLoad(callback) {
+ let loadedCount = 0;
+
+ function checkLoaded() {
+ loadedCount++;
+ if (loadedCount === 2) {
+ callback();
+ }
+ }
+
+ // If already loaded (from cache)
+ if (beforeImg[0].complete) checkLoaded();
+ else beforeImg.on('load', checkLoaded).on('error', function () {
+ console.error("Before image failed to load.");
+ });
+
+ if (afterImg[0].complete) checkLoaded();
+ else afterImg.on('load', checkLoaded).on('error', function () {
+ console.error("After image failed to load.");
+ });
+ }
+
+ //function setOverlayWidth(percent) {
+ // overlay.width(percent + '%');
+ // sliderHandle.css('left', percent + '%');
+ //}
+ function setOverlayWidth(percent) {
+ $('.img-comp-overlay').css('width', percent + '%');
+ $('.slider-handle').css('left', percent + '%');
+ }
+
+ // Then call this function
+ waitForImagesToLoad(function () {
+ $('.img-comp-container').fadeIn();
+ //initializeSlider(); // Your custom slider logic
+
+ // Initialize slider position to 50%
+ setOverlayWidth(50);
+
+ // Draggable handle
+ sliderHandle.on('mousedown touchstart', function(e) {
+ e.preventDefault();
+ dragging = true;
+ });
+ $(document).on('mouseup touchend', function() {
+ dragging = false;
+ });
+ $(document).on('mousemove touchmove', function(e) {
+ if (!dragging) return;
+ let containerOffset = sliderContainer.offset().left;
+ let pageX = e.pageX || e.originalEvent.touches[0].pageX;
+ let pos = pageX - containerOffset;
+ let width = sliderContainer.width();
+ let percent = Math.min(Math.max(pos / width * 100, 0), 100);
+ setOverlayWidth(percent);
+ });
+
+ // Click on any webp sample to load before/after
+ $('#zs_webp_test_images img').click(function(){
+ let basename = $(this).data('basename');
+ $.post(zsWebpTest.ajax_url, {
+ action: 'zs_convert_png_to_webp',
+ nonce: zsWebpTest.nonce,
+ basename: basename,
+ quality: $('#zs_webp_quality_slider').val()
+ }, function(response){
+ if (response.success) {
+ let originalPNG = zsWebpTest.plugin_url + 'samples/' + basename + '.png';
+ let convertedWebP = response.data.webp_url;
+ beforeImg.attr('src', originalPNG);
+ afterImg.attr('src', convertedWebP);
+ labelWebP.html('WebP [' + response.data.webp_size + ' KBytes]');
+ labelPNG.html('PNG [' + response.data.png_size + ' KBytes]');
+ sourceInfo.html('Source: ' + response.data.source_info + '');
+ sliderContainer.show();
+ setOverlayWidth(50);
+ } else {
+ alert(response.data || 'Error loading images');
+ }
+ });
+ });
+ });
+});
diff --git a/0.2.1/samples/blackboard.nfo b/0.2.1/samples/blackboard.nfo
new file mode 100644
index 0000000..5c5722e
--- /dev/null
+++ b/0.2.1/samples/blackboard.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/business-idea-planning-board-3683781/
diff --git a/0.2.1/samples/blackboard.png b/0.2.1/samples/blackboard.png
new file mode 100644
index 0000000..75fcccc
Binary files /dev/null and b/0.2.1/samples/blackboard.png differ
diff --git a/0.2.1/samples/building.nfo b/0.2.1/samples/building.nfo
new file mode 100644
index 0000000..5751ad0
--- /dev/null
+++ b/0.2.1/samples/building.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/mexico-cdmx-reform-chapultepec-7596566/
diff --git a/0.2.1/samples/building.png b/0.2.1/samples/building.png
new file mode 100644
index 0000000..ebabd4f
Binary files /dev/null and b/0.2.1/samples/building.png differ
diff --git a/0.2.1/samples/citylights.nfo b/0.2.1/samples/citylights.nfo
new file mode 100644
index 0000000..0817f11
--- /dev/null
+++ b/0.2.1/samples/citylights.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/boat-lake-mountains-snow-italy-6686952/
diff --git a/0.2.1/samples/citylights.png b/0.2.1/samples/citylights.png
new file mode 100644
index 0000000..cce56f6
Binary files /dev/null and b/0.2.1/samples/citylights.png differ
diff --git a/0.2.1/samples/desk.nfo b/0.2.1/samples/desk.nfo
new file mode 100644
index 0000000..98d108e
--- /dev/null
+++ b/0.2.1/samples/desk.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/coffee-phone-paper-business-792113/
diff --git a/0.2.1/samples/desk.png b/0.2.1/samples/desk.png
new file mode 100644
index 0000000..628f46f
Binary files /dev/null and b/0.2.1/samples/desk.png differ
diff --git a/0.2.1/samples/duckling.nfo b/0.2.1/samples/duckling.nfo
new file mode 100644
index 0000000..39c564d
--- /dev/null
+++ b/0.2.1/samples/duckling.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/chick-ducklings-nature-cute-animal-8160008/
diff --git a/0.2.1/samples/duckling.png b/0.2.1/samples/duckling.png
new file mode 100644
index 0000000..14689d0
Binary files /dev/null and b/0.2.1/samples/duckling.png differ
diff --git a/0.2.1/samples/girl.nfo b/0.2.1/samples/girl.nfo
new file mode 100644
index 0000000..103b0a4
--- /dev/null
+++ b/0.2.1/samples/girl.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/waiting-unhappy-woman-rain-china-9588284/
diff --git a/0.2.1/samples/girl.png b/0.2.1/samples/girl.png
new file mode 100644
index 0000000..e833b16
Binary files /dev/null and b/0.2.1/samples/girl.png differ
diff --git a/0.2.1/samples/meeting.nfo b/0.2.1/samples/meeting.nfo
new file mode 100644
index 0000000..375f899
--- /dev/null
+++ b/0.2.1/samples/meeting.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/meeting-brainstorming-business-594091/
diff --git a/0.2.1/samples/meeting.png b/0.2.1/samples/meeting.png
new file mode 100644
index 0000000..6ec619a
Binary files /dev/null and b/0.2.1/samples/meeting.png differ
diff --git a/0.2.1/samples/mountains.nfo b/0.2.1/samples/mountains.nfo
new file mode 100644
index 0000000..98d108e
--- /dev/null
+++ b/0.2.1/samples/mountains.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/coffee-phone-paper-business-792113/
diff --git a/0.2.1/samples/mountains.png b/0.2.1/samples/mountains.png
new file mode 100644
index 0000000..3d4092e
Binary files /dev/null and b/0.2.1/samples/mountains.png differ
diff --git a/0.2.1/samples/plane.nfo b/0.2.1/samples/plane.nfo
new file mode 100644
index 0000000..ec0c194
--- /dev/null
+++ b/0.2.1/samples/plane.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/aircraft-pilatus-pc-24-corporate-jet-5611528/
diff --git a/0.2.1/samples/plane.png b/0.2.1/samples/plane.png
new file mode 100644
index 0000000..5e9c557
Binary files /dev/null and b/0.2.1/samples/plane.png differ
diff --git a/0.2.1/samples/street.nfo b/0.2.1/samples/street.nfo
new file mode 100644
index 0000000..0c5605e
--- /dev/null
+++ b/0.2.1/samples/street.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/street-japan-city-urban-road-5130030/
diff --git a/0.2.1/samples/street.png b/0.2.1/samples/street.png
new file mode 100644
index 0000000..1bdf05f
Binary files /dev/null and b/0.2.1/samples/street.png differ
diff --git a/0.2.1/zs-convert-to-webp.php b/0.2.1/zs-convert-to-webp.php
new file mode 100644
index 0000000..4914893
--- /dev/null
+++ b/0.2.1/zs-convert-to-webp.php
@@ -0,0 +1,298 @@
+Error: Image conversion to WebP failed. The original file has been kept.
';
+ });
+ }
+ }
+
+ 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']);
+ ?>
+
+
+
ZS WebP Converter Settings
+
Version:
+
+
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.
+
+
+
+
+ Test
+
+
+
; ?>)
+
+
+
+
+
+
+
Comparison
+
+
WebP [ KBytes]
+
PNG [ KBytes]
+
+
+
![Before Image]()
+
+
![After Image]()
+
+
⇄
+
+
+
+
+
+
+
+ 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,
+ ]);
+}
+
diff --git a/0.2/css/webp-test.css b/0.2/css/webp-test.css
new file mode 100644
index 0000000..3cdc5eb
--- /dev/null
+++ b/0.2/css/webp-test.css
@@ -0,0 +1,56 @@
+.img-comp-container {
+ position: relative;
+ height: auto;
+ overflow: hidden;
+ display: none;
+}
+.img-comp-img {
+ width: auto;
+ height: 100%;
+ display: block;
+ position: relative;
+}
+.img-comp-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ overflow: hidden;
+ height: 100%;
+ width: 50%; /* Default */
+}
+/*.img-comp-overlay img {
+ width: 100%;
+ height: 100%;
+ display: block;
+ position: relative;
+}*/
+.slider-handle {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 24px;
+ background: rgba(255,255,255,0.5);
+ border: 1px solid #999;
+ cursor: ew-resize;
+ z-index: 10;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 18px;
+}
+.img-comp-labels {
+ display: flex;
+ width: 100%; /* or any fixed width */
+ height: auto; /* example height */
+}
+.img-comp-labels-child {
+ flex: 1; /* both boxes take equal space */
+ padding: 20px;
+ box-sizing: border-box;
+}
+.img-comp-labels-left {
+ text-align: left;
+}
+.img-comp-labels-right {
+ text-align: right;
+}
diff --git a/0.2/js/webp-test.js b/0.2/js/webp-test.js
new file mode 100644
index 0000000..299e49b
--- /dev/null
+++ b/0.2/js/webp-test.js
@@ -0,0 +1,94 @@
+jQuery(document).ready(function($){
+ const sliderContainer = $('#zs_webp_test_slider_container');
+ const beforeImg = $('#before_img');
+ const afterImg = $('#after_img');
+ const sliderHandle = $('.slider-handle');
+ const overlay = $('.img-comp-overlay');
+ const sourceInfo = $('#zs_webp_source_info');
+ const labelWebP = $('#webp-label');
+ const labelPNG = $('#png-label');
+ let dragging = false;
+
+ function waitForImagesToLoad(callback) {
+ let loadedCount = 0;
+
+ function checkLoaded() {
+ loadedCount++;
+ if (loadedCount === 2) {
+ callback();
+ }
+ }
+
+ // If already loaded (from cache)
+ if (beforeImg[0].complete) checkLoaded();
+ else beforeImg.on('load', checkLoaded).on('error', function () {
+ console.error("Before image failed to load.");
+ });
+
+ if (afterImg[0].complete) checkLoaded();
+ else afterImg.on('load', checkLoaded).on('error', function () {
+ console.error("After image failed to load.");
+ });
+ }
+
+ //function setOverlayWidth(percent) {
+ // overlay.width(percent + '%');
+ // sliderHandle.css('left', percent + '%');
+ //}
+ function setOverlayWidth(percent) {
+ $('.img-comp-overlay').css('width', percent + '%');
+ $('.slider-handle').css('left', percent + '%');
+ }
+
+ // Then call this function
+ waitForImagesToLoad(function () {
+ $('.img-comp-container').fadeIn();
+ //initializeSlider(); // Your custom slider logic
+
+ // Initialize slider position to 50%
+ setOverlayWidth(50);
+
+ // Draggable handle
+ sliderHandle.on('mousedown touchstart', function(e) {
+ e.preventDefault();
+ dragging = true;
+ });
+ $(document).on('mouseup touchend', function() {
+ dragging = false;
+ });
+ $(document).on('mousemove touchmove', function(e) {
+ if (!dragging) return;
+ let containerOffset = sliderContainer.offset().left;
+ let pageX = e.pageX || e.originalEvent.touches[0].pageX;
+ let pos = pageX - containerOffset;
+ let width = sliderContainer.width();
+ let percent = Math.min(Math.max(pos / width * 100, 0), 100);
+ setOverlayWidth(percent);
+ });
+
+ // Click on any webp sample to load before/after
+ $('#zs_webp_test_images img').click(function(){
+ let basename = $(this).data('basename');
+ $.post(zsWebpTest.ajax_url, {
+ action: 'zs_convert_png_to_webp',
+ nonce: zsWebpTest.nonce,
+ basename: basename,
+ quality: $('#zs_webp_quality_slider').val()
+ }, function(response){
+ if (response.success) {
+ let originalPNG = zsWebpTest.plugin_url + 'samples/' + basename + '.png';
+ let convertedWebP = response.data.webp_url;
+ beforeImg.attr('src', originalPNG);
+ afterImg.attr('src', convertedWebP);
+ labelWebP.html('WebP [' + response.data.webp_size + ' KBytes]');
+ labelPNG.html('PNG [' + response.data.png_size + ' KBytes]');
+ sourceInfo.html('Source: ' + response.data.source_info + '');
+ sliderContainer.show();
+ setOverlayWidth(50);
+ } else {
+ alert(response.data || 'Error loading images');
+ }
+ });
+ });
+ });
+});
diff --git a/0.2/samples/blackboard.nfo b/0.2/samples/blackboard.nfo
new file mode 100644
index 0000000..5c5722e
--- /dev/null
+++ b/0.2/samples/blackboard.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/business-idea-planning-board-3683781/
diff --git a/0.2/samples/blackboard.png b/0.2/samples/blackboard.png
new file mode 100644
index 0000000..75fcccc
Binary files /dev/null and b/0.2/samples/blackboard.png differ
diff --git a/0.2/samples/building.nfo b/0.2/samples/building.nfo
new file mode 100644
index 0000000..5751ad0
--- /dev/null
+++ b/0.2/samples/building.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/mexico-cdmx-reform-chapultepec-7596566/
diff --git a/0.2/samples/building.png b/0.2/samples/building.png
new file mode 100644
index 0000000..ebabd4f
Binary files /dev/null and b/0.2/samples/building.png differ
diff --git a/0.2/samples/citylights.nfo b/0.2/samples/citylights.nfo
new file mode 100644
index 0000000..0817f11
--- /dev/null
+++ b/0.2/samples/citylights.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/boat-lake-mountains-snow-italy-6686952/
diff --git a/0.2/samples/citylights.png b/0.2/samples/citylights.png
new file mode 100644
index 0000000..cce56f6
Binary files /dev/null and b/0.2/samples/citylights.png differ
diff --git a/0.2/samples/desk.nfo b/0.2/samples/desk.nfo
new file mode 100644
index 0000000..98d108e
--- /dev/null
+++ b/0.2/samples/desk.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/coffee-phone-paper-business-792113/
diff --git a/0.2/samples/desk.png b/0.2/samples/desk.png
new file mode 100644
index 0000000..628f46f
Binary files /dev/null and b/0.2/samples/desk.png differ
diff --git a/0.2/samples/duckling.nfo b/0.2/samples/duckling.nfo
new file mode 100644
index 0000000..39c564d
--- /dev/null
+++ b/0.2/samples/duckling.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/chick-ducklings-nature-cute-animal-8160008/
diff --git a/0.2/samples/duckling.png b/0.2/samples/duckling.png
new file mode 100644
index 0000000..14689d0
Binary files /dev/null and b/0.2/samples/duckling.png differ
diff --git a/0.2/samples/girl.nfo b/0.2/samples/girl.nfo
new file mode 100644
index 0000000..103b0a4
--- /dev/null
+++ b/0.2/samples/girl.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/waiting-unhappy-woman-rain-china-9588284/
diff --git a/0.2/samples/girl.png b/0.2/samples/girl.png
new file mode 100644
index 0000000..e833b16
Binary files /dev/null and b/0.2/samples/girl.png differ
diff --git a/0.2/samples/meeting.nfo b/0.2/samples/meeting.nfo
new file mode 100644
index 0000000..375f899
--- /dev/null
+++ b/0.2/samples/meeting.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/meeting-brainstorming-business-594091/
diff --git a/0.2/samples/meeting.png b/0.2/samples/meeting.png
new file mode 100644
index 0000000..6ec619a
Binary files /dev/null and b/0.2/samples/meeting.png differ
diff --git a/0.2/samples/mountains.nfo b/0.2/samples/mountains.nfo
new file mode 100644
index 0000000..98d108e
--- /dev/null
+++ b/0.2/samples/mountains.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/coffee-phone-paper-business-792113/
diff --git a/0.2/samples/mountains.png b/0.2/samples/mountains.png
new file mode 100644
index 0000000..3d4092e
Binary files /dev/null and b/0.2/samples/mountains.png differ
diff --git a/0.2/samples/plane.nfo b/0.2/samples/plane.nfo
new file mode 100644
index 0000000..ec0c194
--- /dev/null
+++ b/0.2/samples/plane.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/aircraft-pilatus-pc-24-corporate-jet-5611528/
diff --git a/0.2/samples/plane.png b/0.2/samples/plane.png
new file mode 100644
index 0000000..5e9c557
Binary files /dev/null and b/0.2/samples/plane.png differ
diff --git a/0.2/samples/street.nfo b/0.2/samples/street.nfo
new file mode 100644
index 0000000..0c5605e
--- /dev/null
+++ b/0.2/samples/street.nfo
@@ -0,0 +1 @@
+https://pixabay.com/photos/street-japan-city-urban-road-5130030/
diff --git a/0.2/samples/street.png b/0.2/samples/street.png
new file mode 100644
index 0000000..1bdf05f
Binary files /dev/null and b/0.2/samples/street.png differ
diff --git a/0.2/zs-convert-to-webp.php b/0.2/zs-convert-to-webp.php
new file mode 100644
index 0000000..dc9089e
--- /dev/null
+++ b/0.2/zs-convert-to-webp.php
@@ -0,0 +1,298 @@
+Error: Image conversion to WebP failed. The original file has been kept.
';
+ });
+ }
+ }
+
+ 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']);
+ ?>
+
+
+
ZS WebP Converter Settings
+
Version:
+
+
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.
+
+
+
+
+ Test
+
+
+
; ?>)
+
+
+
+
+
+
+
Comparison
+
+
WebP [ KBytes]
+
PNG [ KBytes]
+
+
+
![Before Image]()
+
+
![After Image]()
+
+
⇄
+
+
+
+
+
+
+
+ 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,
+ ]);
+}
+