Skip to main content
Code Review

Return to Question

Notice removed Authoritative reference needed by Community Bot
Bounty Ended with Sᴀᴍ Onᴇᴌᴀ's answer chosen by Community Bot
update formatting
Source Link
  • Automatically converts images on upload to WebP and AVIF formats using predefined quality settings. Uses imagecreatefromjpeg/png/gif and imagewebp/imageavif functions.

  • Adds custom fields in media library for per-image quality control of JPEG, WebP, and AVIF.

  • Bulk conversion utility to convert all existing media library images. Shows progress bar during conversion.

  • Option to bulk delete all WebP/AVIF images.

  • Fallback to original image formats if WebP/AVIF is not supported by the browser.

    Uses best practices like namespace organization, OOP structure, and exception handling.

class-web-avif-converter.php

class-web-avif-converter.php

attachment_hooks.php

attachment_hooks.php

generator-utils.php

generator-utils.php

utils.php

utils.php

  • Automatically converts images on upload to WebP and AVIF using predefined quality settings. Uses imagecreatefromjpeg/png/gif and imagewebp/imageavif functions.

  • Adds custom fields in media library for per-image quality control of JPEG, WebP, and AVIF.

  • Bulk conversion utility to convert all existing media library images. Shows progress bar during conversion.

  • Option to bulk delete all WebP/AVIF images.

  • Fallback to original image formats if WebP/AVIF is not supported by the browser.

    Uses best practices like namespace organization, OOP structure, and exception handling.

class-web-avif-converter.php

attachment_hooks.php

generator-utils.php

utils.php

  • Automatically converts images on upload to WebP and AVIF formats using predefined quality settings. Uses imagecreatefromjpeg/png/gif and imagewebp/imageavif functions.

  • Adds custom fields in media library for per-image quality control of JPEG, WebP, and AVIF.

  • Bulk conversion utility to convert all existing media library images. Shows progress bar during conversion.

  • Option to bulk delete all WebP/AVIF images.

  • Fallback to original image formats if WebP/AVIF is not supported by the browser.

    Uses best practices like namespace organization, OOP structure, and exception handling.

class-web-avif-converter.php

attachment_hooks.php

generator-utils.php

utils.php

Notice added Authoritative reference needed by KermitTheFrog
Bounty Started worth 100 reputation by KermitTheFrog
added 91 characters in body
Source Link

class-web-avif-converter.php

<?php
/**
 * The plugin bootstrap file
 *
 * This file is read by WordPress to generate the plugin information in the plugin
 * admin area. This file also includes all of the dependencies used by the plugin,
 * registers the activation and deactivation functions, and defines a function
 * that starts the plugin.
 *
 * @link https://rekurencja.com/
 * @since 1.0.0
 * @package Web_Avif_Converter
 *
 * @wordpress-plugin
 * Plugin Name: WebP & Avif Converter
 * Plugin URI: https://images.rekurencja.com
 * Description: Fast and simple plugin to automatically convert and serve WebP & AVIF images.
 * Version: 1.0.0
 * Author: Rekurencja
 * Author URI: https://rekurencja.com/
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain: web-avif-converter
 * Domain Path: /languages
 */
// If this file is called directly, abort.
if (!defined('WPINC')) {
 die;
}
define('PHP_REQUIRED_VERSION', '8.1.0');
define('PHP_VERSION_OK', version_compare(phpversion(), PHP_REQUIRED_VERSION, '>='));
define('DEFAULT_QUALITY', 82);
require plugin_dir_path(__FILE__) . 'public/src/utils/utils.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/activation_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/attachment_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/utils/generator-utils.php';
// exceptions
require plugin_dir_path(__FILE__) . 'public/src/exceptions/exceptions.php';
// Include admin.php for admin page functionality
if (is_admin()) {
 require plugin_dir_path(__FILE__) . 'public/src/admin.php';
}
register_activation_hook(__FILE__, 'WebAvifConverter\Hooks\activate_web_avif_converter');
register_deactivation_hook(__FILE__, 'WebAvifConverter\Hooks\deactivate_web_avif_converter');
add_filter('attachment_fields_to_edit', 'add_image_quality_field', 10, 2);
add_filter('manage_media_columns', 'add_image_quality_column');
add_action('manage_media_custom_column', 'display_image_quality_column', 10, 2);
add_filter('jpeg_quality', 'get_jpeg_quality');
function get_jpeg_quality($quality)
{
 return get_option('wac_quality_jpeg', 82);
}
use WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
function add_image_quality_column($columns)
{
 $columns['quality_webp'] = 'WebP Quality';
 $columns['quality_avif'] = 'Avif Quality';
 $columns['quality_jpeg'] = 'Jpeg Quality';
 return $columns;
}
function add_image_quality_field($form_fields, $post)
{
 // wp_die( print_r( $form_fields ));
 $form_fields['quality_webp'] = generate_quality_field($post->ID, 'quality_webp', 'Quality of WEBP');
 $form_fields['quality_avif'] = generate_quality_field($post->ID, 'quality_avif', 'Quality of AVIF');
 $form_fields['quality_jpeg'] = generate_quality_field($post->ID, 'quality_jpeg', 'Quality of JPEG');
 return $form_fields;
}
function determine_image_extension($image_url)
{
 $extension = pathinfo($image_url, PATHINFO_EXTENSION);
 return strtolower($extension);
}
function generate_quality_field($post_id, $field_name, $field_label)
{
 // get post metadata
 $metadata = wp_get_attachment_metadata($post_id);
 // echo $post_id;
 // wp_die(print_r($metadata));
 if (isset(wp_get_attachment_metadata($post_id)[$field_name])) {
 $field_value = wp_get_attachment_metadata($post_id)[$field_name];
 $placeholder_value = $field_value;
 } else {
 $field_value = '';
 $placeholder_value = 'Quality is not set';
 }
 $input_html = "<input type='number' min='0' max='100' step='1' ";
 $input_html .= "name='attachments[$post_id][$field_name]' ";
 $input_html .= "value='" . esc_attr($field_value ? $field_value : '') . "' ";
 $input_html .= "placeholder='" . esc_attr($placeholder_value) . "'/>";
 $field = array(
 'label' => $field_label,
 'input' => 'html',
 'helps' => 'Enter a value between 1 and 100 for image quality (100 = best quality, 1 = worst quality)',
 'html' => $input_html,
 );
 return $field;
}
function display_image_quality_column($column_name, $attachment_id)
{
 $allowed_columns = ['quality_avif', 'quality_webp', 'quality_jpeg'];
 if (in_array($column_name, $allowed_columns)) {
 $attachment_metadata = wp_get_attachment_metadata($attachment_id);
 if (isset($attachment_metadata[$column_name])) {
 echo $attachment_metadata[$column_name];
 } else {
 echo 'N/A';
 }
 }
}
add_action('admin_menu', 'webp_avif_bulk_convert_menu');
function webp_avif_bulk_convert_menu()
{
 add_submenu_page(
 'options-general.php',
 'WebP & Avif Converter',
 'WebP & Avif Converter',
 'manage_options',
 'webp_avif_bulk_convert',
 'webp_avif_bulk_convert_page'
 );
}
function get_images_size_info()
{
 // loop through all images
 $images = get_posts(
 array(
 'post_type' => 'attachment',
 'post_mime_type' => 'image',
 'numberposts' => -1,
 )
 );
 $images_size_info = [
 "total_original_size" => 0,
 "total_avif_size" => 0,
 "total_webp_size" => 0,
 ];
 echo "<div class='summary-wrapper'>";
 foreach ($images as $image) {
 try {
 // Determine the extension
 $extension = determine_image_extension($image->guid);
 // Handle unsupported extensions
 if ($extension === 'svg' || $extension === 'gif') {
 throw new FilesizeUnavailableException($extension, 'Unsupported extension: ' . $extension);
 }
 $metadata = wp_get_attachment_metadata($image->ID);
 $cur_image_size_info = [
 "original_size" => isset($metadata['filesize']) ? $metadata['filesize'] : 0,
 "avif_size" => 0,
 "webp_size" => 0,
 ];
 if (isset($metadata['sizes'])) {
 foreach ($metadata['sizes'] as $size_name => $size) {
 $cur_image_size_info["original_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_avif'])) {
 foreach ($metadata['sizes_avif'] as $size_name => $size) {
 $cur_image_size_info["avif_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_webp'])) {
 foreach ($metadata['sizes_webp'] as $size_name => $size) {
 $cur_image_size_info["webp_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (!isset($metadata['sizes'])) {
 throw new FilesizeUnavailableException('Unknown', 'Filesize information not available for this file.');
 }
 $images_size_info['total_original_size'] += $cur_image_size_info['original_size'];
 $images_size_info['total_avif_size'] += $cur_image_size_info['avif_size'];
 $images_size_info['total_webp_size'] += $cur_image_size_info['webp_size'];
 echo "<div class='summary-item'>";
 echo "<img src='" . $image->guid . "' alt='Image ID: " . $image->ID . "' width='150px'>";
 echo "<h4>Image ID: " . $image->ID . "</h4>";
 echo "<p>Image Title: <b>" . $image->post_title . "</b></p>";
 echo "<p>Original size: " . size_format($cur_image_size_info['original_size']) . " </p>";
 echo "<p>Avif size: " . size_format($cur_image_size_info['avif_size']) . "</p>";
 echo "<p>Webp size: " . size_format($cur_image_size_info['webp_size']) . "</p>";
 echo "</div>";
 } catch (FilesizeUnavailableException $e) {
 echo "Filesize information not available for image ID " . $image->ID . ". " . $e->getMessage();
 } catch (Exception $e) {
 echo "An error occurred: " . $e->getMessage();
 }
 }
 
 echo "</div>";
 echo "<div class='total-summary-item'>";
 echo "<h4>Total Summary:</h4>";
 echo "<p>Total Original Image Size: " . size_format($images_size_info['total_original_size']) . "</p>";
 echo "<p>Total AVIF Image Size: " . size_format($images_size_info['total_avif_size']) . "</p>";
 echo "<p>Total WebP Image Size: " . size_format($images_size_info['total_webp_size']) . "</p>";
 echo "</div>";
 return $images_size_info;
}
function webp_avif_bulk_convert_page()
{
 if (isset($_POST['submit'])) {
 $quality_webp = isset($_POST['quality_webp']) ? intval($_POST['quality_webp']) : DEFAULT_QUALITY;
 $quality_avif = isset($_POST['quality_avif']) ? intval($_POST['quality_avif']) : DEFAULT_QUALITY;
 $quality_jpeg = isset($_POST['quality_jpeg']) ? intval($_POST['quality_jpeg']) : DEFAULT_QUALITY;
 if ($_POST['submit'] === 'Set') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 update_option('wac_quality_webp', $quality_webp);
 update_option('wac_quality_avif', $quality_avif);
 update_option('wac_quality_jpeg', $quality_jpeg);
 if (isset($_POST['regenerate']) && $_POST['regenerate'] === 'on') {
 echo '<span class="closebtn icon" onclick="this.parentElement.style.display=\'none\';"></span>';
 echo '<div class="progress-bar" id="progress-bar" style="width: 0%">0%;
 </div>';
 Hooks\update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg);
 echo '<p class="notification notification-good">
 All images have been converted to WebP and Avif formats.
 </p>';
 }
 } else if ($_POST['submit'] === 'Delete') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 Hooks\delete_all_attachments_avif_and_webp();
 echo '<p class="notification notification-bad">
 All WebP and Avif images have been deleted.
 </p>';
 }
 echo '</div>';
 echo '</div>';
 }
 ?>
<div class="image-conversion-wrapper">
 <h1 class="conversion-heading">WebP & Avif Converter </h1>
 <form method="post">
 <?php $isPhpVersionOk = true; ?> <!-- Define PHP_VERSION_OK -->
 <fieldset <?php echo $isPhpVersionOk ? '' : 'disabled' ?>>
 <p class="conversion-description">Tool for WebP and Avif format conversion of all images in the
 uploads/media library directory. <br>
 <b>Choose quality</b> - choose the quality of the converted images (the lower the quality, the smaller
 the size) <br>
 <b>Delete function</b> - deletes all WebP and Avif images from the uploads/media library directory.
 <br>
 <b>Convert function</b> - converts all images in the uploads/media library directory to WebP and Avif
 formats. <br>
 <b>Note: </b> This tool will not convert images that are not in the uploads/media library directory.<br>
 <?php echo Utils\get_php_version_info(); ?>
 </p>
 <div class="conversion-options">
 <label class="option-label">Quality of WEBP: (0 - 100%)</label>
 <input type="number" name="quality_webp" value="<?php echo get_option('wac_quality_webp', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of AVIF: (0 - 100%)</label>
 <input type="number" name="quality_avif" value="<?php echo get_option('wac_quality_avif', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of JPEG: (0 - 100%)</label>
 <input type="number" name="quality_jpeg" value="<?php echo get_option('wac_quality_jpeg', DEFAULT_QUALITY); ?>" min="0" max="100">
 <input type="checkbox" name="regenerate" id="regenerate" checked>
 <label for="regenerate" class="option-label">
 Update qualities of existing images
 </label>
 
 <div class="toggle-summary_w">
 <button id="toggle-summary">Show / Hide Podsumowanie</button>
 </div>
 <div class="conversion-summary-toggle">
 <?php
 // You need to define the get_images_size_info function or include the file that contains it.
 get_images_size_info();
 ?>
 </div>
 </div>
 
 <div class="conversion-buttons">
 <input type="submit" name="submit" value="Set" class="convert-button">
 <input type="submit" name="submit" value="Delete" class="delete-button">
 </div>
 </fieldset>
 </form>
</div>
<?php
}
/**
 * Runs the main functionality of the plugin.
 */
function run_web_avif_converter()
{
 // The 'Web_Avif_Converter' class code is included in the 'includes/class-web-avif-converter.php' file.
 require plugin_dir_path(__FILE__) . 'includes/class-web-avif-converter.php';
 // echo print_r
 $plugin = new Web_Avif_Converter();
 $plugin->run();
}
run_web_avif_converter();

<?php
namespace WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
use WebAvifConverter\GeneratorUtils;
// function p($a, $die = 0){
 // echo '<pre>';
 // echo print_r($a);
 // echo '</pre>';
 // if ($die) { wp_die(); }
// }
apply_filters('jepg_quality', get_option('wac_quality_jpeg', DEFAULT_QUALITY));
add_filter('wp_generate_attachment_metadata', 'WebAvifConverter\Hooks\convert_images_on_generate_attachment_metadata', 10, 2);
function convert_images_on_generate_attachment_metadata($metadata, $attachment_id)
{
 if (!isset($metadata['file'])) { return $metadata; }
 $extension = pathinfo($metadata['file'], PATHINFO_EXTENSION);
 if (!in_array($extension, ['jpg', 'jpeg', 'png'])) { return $metadata; }
 
 $metadata['quality_jpeg'] = get_option('wac_quality_jpeg', DEFAULT_QUALITY);
 wp_update_attachment_metadata($attachment_id, $metadata);
 // Generating JPEGs with adjusted quality is handled by jepg_quality filter
 GeneratorUtils\generate_webp_sizes($attachment_id, get_option('wac_quality_webp', DEFAULT_QUALITY));
 GeneratorUtils\generate_avif_sizes($attachment_id, get_option('wac_quality_avif', DEFAULT_QUALITY));
 return wp_get_attachment_metadata($attachment_id);
}
add_action('edit_attachment', 'WebAvifConverter\Hooks\save_image_quality_metadata');
function save_image_quality_metadata($attachment_id)
{ 
 $metadata = wp_get_attachment_metadata($attachment_id);
 $filed_names = ['quality_jpeg', 'quality_avif', 'quality_webp' ];
 foreach ($filed_names as $filed_name) {
 if (empty($_REQUEST['attachments'][$attachment_id][$filed_name])) { continue; }
 $quality = intval($_REQUEST['attachments'][$attachment_id][$filed_name]);
 if ($quality < 1 || $quality > 100 || isset($metadata[$filed_name]) && $quality === $metadata[$filed_name]) { continue; }
 if ($filed_name === 'quality_jpeg') { GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_webp') { GeneratorUtils\generate_webp_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_avif') { GeneratorUtils\generate_avif_sizes($attachment_id, $quality); }
 } 
}
function update_attachment_quality($attachment_id, $quality_webp = DEFAULT_QUALITY, $quality_avif = DEFAULT_QUALITY, $quality_jpeg = DEFAULT_QUALITY)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata) || !isset($metadata['file']) || !isset($metadata['sizes'])) {
 return; // No metadata found for this attachment.
 }
 if(!isset($metadata['quality_jpeg']) || intval($metadata['quality_jpeg']) !== $quality_jpeg){
 
 GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality_jpeg);
 }
 if(!isset($metadata['quality_webp']) || intval($metadata['quality_webp']) !== $quality_webp){
 
 
 GeneratorUtils\generate_webp_sizes($attachment_id, $quality_webp);
 }
 
 if(!isset($metadata['quality_avif']) || intval($metadata['quality_avif']) !== $quality_avif){
 GeneratorUtils\generate_avif_sizes($attachment_id, $quality_avif);
 }
}
function update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg)
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_status' => null,
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 
 foreach ($attachments as $attachment) {
 $progress++;
 $percent = intval($progress / $total_attachments * 100);
 Utils\update_progress_bar($percent);
 update_attachment_quality($attachment->ID, $quality_webp, $quality_avif, $quality_jpeg);
 }
}
add_filter('delete_attachment', 'WebAvifConverter\Hooks\delete_attachment_files');
function delete_attachment_files($attachment_id)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 $upload_dir = wp_upload_dir()['basedir'];
 if (array_key_exists('file_webp', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_webp']);
 unset($metadata['file_webp']);
 }
 if (array_key_exists('file_avif', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_avif']);
 unset($metadata['file_avif']);
 }
 $attachment_subdir = dirname($metadata['file']);
 $attachment_files_dir = $upload_dir . '/' . $attachment_subdir . '/';
 if (array_key_exists('sizes_avif', $metadata)) {
 foreach ($metadata['sizes_avif'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_avif']);
 }
 
 if (array_key_exists('quality_webp', $metadata)){
 unset($metadata['quality_webp']);
 }
 
 if (array_key_exists('quality_avif', $metadata)){
 unset($metadata['quality_avif']);
 }
 if (array_key_exists('sizes_webp', $metadata)) {
 foreach ($metadata['sizes_webp'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_webp']);
 }wp_update_attachment_metadata($attachment_id, $metadata);
}
function delete_all_attachments_avif_and_webp()
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_mime_type' => 'image',
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 foreach ($attachments as $attachment) {
 delete_attachment_files($attachment->ID); 
 $progress++;
 $percent = intval($progress / $total_attachments * 100) . "%";
 Utils\update_progress_bar($percent);
 }
}
<?php
namespace WebAvifConverter\GeneratorUtils;
/**
 * Convert image to WebP format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted WebP image or void if unable to create an image resource.
 */
 function p($a, $die = 0){
 echo '<pre>';
 echo print_r($a);
 echo '</pre>';
 if ($die) { wp_die(); }
}
function generate_jpeg(string $path, int $quality = 80){
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagejpeg($image, $output_path . '/' . $filename , $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename;
}
function generate_webp(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagewebp($image, $output_path . '/' . $filename . '.webp', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.webp';
}
/**
 * Convert image to AVIF format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted AVIF image or void if unable to create an image resource.
 */
function generate_avif(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imageavif($image, $output_path . '/' . $filename . '.avif', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.avif';
}
function generate_jpeg_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_jpeg'] = $quality;
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 // p($metadata['sizes'], 1);
 foreach($metadata['sizes'] as $size_name => $size){
 $subsize_path = $image_subdir_path . '/' . $size['file'];
 $image = wp_get_image_editor($subsize_path);
 $image->set_quality( $quality );
 $saved = $image->save($subsize_path);
 $metadata['sizes'][$size_name]['filesize'] = filesize($subsize_path);
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_webp_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_webp'] = $quality;
 $metadata['sizes_webp'] = [];
 $metadata['file_webp'] = generate_webp(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['webp_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_webp']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 
 //create or overwrite the subsize image
 $subsize_subpath = generate_webp($original_subsize_path, $quality);
 $metadata['sizes_webp'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/webp',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_avif_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_avif'] = $quality;
 $metadata['sizes_avif'] = [];
 $metadata['file_avif'] = generate_avif(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['avif_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_avif']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 //create or overwrite the subsize image
 $subsize_subpath = generate_avif($original_subsize_path, $quality);
 $metadata['sizes_avif'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/avif',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
<?php
namespace WebAvifConverter\Utils;
/**
 * Helper function for deleting files.
 */
function safe_unlink($path)
{
 if (file_exists($path)) {
 unlink($path);
 }
}
function update_progress_bar($percent) {
 $percent = strval($percent);
 echo "<script>
 var progressBar = document.getElementById('progress-bar');
 progressBar.style.width = '$percent%';
 progressBar.innerHTML = '$percent%';
 </script>";
 ob_flush();
 flush();
}
function get_php_version_info()
{
 if(version_compare(phpversion(), PHP_REQUIRED_VERSION, '>=')){
 return 'PHP Version is: <span class="php-version-good">' . phpversion() . '</span><b> version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 } else {
 return 'PHP Version: <span class="php-version-bad">' . phpversion() . '</span> is too low <.>version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 }
}

attachment_hooks.php

<?php
namespace WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
use WebAvifConverter\GeneratorUtils;
// function p($a, $die = 0){
 // echo '<pre>';
 // echo print_r($a);
 // echo '</pre>';
 // if ($die) { wp_die(); }
// }
apply_filters('jepg_quality', get_option('wac_quality_jpeg', DEFAULT_QUALITY));
add_filter('wp_generate_attachment_metadata', 'WebAvifConverter\Hooks\convert_images_on_generate_attachment_metadata', 10, 2);
function convert_images_on_generate_attachment_metadata($metadata, $attachment_id)
{
 if (!isset($metadata['file'])) { return $metadata; }
 $extension = pathinfo($metadata['file'], PATHINFO_EXTENSION);
 if (!in_array($extension, ['jpg', 'jpeg', 'png'])) { return $metadata; }
 
 $metadata['quality_jpeg'] = get_option('wac_quality_jpeg', DEFAULT_QUALITY);
 wp_update_attachment_metadata($attachment_id, $metadata);
 // Generating JPEGs with adjusted quality is handled by jepg_quality filter
 GeneratorUtils\generate_webp_sizes($attachment_id, get_option('wac_quality_webp', DEFAULT_QUALITY));
 GeneratorUtils\generate_avif_sizes($attachment_id, get_option('wac_quality_avif', DEFAULT_QUALITY));
 return wp_get_attachment_metadata($attachment_id);
}
add_action('edit_attachment', 'WebAvifConverter\Hooks\save_image_quality_metadata');
function save_image_quality_metadata($attachment_id)
{ 
 $metadata = wp_get_attachment_metadata($attachment_id);
 $filed_names = ['quality_jpeg', 'quality_avif', 'quality_webp' ];
 foreach ($filed_names as $filed_name) {
 if (empty($_REQUEST['attachments'][$attachment_id][$filed_name])) { continue; }
 $quality = intval($_REQUEST['attachments'][$attachment_id][$filed_name]);
 if ($quality < 1 || $quality > 100 || isset($metadata[$filed_name]) && $quality === $metadata[$filed_name]) { continue; }
 if ($filed_name === 'quality_jpeg') { GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_webp') { GeneratorUtils\generate_webp_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_avif') { GeneratorUtils\generate_avif_sizes($attachment_id, $quality); }
 } 
}
function update_attachment_quality($attachment_id, $quality_webp = DEFAULT_QUALITY, $quality_avif = DEFAULT_QUALITY, $quality_jpeg = DEFAULT_QUALITY)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata) || !isset($metadata['file']) || !isset($metadata['sizes'])) {
 return; // No metadata found for this attachment.
 }
 if(!isset($metadata['quality_jpeg']) || intval($metadata['quality_jpeg']) !== $quality_jpeg){
 
 GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality_jpeg);
 }
 if(!isset($metadata['quality_webp']) || intval($metadata['quality_webp']) !== $quality_webp){
 
 
 GeneratorUtils\generate_webp_sizes($attachment_id, $quality_webp);
 }
 
 if(!isset($metadata['quality_avif']) || intval($metadata['quality_avif']) !== $quality_avif){
 GeneratorUtils\generate_avif_sizes($attachment_id, $quality_avif);
 }
}
function update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg)
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_status' => null,
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 
 foreach ($attachments as $attachment) {
 $progress++;
 $percent = intval($progress / $total_attachments * 100);
 Utils\update_progress_bar($percent);
 update_attachment_quality($attachment->ID, $quality_webp, $quality_avif, $quality_jpeg);
 }
}
add_filter('delete_attachment', 'WebAvifConverter\Hooks\delete_attachment_files');
function delete_attachment_files($attachment_id)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 $upload_dir = wp_upload_dir()['basedir'];
 if (array_key_exists('file_webp', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_webp']);
 unset($metadata['file_webp']);
 }
 if (array_key_exists('file_avif', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_avif']);
 unset($metadata['file_avif']);
 }
 $attachment_subdir = dirname($metadata['file']);
 $attachment_files_dir = $upload_dir . '/' . $attachment_subdir . '/';
 if (array_key_exists('sizes_avif', $metadata)) {
 foreach ($metadata['sizes_avif'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_avif']);
 }
 
 if (array_key_exists('quality_webp', $metadata)){
 unset($metadata['quality_webp']);
 }
 
 if (array_key_exists('quality_avif', $metadata)){
 unset($metadata['quality_avif']);
 }
 if (array_key_exists('sizes_webp', $metadata)) {
 foreach ($metadata['sizes_webp'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_webp']);
 }wp_update_attachment_metadata($attachment_id, $metadata);
}
function delete_all_attachments_avif_and_webp()
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_mime_type' => 'image',
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 foreach ($attachments as $attachment) {
 delete_attachment_files($attachment->ID); 
 $progress++;
 $percent = intval($progress / $total_attachments * 100) . "%";
 Utils\update_progress_bar($percent);
 }
}

generator-utils.php

<?php
namespace WebAvifConverter\GeneratorUtils;
/**
 * Convert image to WebP format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted WebP image or void if unable to create an image resource.
 */
 function p($a, $die = 0){
 echo '<pre>';
 echo print_r($a);
 echo '</pre>';
 if ($die) { wp_die(); }
}
function generate_jpeg(string $path, int $quality = 80){
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagejpeg($image, $output_path . '/' . $filename , $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename;
}
function generate_webp(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagewebp($image, $output_path . '/' . $filename . '.webp', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.webp';
}
/**
 * Convert image to AVIF format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted AVIF image or void if unable to create an image resource.
 */
function generate_avif(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imageavif($image, $output_path . '/' . $filename . '.avif', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.avif';
}
function generate_jpeg_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_jpeg'] = $quality;
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 // p($metadata['sizes'], 1);
 foreach($metadata['sizes'] as $size_name => $size){
 $subsize_path = $image_subdir_path . '/' . $size['file'];
 $image = wp_get_image_editor($subsize_path);
 $image->set_quality( $quality );
 $saved = $image->save($subsize_path);
 $metadata['sizes'][$size_name]['filesize'] = filesize($subsize_path);
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_webp_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_webp'] = $quality;
 $metadata['sizes_webp'] = [];
 $metadata['file_webp'] = generate_webp(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['webp_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_webp']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 
 //create or overwrite the subsize image
 $subsize_subpath = generate_webp($original_subsize_path, $quality);
 $metadata['sizes_webp'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/webp',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_avif_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_avif'] = $quality;
 $metadata['sizes_avif'] = [];
 $metadata['file_avif'] = generate_avif(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['avif_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_avif']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 //create or overwrite the subsize image
 $subsize_subpath = generate_avif($original_subsize_path, $quality);
 $metadata['sizes_avif'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/avif',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};

utils.php

<?php
namespace WebAvifConverter\Utils;
/**
 * Helper function for deleting files.
 */
function safe_unlink($path)
{
 if (file_exists($path)) {
 unlink($path);
 }
}
function update_progress_bar($percent) {
 $percent = strval($percent);
 echo "<script>
 var progressBar = document.getElementById('progress-bar');
 progressBar.style.width = '$percent%';
 progressBar.innerHTML = '$percent%';
 </script>";
 ob_flush();
 flush();
}
function get_php_version_info()
{
 if(version_compare(phpversion(), PHP_REQUIRED_VERSION, '>=')){
 return 'PHP Version is: <span class="php-version-good">' . phpversion() . '</span><b> version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 } else {
 return 'PHP Version: <span class="php-version-bad">' . phpversion() . '</span> is too low <.>version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 }
}
<?php
/**
 * The plugin bootstrap file
 *
 * This file is read by WordPress to generate the plugin information in the plugin
 * admin area. This file also includes all of the dependencies used by the plugin,
 * registers the activation and deactivation functions, and defines a function
 * that starts the plugin.
 *
 * @link https://rekurencja.com/
 * @since 1.0.0
 * @package Web_Avif_Converter
 *
 * @wordpress-plugin
 * Plugin Name: WebP & Avif Converter
 * Plugin URI: https://images.rekurencja.com
 * Description: Fast and simple plugin to automatically convert and serve WebP & AVIF images.
 * Version: 1.0.0
 * Author: Rekurencja
 * Author URI: https://rekurencja.com/
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain: web-avif-converter
 * Domain Path: /languages
 */
// If this file is called directly, abort.
if (!defined('WPINC')) {
 die;
}
define('PHP_REQUIRED_VERSION', '8.1.0');
define('PHP_VERSION_OK', version_compare(phpversion(), PHP_REQUIRED_VERSION, '>='));
define('DEFAULT_QUALITY', 82);
require plugin_dir_path(__FILE__) . 'public/src/utils/utils.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/activation_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/attachment_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/utils/generator-utils.php';
// exceptions
require plugin_dir_path(__FILE__) . 'public/src/exceptions/exceptions.php';
// Include admin.php for admin page functionality
if (is_admin()) {
 require plugin_dir_path(__FILE__) . 'public/src/admin.php';
}
register_activation_hook(__FILE__, 'WebAvifConverter\Hooks\activate_web_avif_converter');
register_deactivation_hook(__FILE__, 'WebAvifConverter\Hooks\deactivate_web_avif_converter');
add_filter('attachment_fields_to_edit', 'add_image_quality_field', 10, 2);
add_filter('manage_media_columns', 'add_image_quality_column');
add_action('manage_media_custom_column', 'display_image_quality_column', 10, 2);
add_filter('jpeg_quality', 'get_jpeg_quality');
function get_jpeg_quality($quality)
{
 return get_option('wac_quality_jpeg', 82);
}
use WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
function add_image_quality_column($columns)
{
 $columns['quality_webp'] = 'WebP Quality';
 $columns['quality_avif'] = 'Avif Quality';
 $columns['quality_jpeg'] = 'Jpeg Quality';
 return $columns;
}
function add_image_quality_field($form_fields, $post)
{
 // wp_die( print_r( $form_fields ));
 $form_fields['quality_webp'] = generate_quality_field($post->ID, 'quality_webp', 'Quality of WEBP');
 $form_fields['quality_avif'] = generate_quality_field($post->ID, 'quality_avif', 'Quality of AVIF');
 $form_fields['quality_jpeg'] = generate_quality_field($post->ID, 'quality_jpeg', 'Quality of JPEG');
 return $form_fields;
}
function determine_image_extension($image_url)
{
 $extension = pathinfo($image_url, PATHINFO_EXTENSION);
 return strtolower($extension);
}
function generate_quality_field($post_id, $field_name, $field_label)
{
 // get post metadata
 $metadata = wp_get_attachment_metadata($post_id);
 // echo $post_id;
 // wp_die(print_r($metadata));
 if (isset(wp_get_attachment_metadata($post_id)[$field_name])) {
 $field_value = wp_get_attachment_metadata($post_id)[$field_name];
 $placeholder_value = $field_value;
 } else {
 $field_value = '';
 $placeholder_value = 'Quality is not set';
 }
 $input_html = "<input type='number' min='0' max='100' step='1' ";
 $input_html .= "name='attachments[$post_id][$field_name]' ";
 $input_html .= "value='" . esc_attr($field_value ? $field_value : '') . "' ";
 $input_html .= "placeholder='" . esc_attr($placeholder_value) . "'/>";
 $field = array(
 'label' => $field_label,
 'input' => 'html',
 'helps' => 'Enter a value between 1 and 100 for image quality (100 = best quality, 1 = worst quality)',
 'html' => $input_html,
 );
 return $field;
}
function display_image_quality_column($column_name, $attachment_id)
{
 $allowed_columns = ['quality_avif', 'quality_webp', 'quality_jpeg'];
 if (in_array($column_name, $allowed_columns)) {
 $attachment_metadata = wp_get_attachment_metadata($attachment_id);
 if (isset($attachment_metadata[$column_name])) {
 echo $attachment_metadata[$column_name];
 } else {
 echo 'N/A';
 }
 }
}
add_action('admin_menu', 'webp_avif_bulk_convert_menu');
function webp_avif_bulk_convert_menu()
{
 add_submenu_page(
 'options-general.php',
 'WebP & Avif Converter',
 'WebP & Avif Converter',
 'manage_options',
 'webp_avif_bulk_convert',
 'webp_avif_bulk_convert_page'
 );
}
function get_images_size_info()
{
 // loop through all images
 $images = get_posts(
 array(
 'post_type' => 'attachment',
 'post_mime_type' => 'image',
 'numberposts' => -1,
 )
 );
 $images_size_info = [
 "total_original_size" => 0,
 "total_avif_size" => 0,
 "total_webp_size" => 0,
 ];
 echo "<div class='summary-wrapper'>";
 foreach ($images as $image) {
 try {
 // Determine the extension
 $extension = determine_image_extension($image->guid);
 // Handle unsupported extensions
 if ($extension === 'svg' || $extension === 'gif') {
 throw new FilesizeUnavailableException($extension, 'Unsupported extension: ' . $extension);
 }
 $metadata = wp_get_attachment_metadata($image->ID);
 $cur_image_size_info = [
 "original_size" => isset($metadata['filesize']) ? $metadata['filesize'] : 0,
 "avif_size" => 0,
 "webp_size" => 0,
 ];
 if (isset($metadata['sizes'])) {
 foreach ($metadata['sizes'] as $size_name => $size) {
 $cur_image_size_info["original_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_avif'])) {
 foreach ($metadata['sizes_avif'] as $size_name => $size) {
 $cur_image_size_info["avif_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_webp'])) {
 foreach ($metadata['sizes_webp'] as $size_name => $size) {
 $cur_image_size_info["webp_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (!isset($metadata['sizes'])) {
 throw new FilesizeUnavailableException('Unknown', 'Filesize information not available for this file.');
 }
 $images_size_info['total_original_size'] += $cur_image_size_info['original_size'];
 $images_size_info['total_avif_size'] += $cur_image_size_info['avif_size'];
 $images_size_info['total_webp_size'] += $cur_image_size_info['webp_size'];
 echo "<div class='summary-item'>";
 echo "<img src='" . $image->guid . "' alt='Image ID: " . $image->ID . "' width='150px'>";
 echo "<h4>Image ID: " . $image->ID . "</h4>";
 echo "<p>Image Title: <b>" . $image->post_title . "</b></p>";
 echo "<p>Original size: " . size_format($cur_image_size_info['original_size']) . " </p>";
 echo "<p>Avif size: " . size_format($cur_image_size_info['avif_size']) . "</p>";
 echo "<p>Webp size: " . size_format($cur_image_size_info['webp_size']) . "</p>";
 echo "</div>";
 } catch (FilesizeUnavailableException $e) {
 echo "Filesize information not available for image ID " . $image->ID . ". " . $e->getMessage();
 } catch (Exception $e) {
 echo "An error occurred: " . $e->getMessage();
 }
 }
 
 echo "</div>";
 echo "<div class='total-summary-item'>";
 echo "<h4>Total Summary:</h4>";
 echo "<p>Total Original Image Size: " . size_format($images_size_info['total_original_size']) . "</p>";
 echo "<p>Total AVIF Image Size: " . size_format($images_size_info['total_avif_size']) . "</p>";
 echo "<p>Total WebP Image Size: " . size_format($images_size_info['total_webp_size']) . "</p>";
 echo "</div>";
 return $images_size_info;
}
function webp_avif_bulk_convert_page()
{
 if (isset($_POST['submit'])) {
 $quality_webp = isset($_POST['quality_webp']) ? intval($_POST['quality_webp']) : DEFAULT_QUALITY;
 $quality_avif = isset($_POST['quality_avif']) ? intval($_POST['quality_avif']) : DEFAULT_QUALITY;
 $quality_jpeg = isset($_POST['quality_jpeg']) ? intval($_POST['quality_jpeg']) : DEFAULT_QUALITY;
 if ($_POST['submit'] === 'Set') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 update_option('wac_quality_webp', $quality_webp);
 update_option('wac_quality_avif', $quality_avif);
 update_option('wac_quality_jpeg', $quality_jpeg);
 if (isset($_POST['regenerate']) && $_POST['regenerate'] === 'on') {
 echo '<span class="closebtn icon" onclick="this.parentElement.style.display=\'none\';"></span>';
 echo '<div class="progress-bar" id="progress-bar" style="width: 0%">0%;
 </div>';
 Hooks\update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg);
 echo '<p class="notification notification-good">
 All images have been converted to WebP and Avif formats.
 </p>';
 }
 } else if ($_POST['submit'] === 'Delete') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 Hooks\delete_all_attachments_avif_and_webp();
 echo '<p class="notification notification-bad">
 All WebP and Avif images have been deleted.
 </p>';
 }
 echo '</div>';
 echo '</div>';
 }
 ?>
<div class="image-conversion-wrapper">
 <h1 class="conversion-heading">WebP & Avif Converter </h1>
 <form method="post">
 <?php $isPhpVersionOk = true; ?> <!-- Define PHP_VERSION_OK -->
 <fieldset <?php echo $isPhpVersionOk ? '' : 'disabled' ?>>
 <p class="conversion-description">Tool for WebP and Avif format conversion of all images in the
 uploads/media library directory. <br>
 <b>Choose quality</b> - choose the quality of the converted images (the lower the quality, the smaller
 the size) <br>
 <b>Delete function</b> - deletes all WebP and Avif images from the uploads/media library directory.
 <br>
 <b>Convert function</b> - converts all images in the uploads/media library directory to WebP and Avif
 formats. <br>
 <b>Note: </b> This tool will not convert images that are not in the uploads/media library directory.<br>
 <?php echo Utils\get_php_version_info(); ?>
 </p>
 <div class="conversion-options">
 <label class="option-label">Quality of WEBP: (0 - 100%)</label>
 <input type="number" name="quality_webp" value="<?php echo get_option('wac_quality_webp', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of AVIF: (0 - 100%)</label>
 <input type="number" name="quality_avif" value="<?php echo get_option('wac_quality_avif', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of JPEG: (0 - 100%)</label>
 <input type="number" name="quality_jpeg" value="<?php echo get_option('wac_quality_jpeg', DEFAULT_QUALITY); ?>" min="0" max="100">
 <input type="checkbox" name="regenerate" id="regenerate" checked>
 <label for="regenerate" class="option-label">
 Update qualities of existing images
 </label>
 
 <div class="toggle-summary_w">
 <button id="toggle-summary">Show / Hide Podsumowanie</button>
 </div>
 <div class="conversion-summary-toggle">
 <?php
 // You need to define the get_images_size_info function or include the file that contains it.
 get_images_size_info();
 ?>
 </div>
 </div>
 
 <div class="conversion-buttons">
 <input type="submit" name="submit" value="Set" class="convert-button">
 <input type="submit" name="submit" value="Delete" class="delete-button">
 </div>
 </fieldset>
 </form>
</div>
<?php
}
/**
 * Runs the main functionality of the plugin.
 */
function run_web_avif_converter()
{
 // The 'Web_Avif_Converter' class code is included in the 'includes/class-web-avif-converter.php' file.
 require plugin_dir_path(__FILE__) . 'includes/class-web-avif-converter.php';
 // echo print_r
 $plugin = new Web_Avif_Converter();
 $plugin->run();
}
run_web_avif_converter();

<?php
namespace WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
use WebAvifConverter\GeneratorUtils;
// function p($a, $die = 0){
 // echo '<pre>';
 // echo print_r($a);
 // echo '</pre>';
 // if ($die) { wp_die(); }
// }
apply_filters('jepg_quality', get_option('wac_quality_jpeg', DEFAULT_QUALITY));
add_filter('wp_generate_attachment_metadata', 'WebAvifConverter\Hooks\convert_images_on_generate_attachment_metadata', 10, 2);
function convert_images_on_generate_attachment_metadata($metadata, $attachment_id)
{
 if (!isset($metadata['file'])) { return $metadata; }
 $extension = pathinfo($metadata['file'], PATHINFO_EXTENSION);
 if (!in_array($extension, ['jpg', 'jpeg', 'png'])) { return $metadata; }
 
 $metadata['quality_jpeg'] = get_option('wac_quality_jpeg', DEFAULT_QUALITY);
 wp_update_attachment_metadata($attachment_id, $metadata);
 // Generating JPEGs with adjusted quality is handled by jepg_quality filter
 GeneratorUtils\generate_webp_sizes($attachment_id, get_option('wac_quality_webp', DEFAULT_QUALITY));
 GeneratorUtils\generate_avif_sizes($attachment_id, get_option('wac_quality_avif', DEFAULT_QUALITY));
 return wp_get_attachment_metadata($attachment_id);
}
add_action('edit_attachment', 'WebAvifConverter\Hooks\save_image_quality_metadata');
function save_image_quality_metadata($attachment_id)
{ 
 $metadata = wp_get_attachment_metadata($attachment_id);
 $filed_names = ['quality_jpeg', 'quality_avif', 'quality_webp' ];
 foreach ($filed_names as $filed_name) {
 if (empty($_REQUEST['attachments'][$attachment_id][$filed_name])) { continue; }
 $quality = intval($_REQUEST['attachments'][$attachment_id][$filed_name]);
 if ($quality < 1 || $quality > 100 || isset($metadata[$filed_name]) && $quality === $metadata[$filed_name]) { continue; }
 if ($filed_name === 'quality_jpeg') { GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_webp') { GeneratorUtils\generate_webp_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_avif') { GeneratorUtils\generate_avif_sizes($attachment_id, $quality); }
 } 
}
function update_attachment_quality($attachment_id, $quality_webp = DEFAULT_QUALITY, $quality_avif = DEFAULT_QUALITY, $quality_jpeg = DEFAULT_QUALITY)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata) || !isset($metadata['file']) || !isset($metadata['sizes'])) {
 return; // No metadata found for this attachment.
 }
 if(!isset($metadata['quality_jpeg']) || intval($metadata['quality_jpeg']) !== $quality_jpeg){
 
 GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality_jpeg);
 }
 if(!isset($metadata['quality_webp']) || intval($metadata['quality_webp']) !== $quality_webp){
 
 
 GeneratorUtils\generate_webp_sizes($attachment_id, $quality_webp);
 }
 
 if(!isset($metadata['quality_avif']) || intval($metadata['quality_avif']) !== $quality_avif){
 GeneratorUtils\generate_avif_sizes($attachment_id, $quality_avif);
 }
}
function update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg)
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_status' => null,
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 
 foreach ($attachments as $attachment) {
 $progress++;
 $percent = intval($progress / $total_attachments * 100);
 Utils\update_progress_bar($percent);
 update_attachment_quality($attachment->ID, $quality_webp, $quality_avif, $quality_jpeg);
 }
}
add_filter('delete_attachment', 'WebAvifConverter\Hooks\delete_attachment_files');
function delete_attachment_files($attachment_id)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 $upload_dir = wp_upload_dir()['basedir'];
 if (array_key_exists('file_webp', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_webp']);
 unset($metadata['file_webp']);
 }
 if (array_key_exists('file_avif', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_avif']);
 unset($metadata['file_avif']);
 }
 $attachment_subdir = dirname($metadata['file']);
 $attachment_files_dir = $upload_dir . '/' . $attachment_subdir . '/';
 if (array_key_exists('sizes_avif', $metadata)) {
 foreach ($metadata['sizes_avif'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_avif']);
 }
 
 if (array_key_exists('quality_webp', $metadata)){
 unset($metadata['quality_webp']);
 }
 
 if (array_key_exists('quality_avif', $metadata)){
 unset($metadata['quality_avif']);
 }
 if (array_key_exists('sizes_webp', $metadata)) {
 foreach ($metadata['sizes_webp'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_webp']);
 }wp_update_attachment_metadata($attachment_id, $metadata);
}
function delete_all_attachments_avif_and_webp()
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_mime_type' => 'image',
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 foreach ($attachments as $attachment) {
 delete_attachment_files($attachment->ID); 
 $progress++;
 $percent = intval($progress / $total_attachments * 100) . "%";
 Utils\update_progress_bar($percent);
 }
}
<?php
namespace WebAvifConverter\GeneratorUtils;
/**
 * Convert image to WebP format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted WebP image or void if unable to create an image resource.
 */
 function p($a, $die = 0){
 echo '<pre>';
 echo print_r($a);
 echo '</pre>';
 if ($die) { wp_die(); }
}
function generate_jpeg(string $path, int $quality = 80){
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagejpeg($image, $output_path . '/' . $filename , $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename;
}
function generate_webp(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagewebp($image, $output_path . '/' . $filename . '.webp', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.webp';
}
/**
 * Convert image to AVIF format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted AVIF image or void if unable to create an image resource.
 */
function generate_avif(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imageavif($image, $output_path . '/' . $filename . '.avif', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.avif';
}
function generate_jpeg_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_jpeg'] = $quality;
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 // p($metadata['sizes'], 1);
 foreach($metadata['sizes'] as $size_name => $size){
 $subsize_path = $image_subdir_path . '/' . $size['file'];
 $image = wp_get_image_editor($subsize_path);
 $image->set_quality( $quality );
 $saved = $image->save($subsize_path);
 $metadata['sizes'][$size_name]['filesize'] = filesize($subsize_path);
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_webp_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_webp'] = $quality;
 $metadata['sizes_webp'] = [];
 $metadata['file_webp'] = generate_webp(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['webp_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_webp']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 
 //create or overwrite the subsize image
 $subsize_subpath = generate_webp($original_subsize_path, $quality);
 $metadata['sizes_webp'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/webp',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_avif_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_avif'] = $quality;
 $metadata['sizes_avif'] = [];
 $metadata['file_avif'] = generate_avif(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['avif_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_avif']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 //create or overwrite the subsize image
 $subsize_subpath = generate_avif($original_subsize_path, $quality);
 $metadata['sizes_avif'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/avif',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
<?php
namespace WebAvifConverter\Utils;
/**
 * Helper function for deleting files.
 */
function safe_unlink($path)
{
 if (file_exists($path)) {
 unlink($path);
 }
}
function update_progress_bar($percent) {
 $percent = strval($percent);
 echo "<script>
 var progressBar = document.getElementById('progress-bar');
 progressBar.style.width = '$percent%';
 progressBar.innerHTML = '$percent%';
 </script>";
 ob_flush();
 flush();
}
function get_php_version_info()
{
 if(version_compare(phpversion(), PHP_REQUIRED_VERSION, '>=')){
 return 'PHP Version is: <span class="php-version-good">' . phpversion() . '</span><b> version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 } else {
 return 'PHP Version: <span class="php-version-bad">' . phpversion() . '</span> is too low <.>version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 }
}

class-web-avif-converter.php

<?php
/**
 * The plugin bootstrap file
 *
 * This file is read by WordPress to generate the plugin information in the plugin
 * admin area. This file also includes all of the dependencies used by the plugin,
 * registers the activation and deactivation functions, and defines a function
 * that starts the plugin.
 *
 * @link https://rekurencja.com/
 * @since 1.0.0
 * @package Web_Avif_Converter
 *
 * @wordpress-plugin
 * Plugin Name: WebP & Avif Converter
 * Plugin URI: https://images.rekurencja.com
 * Description: Fast and simple plugin to automatically convert and serve WebP & AVIF images.
 * Version: 1.0.0
 * Author: Rekurencja
 * Author URI: https://rekurencja.com/
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain: web-avif-converter
 * Domain Path: /languages
 */
// If this file is called directly, abort.
if (!defined('WPINC')) {
 die;
}
define('PHP_REQUIRED_VERSION', '8.1.0');
define('PHP_VERSION_OK', version_compare(phpversion(), PHP_REQUIRED_VERSION, '>='));
define('DEFAULT_QUALITY', 82);
require plugin_dir_path(__FILE__) . 'public/src/utils/utils.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/activation_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/attachment_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/utils/generator-utils.php';
// exceptions
require plugin_dir_path(__FILE__) . 'public/src/exceptions/exceptions.php';
// Include admin.php for admin page functionality
if (is_admin()) {
 require plugin_dir_path(__FILE__) . 'public/src/admin.php';
}
register_activation_hook(__FILE__, 'WebAvifConverter\Hooks\activate_web_avif_converter');
register_deactivation_hook(__FILE__, 'WebAvifConverter\Hooks\deactivate_web_avif_converter');
add_filter('attachment_fields_to_edit', 'add_image_quality_field', 10, 2);
add_filter('manage_media_columns', 'add_image_quality_column');
add_action('manage_media_custom_column', 'display_image_quality_column', 10, 2);
add_filter('jpeg_quality', 'get_jpeg_quality');
function get_jpeg_quality($quality)
{
 return get_option('wac_quality_jpeg', 82);
}
use WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
function add_image_quality_column($columns)
{
 $columns['quality_webp'] = 'WebP Quality';
 $columns['quality_avif'] = 'Avif Quality';
 $columns['quality_jpeg'] = 'Jpeg Quality';
 return $columns;
}
function add_image_quality_field($form_fields, $post)
{
 // wp_die( print_r( $form_fields ));
 $form_fields['quality_webp'] = generate_quality_field($post->ID, 'quality_webp', 'Quality of WEBP');
 $form_fields['quality_avif'] = generate_quality_field($post->ID, 'quality_avif', 'Quality of AVIF');
 $form_fields['quality_jpeg'] = generate_quality_field($post->ID, 'quality_jpeg', 'Quality of JPEG');
 return $form_fields;
}
function determine_image_extension($image_url)
{
 $extension = pathinfo($image_url, PATHINFO_EXTENSION);
 return strtolower($extension);
}
function generate_quality_field($post_id, $field_name, $field_label)
{
 // get post metadata
 $metadata = wp_get_attachment_metadata($post_id);
 // echo $post_id;
 // wp_die(print_r($metadata));
 if (isset(wp_get_attachment_metadata($post_id)[$field_name])) {
 $field_value = wp_get_attachment_metadata($post_id)[$field_name];
 $placeholder_value = $field_value;
 } else {
 $field_value = '';
 $placeholder_value = 'Quality is not set';
 }
 $input_html = "<input type='number' min='0' max='100' step='1' ";
 $input_html .= "name='attachments[$post_id][$field_name]' ";
 $input_html .= "value='" . esc_attr($field_value ? $field_value : '') . "' ";
 $input_html .= "placeholder='" . esc_attr($placeholder_value) . "'/>";
 $field = array(
 'label' => $field_label,
 'input' => 'html',
 'helps' => 'Enter a value between 1 and 100 for image quality (100 = best quality, 1 = worst quality)',
 'html' => $input_html,
 );
 return $field;
}
function display_image_quality_column($column_name, $attachment_id)
{
 $allowed_columns = ['quality_avif', 'quality_webp', 'quality_jpeg'];
 if (in_array($column_name, $allowed_columns)) {
 $attachment_metadata = wp_get_attachment_metadata($attachment_id);
 if (isset($attachment_metadata[$column_name])) {
 echo $attachment_metadata[$column_name];
 } else {
 echo 'N/A';
 }
 }
}
add_action('admin_menu', 'webp_avif_bulk_convert_menu');
function webp_avif_bulk_convert_menu()
{
 add_submenu_page(
 'options-general.php',
 'WebP & Avif Converter',
 'WebP & Avif Converter',
 'manage_options',
 'webp_avif_bulk_convert',
 'webp_avif_bulk_convert_page'
 );
}
function get_images_size_info()
{
 // loop through all images
 $images = get_posts(
 array(
 'post_type' => 'attachment',
 'post_mime_type' => 'image',
 'numberposts' => -1,
 )
 );
 $images_size_info = [
 "total_original_size" => 0,
 "total_avif_size" => 0,
 "total_webp_size" => 0,
 ];
 echo "<div class='summary-wrapper'>";
 foreach ($images as $image) {
 try {
 // Determine the extension
 $extension = determine_image_extension($image->guid);
 // Handle unsupported extensions
 if ($extension === 'svg' || $extension === 'gif') {
 throw new FilesizeUnavailableException($extension, 'Unsupported extension: ' . $extension);
 }
 $metadata = wp_get_attachment_metadata($image->ID);
 $cur_image_size_info = [
 "original_size" => isset($metadata['filesize']) ? $metadata['filesize'] : 0,
 "avif_size" => 0,
 "webp_size" => 0,
 ];
 if (isset($metadata['sizes'])) {
 foreach ($metadata['sizes'] as $size_name => $size) {
 $cur_image_size_info["original_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_avif'])) {
 foreach ($metadata['sizes_avif'] as $size_name => $size) {
 $cur_image_size_info["avif_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_webp'])) {
 foreach ($metadata['sizes_webp'] as $size_name => $size) {
 $cur_image_size_info["webp_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (!isset($metadata['sizes'])) {
 throw new FilesizeUnavailableException('Unknown', 'Filesize information not available for this file.');
 }
 $images_size_info['total_original_size'] += $cur_image_size_info['original_size'];
 $images_size_info['total_avif_size'] += $cur_image_size_info['avif_size'];
 $images_size_info['total_webp_size'] += $cur_image_size_info['webp_size'];
 echo "<div class='summary-item'>";
 echo "<img src='" . $image->guid . "' alt='Image ID: " . $image->ID . "' width='150px'>";
 echo "<h4>Image ID: " . $image->ID . "</h4>";
 echo "<p>Image Title: <b>" . $image->post_title . "</b></p>";
 echo "<p>Original size: " . size_format($cur_image_size_info['original_size']) . " </p>";
 echo "<p>Avif size: " . size_format($cur_image_size_info['avif_size']) . "</p>";
 echo "<p>Webp size: " . size_format($cur_image_size_info['webp_size']) . "</p>";
 echo "</div>";
 } catch (FilesizeUnavailableException $e) {
 echo "Filesize information not available for image ID " . $image->ID . ". " . $e->getMessage();
 } catch (Exception $e) {
 echo "An error occurred: " . $e->getMessage();
 }
 }
 
 echo "</div>";
 echo "<div class='total-summary-item'>";
 echo "<h4>Total Summary:</h4>";
 echo "<p>Total Original Image Size: " . size_format($images_size_info['total_original_size']) . "</p>";
 echo "<p>Total AVIF Image Size: " . size_format($images_size_info['total_avif_size']) . "</p>";
 echo "<p>Total WebP Image Size: " . size_format($images_size_info['total_webp_size']) . "</p>";
 echo "</div>";
 return $images_size_info;
}
function webp_avif_bulk_convert_page()
{
 if (isset($_POST['submit'])) {
 $quality_webp = isset($_POST['quality_webp']) ? intval($_POST['quality_webp']) : DEFAULT_QUALITY;
 $quality_avif = isset($_POST['quality_avif']) ? intval($_POST['quality_avif']) : DEFAULT_QUALITY;
 $quality_jpeg = isset($_POST['quality_jpeg']) ? intval($_POST['quality_jpeg']) : DEFAULT_QUALITY;
 if ($_POST['submit'] === 'Set') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 update_option('wac_quality_webp', $quality_webp);
 update_option('wac_quality_avif', $quality_avif);
 update_option('wac_quality_jpeg', $quality_jpeg);
 if (isset($_POST['regenerate']) && $_POST['regenerate'] === 'on') {
 echo '<span class="closebtn icon" onclick="this.parentElement.style.display=\'none\';"></span>';
 echo '<div class="progress-bar" id="progress-bar" style="width: 0%">0%;
 </div>';
 Hooks\update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg);
 echo '<p class="notification notification-good">
 All images have been converted to WebP and Avif formats.
 </p>';
 }
 } else if ($_POST['submit'] === 'Delete') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 Hooks\delete_all_attachments_avif_and_webp();
 echo '<p class="notification notification-bad">
 All WebP and Avif images have been deleted.
 </p>';
 }
 echo '</div>';
 echo '</div>';
 }
 ?>
<div class="image-conversion-wrapper">
 <h1 class="conversion-heading">WebP & Avif Converter </h1>
 <form method="post">
 <?php $isPhpVersionOk = true; ?> <!-- Define PHP_VERSION_OK -->
 <fieldset <?php echo $isPhpVersionOk ? '' : 'disabled' ?>>
 <p class="conversion-description">Tool for WebP and Avif format conversion of all images in the
 uploads/media library directory. <br>
 <b>Choose quality</b> - choose the quality of the converted images (the lower the quality, the smaller
 the size) <br>
 <b>Delete function</b> - deletes all WebP and Avif images from the uploads/media library directory.
 <br>
 <b>Convert function</b> - converts all images in the uploads/media library directory to WebP and Avif
 formats. <br>
 <b>Note: </b> This tool will not convert images that are not in the uploads/media library directory.<br>
 <?php echo Utils\get_php_version_info(); ?>
 </p>
 <div class="conversion-options">
 <label class="option-label">Quality of WEBP: (0 - 100%)</label>
 <input type="number" name="quality_webp" value="<?php echo get_option('wac_quality_webp', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of AVIF: (0 - 100%)</label>
 <input type="number" name="quality_avif" value="<?php echo get_option('wac_quality_avif', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of JPEG: (0 - 100%)</label>
 <input type="number" name="quality_jpeg" value="<?php echo get_option('wac_quality_jpeg', DEFAULT_QUALITY); ?>" min="0" max="100">
 <input type="checkbox" name="regenerate" id="regenerate" checked>
 <label for="regenerate" class="option-label">
 Update qualities of existing images
 </label>
 
 <div class="toggle-summary_w">
 <button id="toggle-summary">Show / Hide Podsumowanie</button>
 </div>
 <div class="conversion-summary-toggle">
 <?php
 // You need to define the get_images_size_info function or include the file that contains it.
 get_images_size_info();
 ?>
 </div>
 </div>
 
 <div class="conversion-buttons">
 <input type="submit" name="submit" value="Set" class="convert-button">
 <input type="submit" name="submit" value="Delete" class="delete-button">
 </div>
 </fieldset>
 </form>
</div>
<?php
}
/**
 * Runs the main functionality of the plugin.
 */
function run_web_avif_converter()
{
 // The 'Web_Avif_Converter' class code is included in the 'includes/class-web-avif-converter.php' file.
 require plugin_dir_path(__FILE__) . 'includes/class-web-avif-converter.php';
 // echo print_r
 $plugin = new Web_Avif_Converter();
 $plugin->run();
}
run_web_avif_converter();

attachment_hooks.php

<?php
namespace WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
use WebAvifConverter\GeneratorUtils;
// function p($a, $die = 0){
 // echo '<pre>';
 // echo print_r($a);
 // echo '</pre>';
 // if ($die) { wp_die(); }
// }
apply_filters('jepg_quality', get_option('wac_quality_jpeg', DEFAULT_QUALITY));
add_filter('wp_generate_attachment_metadata', 'WebAvifConverter\Hooks\convert_images_on_generate_attachment_metadata', 10, 2);
function convert_images_on_generate_attachment_metadata($metadata, $attachment_id)
{
 if (!isset($metadata['file'])) { return $metadata; }
 $extension = pathinfo($metadata['file'], PATHINFO_EXTENSION);
 if (!in_array($extension, ['jpg', 'jpeg', 'png'])) { return $metadata; }
 
 $metadata['quality_jpeg'] = get_option('wac_quality_jpeg', DEFAULT_QUALITY);
 wp_update_attachment_metadata($attachment_id, $metadata);
 // Generating JPEGs with adjusted quality is handled by jepg_quality filter
 GeneratorUtils\generate_webp_sizes($attachment_id, get_option('wac_quality_webp', DEFAULT_QUALITY));
 GeneratorUtils\generate_avif_sizes($attachment_id, get_option('wac_quality_avif', DEFAULT_QUALITY));
 return wp_get_attachment_metadata($attachment_id);
}
add_action('edit_attachment', 'WebAvifConverter\Hooks\save_image_quality_metadata');
function save_image_quality_metadata($attachment_id)
{ 
 $metadata = wp_get_attachment_metadata($attachment_id);
 $filed_names = ['quality_jpeg', 'quality_avif', 'quality_webp' ];
 foreach ($filed_names as $filed_name) {
 if (empty($_REQUEST['attachments'][$attachment_id][$filed_name])) { continue; }
 $quality = intval($_REQUEST['attachments'][$attachment_id][$filed_name]);
 if ($quality < 1 || $quality > 100 || isset($metadata[$filed_name]) && $quality === $metadata[$filed_name]) { continue; }
 if ($filed_name === 'quality_jpeg') { GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_webp') { GeneratorUtils\generate_webp_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_avif') { GeneratorUtils\generate_avif_sizes($attachment_id, $quality); }
 } 
}
function update_attachment_quality($attachment_id, $quality_webp = DEFAULT_QUALITY, $quality_avif = DEFAULT_QUALITY, $quality_jpeg = DEFAULT_QUALITY)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata) || !isset($metadata['file']) || !isset($metadata['sizes'])) {
 return; // No metadata found for this attachment.
 }
 if(!isset($metadata['quality_jpeg']) || intval($metadata['quality_jpeg']) !== $quality_jpeg){
 
 GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality_jpeg);
 }
 if(!isset($metadata['quality_webp']) || intval($metadata['quality_webp']) !== $quality_webp){
 
 
 GeneratorUtils\generate_webp_sizes($attachment_id, $quality_webp);
 }
 
 if(!isset($metadata['quality_avif']) || intval($metadata['quality_avif']) !== $quality_avif){
 GeneratorUtils\generate_avif_sizes($attachment_id, $quality_avif);
 }
}
function update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg)
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_status' => null,
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 
 foreach ($attachments as $attachment) {
 $progress++;
 $percent = intval($progress / $total_attachments * 100);
 Utils\update_progress_bar($percent);
 update_attachment_quality($attachment->ID, $quality_webp, $quality_avif, $quality_jpeg);
 }
}
add_filter('delete_attachment', 'WebAvifConverter\Hooks\delete_attachment_files');
function delete_attachment_files($attachment_id)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 $upload_dir = wp_upload_dir()['basedir'];
 if (array_key_exists('file_webp', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_webp']);
 unset($metadata['file_webp']);
 }
 if (array_key_exists('file_avif', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_avif']);
 unset($metadata['file_avif']);
 }
 $attachment_subdir = dirname($metadata['file']);
 $attachment_files_dir = $upload_dir . '/' . $attachment_subdir . '/';
 if (array_key_exists('sizes_avif', $metadata)) {
 foreach ($metadata['sizes_avif'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_avif']);
 }
 
 if (array_key_exists('quality_webp', $metadata)){
 unset($metadata['quality_webp']);
 }
 
 if (array_key_exists('quality_avif', $metadata)){
 unset($metadata['quality_avif']);
 }
 if (array_key_exists('sizes_webp', $metadata)) {
 foreach ($metadata['sizes_webp'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_webp']);
 }wp_update_attachment_metadata($attachment_id, $metadata);
}
function delete_all_attachments_avif_and_webp()
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_mime_type' => 'image',
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 foreach ($attachments as $attachment) {
 delete_attachment_files($attachment->ID); 
 $progress++;
 $percent = intval($progress / $total_attachments * 100) . "%";
 Utils\update_progress_bar($percent);
 }
}

generator-utils.php

<?php
namespace WebAvifConverter\GeneratorUtils;
/**
 * Convert image to WebP format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted WebP image or void if unable to create an image resource.
 */
 function p($a, $die = 0){
 echo '<pre>';
 echo print_r($a);
 echo '</pre>';
 if ($die) { wp_die(); }
}
function generate_jpeg(string $path, int $quality = 80){
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagejpeg($image, $output_path . '/' . $filename , $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename;
}
function generate_webp(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagewebp($image, $output_path . '/' . $filename . '.webp', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.webp';
}
/**
 * Convert image to AVIF format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted AVIF image or void if unable to create an image resource.
 */
function generate_avif(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imageavif($image, $output_path . '/' . $filename . '.avif', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.avif';
}
function generate_jpeg_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_jpeg'] = $quality;
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 // p($metadata['sizes'], 1);
 foreach($metadata['sizes'] as $size_name => $size){
 $subsize_path = $image_subdir_path . '/' . $size['file'];
 $image = wp_get_image_editor($subsize_path);
 $image->set_quality( $quality );
 $saved = $image->save($subsize_path);
 $metadata['sizes'][$size_name]['filesize'] = filesize($subsize_path);
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_webp_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_webp'] = $quality;
 $metadata['sizes_webp'] = [];
 $metadata['file_webp'] = generate_webp(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['webp_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_webp']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 
 //create or overwrite the subsize image
 $subsize_subpath = generate_webp($original_subsize_path, $quality);
 $metadata['sizes_webp'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/webp',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_avif_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_avif'] = $quality;
 $metadata['sizes_avif'] = [];
 $metadata['file_avif'] = generate_avif(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['avif_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_avif']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 //create or overwrite the subsize image
 $subsize_subpath = generate_avif($original_subsize_path, $quality);
 $metadata['sizes_avif'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/avif',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};

utils.php

<?php
namespace WebAvifConverter\Utils;
/**
 * Helper function for deleting files.
 */
function safe_unlink($path)
{
 if (file_exists($path)) {
 unlink($path);
 }
}
function update_progress_bar($percent) {
 $percent = strval($percent);
 echo "<script>
 var progressBar = document.getElementById('progress-bar');
 progressBar.style.width = '$percent%';
 progressBar.innerHTML = '$percent%';
 </script>";
 ob_flush();
 flush();
}
function get_php_version_info()
{
 if(version_compare(phpversion(), PHP_REQUIRED_VERSION, '>=')){
 return 'PHP Version is: <span class="php-version-good">' . phpversion() . '</span><b> version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 } else {
 return 'PHP Version: <span class="php-version-bad">' . phpversion() . '</span> is too low <.>version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 }
}
add tags; add new line at end so fence won't be displayed with code- see https://codereview.meta.stackexchange.com/q/9148/120114
Source Link
<?php
/**
 * The plugin bootstrap file
 *
 * This file is read by WordPress to generate the plugin information in the plugin
 * admin area. This file also includes all of the dependencies used by the plugin,
 * registers the activation and deactivation functions, and defines a function
 * that starts the plugin.
 *
 * @link https://rekurencja.com/
 * @since 1.0.0
 * @package Web_Avif_Converter
 *
 * @wordpress-plugin
 * Plugin Name: WebP & Avif Converter
 * Plugin URI: https://images.rekurencja.com
 * Description: Fast and simple plugin to automatically convert and serve WebP & AVIF images.
 * Version: 1.0.0
 * Author: Rekurencja
 * Author URI: https://rekurencja.com/
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain: web-avif-converter
 * Domain Path: /languages
 */
// If this file is called directly, abort.
if (!defined('WPINC')) {
 die;
}
define('PHP_REQUIRED_VERSION', '8.1.0');
define('PHP_VERSION_OK', version_compare(phpversion(), PHP_REQUIRED_VERSION, '>='));
define('DEFAULT_QUALITY', 82);
require plugin_dir_path(__FILE__) . 'public/src/utils/utils.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/activation_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/attachment_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/utils/generator-utils.php';
// exceptions
require plugin_dir_path(__FILE__) . 'public/src/exceptions/exceptions.php';
// Include admin.php for admin page functionality
if (is_admin()) {
 require plugin_dir_path(__FILE__) . 'public/src/admin.php';
}
register_activation_hook(__FILE__, 'WebAvifConverter\Hooks\activate_web_avif_converter');
register_deactivation_hook(__FILE__, 'WebAvifConverter\Hooks\deactivate_web_avif_converter');
add_filter('attachment_fields_to_edit', 'add_image_quality_field', 10, 2);
add_filter('manage_media_columns', 'add_image_quality_column');
add_action('manage_media_custom_column', 'display_image_quality_column', 10, 2);
add_filter('jpeg_quality', 'get_jpeg_quality');
function get_jpeg_quality($quality)
{
 return get_option('wac_quality_jpeg', 82);
}
use WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
function add_image_quality_column($columns)
{
 $columns['quality_webp'] = 'WebP Quality';
 $columns['quality_avif'] = 'Avif Quality';
 $columns['quality_jpeg'] = 'Jpeg Quality';
 return $columns;
}
function add_image_quality_field($form_fields, $post)
{
 // wp_die( print_r( $form_fields ));
 $form_fields['quality_webp'] = generate_quality_field($post->ID, 'quality_webp', 'Quality of WEBP');
 $form_fields['quality_avif'] = generate_quality_field($post->ID, 'quality_avif', 'Quality of AVIF');
 $form_fields['quality_jpeg'] = generate_quality_field($post->ID, 'quality_jpeg', 'Quality of JPEG');
 return $form_fields;
}
function determine_image_extension($image_url)
{
 $extension = pathinfo($image_url, PATHINFO_EXTENSION);
 return strtolower($extension);
}
function generate_quality_field($post_id, $field_name, $field_label)
{
 // get post metadata
 $metadata = wp_get_attachment_metadata($post_id);
 // echo $post_id;
 // wp_die(print_r($metadata));
 if (isset(wp_get_attachment_metadata($post_id)[$field_name])) {
 $field_value = wp_get_attachment_metadata($post_id)[$field_name];
 $placeholder_value = $field_value;
 } else {
 $field_value = '';
 $placeholder_value = 'Quality is not set';
 }
 $input_html = "<input type='number' min='0' max='100' step='1' ";
 $input_html .= "name='attachments[$post_id][$field_name]' ";
 $input_html .= "value='" . esc_attr($field_value ? $field_value : '') . "' ";
 $input_html .= "placeholder='" . esc_attr($placeholder_value) . "'/>";
 $field = array(
 'label' => $field_label,
 'input' => 'html',
 'helps' => 'Enter a value between 1 and 100 for image quality (100 = best quality, 1 = worst quality)',
 'html' => $input_html,
 );
 return $field;
}
function display_image_quality_column($column_name, $attachment_id)
{
 $allowed_columns = ['quality_avif', 'quality_webp', 'quality_jpeg'];
 if (in_array($column_name, $allowed_columns)) {
 $attachment_metadata = wp_get_attachment_metadata($attachment_id);
 if (isset($attachment_metadata[$column_name])) {
 echo $attachment_metadata[$column_name];
 } else {
 echo 'N/A';
 }
 }
}
add_action('admin_menu', 'webp_avif_bulk_convert_menu');
function webp_avif_bulk_convert_menu()
{
 add_submenu_page(
 'options-general.php',
 'WebP & Avif Converter',
 'WebP & Avif Converter',
 'manage_options',
 'webp_avif_bulk_convert',
 'webp_avif_bulk_convert_page'
 );
}
function get_images_size_info()
{
 // loop through all images
 $images = get_posts(
 array(
 'post_type' => 'attachment',
 'post_mime_type' => 'image',
 'numberposts' => -1,
 )
 );
 $images_size_info = [
 "total_original_size" => 0,
 "total_avif_size" => 0,
 "total_webp_size" => 0,
 ];
 echo "<div class='summary-wrapper'>";
 foreach ($images as $image) {
 try {
 // Determine the extension
 $extension = determine_image_extension($image->guid);
 // Handle unsupported extensions
 if ($extension === 'svg' || $extension === 'gif') {
 throw new FilesizeUnavailableException($extension, 'Unsupported extension: ' . $extension);
 }
 $metadata = wp_get_attachment_metadata($image->ID);
 $cur_image_size_info = [
 "original_size" => isset($metadata['filesize']) ? $metadata['filesize'] : 0,
 "avif_size" => 0,
 "webp_size" => 0,
 ];
 if (isset($metadata['sizes'])) {
 foreach ($metadata['sizes'] as $size_name => $size) {
 $cur_image_size_info["original_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_avif'])) {
 foreach ($metadata['sizes_avif'] as $size_name => $size) {
 $cur_image_size_info["avif_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_webp'])) {
 foreach ($metadata['sizes_webp'] as $size_name => $size) {
 $cur_image_size_info["webp_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (!isset($metadata['sizes'])) {
 throw new FilesizeUnavailableException('Unknown', 'Filesize information not available for this file.');
 }
 $images_size_info['total_original_size'] += $cur_image_size_info['original_size'];
 $images_size_info['total_avif_size'] += $cur_image_size_info['avif_size'];
 $images_size_info['total_webp_size'] += $cur_image_size_info['webp_size'];
 echo "<div class='summary-item'>";
 echo "<img src='" . $image->guid . "' alt='Image ID: " . $image->ID . "' width='150px'>";
 echo "<h4>Image ID: " . $image->ID . "</h4>";
 echo "<p>Image Title: <b>" . $image->post_title . "</b></p>";
 echo "<p>Original size: " . size_format($cur_image_size_info['original_size']) . " </p>";
 echo "<p>Avif size: " . size_format($cur_image_size_info['avif_size']) . "</p>";
 echo "<p>Webp size: " . size_format($cur_image_size_info['webp_size']) . "</p>";
 echo "</div>";
 } catch (FilesizeUnavailableException $e) {
 echo "Filesize information not available for image ID " . $image->ID . ". " . $e->getMessage();
 } catch (Exception $e) {
 echo "An error occurred: " . $e->getMessage();
 }
 }
 
 echo "</div>";
 echo "<div class='total-summary-item'>";
 echo "<h4>Total Summary:</h4>";
 echo "<p>Total Original Image Size: " . size_format($images_size_info['total_original_size']) . "</p>";
 echo "<p>Total AVIF Image Size: " . size_format($images_size_info['total_avif_size']) . "</p>";
 echo "<p>Total WebP Image Size: " . size_format($images_size_info['total_webp_size']) . "</p>";
 echo "</div>";
 return $images_size_info;
}
function webp_avif_bulk_convert_page()
{
 if (isset($_POST['submit'])) {
 $quality_webp = isset($_POST['quality_webp']) ? intval($_POST['quality_webp']) : DEFAULT_QUALITY;
 $quality_avif = isset($_POST['quality_avif']) ? intval($_POST['quality_avif']) : DEFAULT_QUALITY;
 $quality_jpeg = isset($_POST['quality_jpeg']) ? intval($_POST['quality_jpeg']) : DEFAULT_QUALITY;
 if ($_POST['submit'] === 'Set') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 update_option('wac_quality_webp', $quality_webp);
 update_option('wac_quality_avif', $quality_avif);
 update_option('wac_quality_jpeg', $quality_jpeg);
 if (isset($_POST['regenerate']) && $_POST['regenerate'] === 'on') {
 echo '<span class="closebtn icon" onclick="this.parentElement.style.display=\'none\';"></span>';
 echo '<div class="progress-bar" id="progress-bar" style="width: 0%">0%;
 </div>';
 Hooks\update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg);
 echo '<p class="notification notification-good">
 All images have been converted to WebP and Avif formats.
 </p>';
 }
 } else if ($_POST['submit'] === 'Delete') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 Hooks\delete_all_attachments_avif_and_webp();
 echo '<p class="notification notification-bad">
 All WebP and Avif images have been deleted.
 </p>';
 }
 echo '</div>';
 echo '</div>';
 }
 ?>
<div class="image-conversion-wrapper">
 <h1 class="conversion-heading">WebP & Avif Converter </h1>
 <form method="post">
 <?php $isPhpVersionOk = true; ?> <!-- Define PHP_VERSION_OK -->
 <fieldset <?php echo $isPhpVersionOk ? '' : 'disabled' ?>>
 <p class="conversion-description">Tool for WebP and Avif format conversion of all images in the
 uploads/media library directory. <br>
 <b>Choose quality</b> - choose the quality of the converted images (the lower the quality, the smaller
 the size) <br>
 <b>Delete function</b> - deletes all WebP and Avif images from the uploads/media library directory.
 <br>
 <b>Convert function</b> - converts all images in the uploads/media library directory to WebP and Avif
 formats. <br>
 <b>Note: </b> This tool will not convert images that are not in the uploads/media library directory.<br>
 <?php echo Utils\get_php_version_info(); ?>
 </p>
 <div class="conversion-options">
 <label class="option-label">Quality of WEBP: (0 - 100%)</label>
 <input type="number" name="quality_webp" value="<?php echo get_option('wac_quality_webp', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of AVIF: (0 - 100%)</label>
 <input type="number" name="quality_avif" value="<?php echo get_option('wac_quality_avif', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of JPEG: (0 - 100%)</label>
 <input type="number" name="quality_jpeg" value="<?php echo get_option('wac_quality_jpeg', DEFAULT_QUALITY); ?>" min="0" max="100">
 <input type="checkbox" name="regenerate" id="regenerate" checked>
 <label for="regenerate" class="option-label">
 Update qualities of existing images
 </label>
 
 <div class="toggle-summary_w">
 <button id="toggle-summary">Show / Hide Podsumowanie</button>
 </div>
 <div class="conversion-summary-toggle">
 <?php
 // You need to define the get_images_size_info function or include the file that contains it.
 get_images_size_info();
 ?>
 </div>
 </div>
 
 <div class="conversion-buttons">
 <input type="submit" name="submit" value="Set" class="convert-button">
 <input type="submit" name="submit" value="Delete" class="delete-button">
 </div>
 </fieldset>
 </form>
</div>
<?php
}
/**
 * Runs the main functionality of the plugin.
 */
function run_web_avif_converter()
{
 // The 'Web_Avif_Converter' class code is included in the 'includes/class-web-avif-converter.php' file.
 require plugin_dir_path(__FILE__) . 'includes/class-web-avif-converter.php';
 // echo print_r
 $plugin = new Web_Avif_Converter();
 $plugin->run();
}
run_web_avif_converter();
<?php
namespace WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
use WebAvifConverter\GeneratorUtils;
// function p($a, $die = 0){
 // echo '<pre>';
 // echo print_r($a);
 // echo '</pre>';
 // if ($die) { wp_die(); }
// }
apply_filters('jepg_quality', get_option('wac_quality_jpeg', DEFAULT_QUALITY));
add_filter('wp_generate_attachment_metadata', 'WebAvifConverter\Hooks\convert_images_on_generate_attachment_metadata', 10, 2);
function convert_images_on_generate_attachment_metadata($metadata, $attachment_id)
{
 if (!isset($metadata['file'])) { return $metadata; }
 $extension = pathinfo($metadata['file'], PATHINFO_EXTENSION);
 if (!in_array($extension, ['jpg', 'jpeg', 'png'])) { return $metadata; }
 
 $metadata['quality_jpeg'] = get_option('wac_quality_jpeg', DEFAULT_QUALITY);
 wp_update_attachment_metadata($attachment_id, $metadata);
 // Generating JPEGs with adjusted quality is handled by jepg_quality filter
 GeneratorUtils\generate_webp_sizes($attachment_id, get_option('wac_quality_webp', DEFAULT_QUALITY));
 GeneratorUtils\generate_avif_sizes($attachment_id, get_option('wac_quality_avif', DEFAULT_QUALITY));
 return wp_get_attachment_metadata($attachment_id);
}
add_action('edit_attachment', 'WebAvifConverter\Hooks\save_image_quality_metadata');
function save_image_quality_metadata($attachment_id)
{ 
 $metadata = wp_get_attachment_metadata($attachment_id);
 $filed_names = ['quality_jpeg', 'quality_avif', 'quality_webp' ];
 foreach ($filed_names as $filed_name) {
 if (empty($_REQUEST['attachments'][$attachment_id][$filed_name])) { continue; }
 $quality = intval($_REQUEST['attachments'][$attachment_id][$filed_name]);
 if ($quality < 1 || $quality > 100 || isset($metadata[$filed_name]) && $quality === $metadata[$filed_name]) { continue; }
 if ($filed_name === 'quality_jpeg') { GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_webp') { GeneratorUtils\generate_webp_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_avif') { GeneratorUtils\generate_avif_sizes($attachment_id, $quality); }
 } 
}
function update_attachment_quality($attachment_id, $quality_webp = DEFAULT_QUALITY, $quality_avif = DEFAULT_QUALITY, $quality_jpeg = DEFAULT_QUALITY)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata) || !isset($metadata['file']) || !isset($metadata['sizes'])) {
 return; // No metadata found for this attachment.
 }
 if(!isset($metadata['quality_jpeg']) || intval($metadata['quality_jpeg']) !== $quality_jpeg){
 
 GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality_jpeg);
 }
 if(!isset($metadata['quality_webp']) || intval($metadata['quality_webp']) !== $quality_webp){
 
 
 GeneratorUtils\generate_webp_sizes($attachment_id, $quality_webp);
 }
 
 if(!isset($metadata['quality_avif']) || intval($metadata['quality_avif']) !== $quality_avif){
 GeneratorUtils\generate_avif_sizes($attachment_id, $quality_avif);
 }
}
function update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg)
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_status' => null,
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 
 foreach ($attachments as $attachment) {
 $progress++;
 $percent = intval($progress / $total_attachments * 100);
 Utils\update_progress_bar($percent);
 update_attachment_quality($attachment->ID, $quality_webp, $quality_avif, $quality_jpeg);
 }
}
add_filter('delete_attachment', 'WebAvifConverter\Hooks\delete_attachment_files');
function delete_attachment_files($attachment_id)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 $upload_dir = wp_upload_dir()['basedir'];
 if (array_key_exists('file_webp', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_webp']);
 unset($metadata['file_webp']);
 }
 if (array_key_exists('file_avif', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_avif']);
 unset($metadata['file_avif']);
 }
 $attachment_subdir = dirname($metadata['file']);
 $attachment_files_dir = $upload_dir . '/' . $attachment_subdir . '/';
 if (array_key_exists('sizes_avif', $metadata)) {
 foreach ($metadata['sizes_avif'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_avif']);
 }
 
 if (array_key_exists('quality_webp', $metadata)){
 unset($metadata['quality_webp']);
 }
 
 if (array_key_exists('quality_avif', $metadata)){
 unset($metadata['quality_avif']);
 }
 if (array_key_exists('sizes_webp', $metadata)) {
 foreach ($metadata['sizes_webp'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_webp']);
 }wp_update_attachment_metadata($attachment_id, $metadata);
}
function delete_all_attachments_avif_and_webp()
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_mime_type' => 'image',
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 foreach ($attachments as $attachment) {
 delete_attachment_files($attachment->ID); 
 $progress++;
 $percent = intval($progress / $total_attachments * 100) . "%";
 Utils\update_progress_bar($percent);
 }
}
<?php
namespace WebAvifConverter\GeneratorUtils;
/**
 * Convert image to WebP format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted WebP image or void if unable to create an image resource.
 */
 function p($a, $die = 0){
 echo '<pre>';
 echo print_r($a);
 echo '</pre>';
 if ($die) { wp_die(); }
}
function generate_jpeg(string $path, int $quality = 80){
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagejpeg($image, $output_path . '/' . $filename , $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename;
}
function generate_webp(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagewebp($image, $output_path . '/' . $filename . '.webp', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.webp';
}
/**
 * Convert image to AVIF format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted AVIF image or void if unable to create an image resource.
 */
function generate_avif(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imageavif($image, $output_path . '/' . $filename . '.avif', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.avif';
}
function generate_jpeg_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_jpeg'] = $quality;
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 // p($metadata['sizes'], 1);
 foreach($metadata['sizes'] as $size_name => $size){
 $subsize_path = $image_subdir_path . '/' . $size['file'];
 $image = wp_get_image_editor($subsize_path);
 $image->set_quality( $quality );
 $saved = $image->save($subsize_path);
 $metadata['sizes'][$size_name]['filesize'] = filesize($subsize_path);
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_webp_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_webp'] = $quality;
 $metadata['sizes_webp'] = [];
 $metadata['file_webp'] = generate_webp(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['webp_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_webp']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 
 //create or overwrite the subsize image
 $subsize_subpath = generate_webp($original_subsize_path, $quality);
 $metadata['sizes_webp'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/webp',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_avif_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_avif'] = $quality;
 $metadata['sizes_avif'] = [];
 $metadata['file_avif'] = generate_avif(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['avif_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_avif']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 //create or overwrite the subsize image
 $subsize_subpath = generate_avif($original_subsize_path, $quality);
 $metadata['sizes_avif'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/avif',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
<?php
namespace WebAvifConverter\Utils;
/**
 * Helper function for deleting files.
 */
function safe_unlink($path)
{
 if (file_exists($path)) {
 unlink($path);
 }
}
function update_progress_bar($percent) {
 $percent = strval($percent);
 echo "<script>
 var progressBar = document.getElementById('progress-bar');
 progressBar.style.width = '$percent%';
 progressBar.innerHTML = '$percent%';
 </script>";
 ob_flush();
 flush();
}
function get_php_version_info()
{
 if(version_compare(phpversion(), PHP_REQUIRED_VERSION, '>=')){
 return 'PHP Version is: <span class="php-version-good">' . phpversion() . '</span><b> version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 } else {
 return 'PHP Version: <span class="php-version-bad">' . phpversion() . '</span> is too low <.>version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 }
}
```
<?php
/**
 * The plugin bootstrap file
 *
 * This file is read by WordPress to generate the plugin information in the plugin
 * admin area. This file also includes all of the dependencies used by the plugin,
 * registers the activation and deactivation functions, and defines a function
 * that starts the plugin.
 *
 * @link https://rekurencja.com/
 * @since 1.0.0
 * @package Web_Avif_Converter
 *
 * @wordpress-plugin
 * Plugin Name: WebP & Avif Converter
 * Plugin URI: https://images.rekurencja.com
 * Description: Fast and simple plugin to automatically convert and serve WebP & AVIF images.
 * Version: 1.0.0
 * Author: Rekurencja
 * Author URI: https://rekurencja.com/
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain: web-avif-converter
 * Domain Path: /languages
 */
// If this file is called directly, abort.
if (!defined('WPINC')) {
 die;
}
define('PHP_REQUIRED_VERSION', '8.1.0');
define('PHP_VERSION_OK', version_compare(phpversion(), PHP_REQUIRED_VERSION, '>='));
define('DEFAULT_QUALITY', 82);
require plugin_dir_path(__FILE__) . 'public/src/utils/utils.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/activation_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/attachment_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/utils/generator-utils.php';
// exceptions
require plugin_dir_path(__FILE__) . 'public/src/exceptions/exceptions.php';
// Include admin.php for admin page functionality
if (is_admin()) {
 require plugin_dir_path(__FILE__) . 'public/src/admin.php';
}
register_activation_hook(__FILE__, 'WebAvifConverter\Hooks\activate_web_avif_converter');
register_deactivation_hook(__FILE__, 'WebAvifConverter\Hooks\deactivate_web_avif_converter');
add_filter('attachment_fields_to_edit', 'add_image_quality_field', 10, 2);
add_filter('manage_media_columns', 'add_image_quality_column');
add_action('manage_media_custom_column', 'display_image_quality_column', 10, 2);
add_filter('jpeg_quality', 'get_jpeg_quality');
function get_jpeg_quality($quality)
{
 return get_option('wac_quality_jpeg', 82);
}
use WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
function add_image_quality_column($columns)
{
 $columns['quality_webp'] = 'WebP Quality';
 $columns['quality_avif'] = 'Avif Quality';
 $columns['quality_jpeg'] = 'Jpeg Quality';
 return $columns;
}
function add_image_quality_field($form_fields, $post)
{
 // wp_die( print_r( $form_fields ));
 $form_fields['quality_webp'] = generate_quality_field($post->ID, 'quality_webp', 'Quality of WEBP');
 $form_fields['quality_avif'] = generate_quality_field($post->ID, 'quality_avif', 'Quality of AVIF');
 $form_fields['quality_jpeg'] = generate_quality_field($post->ID, 'quality_jpeg', 'Quality of JPEG');
 return $form_fields;
}
function determine_image_extension($image_url)
{
 $extension = pathinfo($image_url, PATHINFO_EXTENSION);
 return strtolower($extension);
}
function generate_quality_field($post_id, $field_name, $field_label)
{
 // get post metadata
 $metadata = wp_get_attachment_metadata($post_id);
 // echo $post_id;
 // wp_die(print_r($metadata));
 if (isset(wp_get_attachment_metadata($post_id)[$field_name])) {
 $field_value = wp_get_attachment_metadata($post_id)[$field_name];
 $placeholder_value = $field_value;
 } else {
 $field_value = '';
 $placeholder_value = 'Quality is not set';
 }
 $input_html = "<input type='number' min='0' max='100' step='1' ";
 $input_html .= "name='attachments[$post_id][$field_name]' ";
 $input_html .= "value='" . esc_attr($field_value ? $field_value : '') . "' ";
 $input_html .= "placeholder='" . esc_attr($placeholder_value) . "'/>";
 $field = array(
 'label' => $field_label,
 'input' => 'html',
 'helps' => 'Enter a value between 1 and 100 for image quality (100 = best quality, 1 = worst quality)',
 'html' => $input_html,
 );
 return $field;
}
function display_image_quality_column($column_name, $attachment_id)
{
 $allowed_columns = ['quality_avif', 'quality_webp', 'quality_jpeg'];
 if (in_array($column_name, $allowed_columns)) {
 $attachment_metadata = wp_get_attachment_metadata($attachment_id);
 if (isset($attachment_metadata[$column_name])) {
 echo $attachment_metadata[$column_name];
 } else {
 echo 'N/A';
 }
 }
}
add_action('admin_menu', 'webp_avif_bulk_convert_menu');
function webp_avif_bulk_convert_menu()
{
 add_submenu_page(
 'options-general.php',
 'WebP & Avif Converter',
 'WebP & Avif Converter',
 'manage_options',
 'webp_avif_bulk_convert',
 'webp_avif_bulk_convert_page'
 );
}
function get_images_size_info()
{
 // loop through all images
 $images = get_posts(
 array(
 'post_type' => 'attachment',
 'post_mime_type' => 'image',
 'numberposts' => -1,
 )
 );
 $images_size_info = [
 "total_original_size" => 0,
 "total_avif_size" => 0,
 "total_webp_size" => 0,
 ];
 echo "<div class='summary-wrapper'>";
 foreach ($images as $image) {
 try {
 // Determine the extension
 $extension = determine_image_extension($image->guid);
 // Handle unsupported extensions
 if ($extension === 'svg' || $extension === 'gif') {
 throw new FilesizeUnavailableException($extension, 'Unsupported extension: ' . $extension);
 }
 $metadata = wp_get_attachment_metadata($image->ID);
 $cur_image_size_info = [
 "original_size" => isset($metadata['filesize']) ? $metadata['filesize'] : 0,
 "avif_size" => 0,
 "webp_size" => 0,
 ];
 if (isset($metadata['sizes'])) {
 foreach ($metadata['sizes'] as $size_name => $size) {
 $cur_image_size_info["original_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_avif'])) {
 foreach ($metadata['sizes_avif'] as $size_name => $size) {
 $cur_image_size_info["avif_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_webp'])) {
 foreach ($metadata['sizes_webp'] as $size_name => $size) {
 $cur_image_size_info["webp_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (!isset($metadata['sizes'])) {
 throw new FilesizeUnavailableException('Unknown', 'Filesize information not available for this file.');
 }
 $images_size_info['total_original_size'] += $cur_image_size_info['original_size'];
 $images_size_info['total_avif_size'] += $cur_image_size_info['avif_size'];
 $images_size_info['total_webp_size'] += $cur_image_size_info['webp_size'];
 echo "<div class='summary-item'>";
 echo "<img src='" . $image->guid . "' alt='Image ID: " . $image->ID . "' width='150px'>";
 echo "<h4>Image ID: " . $image->ID . "</h4>";
 echo "<p>Image Title: <b>" . $image->post_title . "</b></p>";
 echo "<p>Original size: " . size_format($cur_image_size_info['original_size']) . " </p>";
 echo "<p>Avif size: " . size_format($cur_image_size_info['avif_size']) . "</p>";
 echo "<p>Webp size: " . size_format($cur_image_size_info['webp_size']) . "</p>";
 echo "</div>";
 } catch (FilesizeUnavailableException $e) {
 echo "Filesize information not available for image ID " . $image->ID . ". " . $e->getMessage();
 } catch (Exception $e) {
 echo "An error occurred: " . $e->getMessage();
 }
 }
 
 echo "</div>";
 echo "<div class='total-summary-item'>";
 echo "<h4>Total Summary:</h4>";
 echo "<p>Total Original Image Size: " . size_format($images_size_info['total_original_size']) . "</p>";
 echo "<p>Total AVIF Image Size: " . size_format($images_size_info['total_avif_size']) . "</p>";
 echo "<p>Total WebP Image Size: " . size_format($images_size_info['total_webp_size']) . "</p>";
 echo "</div>";
 return $images_size_info;
}
function webp_avif_bulk_convert_page()
{
 if (isset($_POST['submit'])) {
 $quality_webp = isset($_POST['quality_webp']) ? intval($_POST['quality_webp']) : DEFAULT_QUALITY;
 $quality_avif = isset($_POST['quality_avif']) ? intval($_POST['quality_avif']) : DEFAULT_QUALITY;
 $quality_jpeg = isset($_POST['quality_jpeg']) ? intval($_POST['quality_jpeg']) : DEFAULT_QUALITY;
 if ($_POST['submit'] === 'Set') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 update_option('wac_quality_webp', $quality_webp);
 update_option('wac_quality_avif', $quality_avif);
 update_option('wac_quality_jpeg', $quality_jpeg);
 if (isset($_POST['regenerate']) && $_POST['regenerate'] === 'on') {
 echo '<span class="closebtn icon" onclick="this.parentElement.style.display=\'none\';"></span>';
 echo '<div class="progress-bar" id="progress-bar" style="width: 0%">0%;
 </div>';
 Hooks\update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg);
 echo '<p class="notification notification-good">
 All images have been converted to WebP and Avif formats.
 </p>';
 }
 } else if ($_POST['submit'] === 'Delete') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 Hooks\delete_all_attachments_avif_and_webp();
 echo '<p class="notification notification-bad">
 All WebP and Avif images have been deleted.
 </p>';
 }
 echo '</div>';
 echo '</div>';
 }
 ?>
<div class="image-conversion-wrapper">
 <h1 class="conversion-heading">WebP & Avif Converter </h1>
 <form method="post">
 <?php $isPhpVersionOk = true; ?> <!-- Define PHP_VERSION_OK -->
 <fieldset <?php echo $isPhpVersionOk ? '' : 'disabled' ?>>
 <p class="conversion-description">Tool for WebP and Avif format conversion of all images in the
 uploads/media library directory. <br>
 <b>Choose quality</b> - choose the quality of the converted images (the lower the quality, the smaller
 the size) <br>
 <b>Delete function</b> - deletes all WebP and Avif images from the uploads/media library directory.
 <br>
 <b>Convert function</b> - converts all images in the uploads/media library directory to WebP and Avif
 formats. <br>
 <b>Note: </b> This tool will not convert images that are not in the uploads/media library directory.<br>
 <?php echo Utils\get_php_version_info(); ?>
 </p>
 <div class="conversion-options">
 <label class="option-label">Quality of WEBP: (0 - 100%)</label>
 <input type="number" name="quality_webp" value="<?php echo get_option('wac_quality_webp', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of AVIF: (0 - 100%)</label>
 <input type="number" name="quality_avif" value="<?php echo get_option('wac_quality_avif', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of JPEG: (0 - 100%)</label>
 <input type="number" name="quality_jpeg" value="<?php echo get_option('wac_quality_jpeg', DEFAULT_QUALITY); ?>" min="0" max="100">
 <input type="checkbox" name="regenerate" id="regenerate" checked>
 <label for="regenerate" class="option-label">
 Update qualities of existing images
 </label>
 
 <div class="toggle-summary_w">
 <button id="toggle-summary">Show / Hide Podsumowanie</button>
 </div>
 <div class="conversion-summary-toggle">
 <?php
 // You need to define the get_images_size_info function or include the file that contains it.
 get_images_size_info();
 ?>
 </div>
 </div>
 
 <div class="conversion-buttons">
 <input type="submit" name="submit" value="Set" class="convert-button">
 <input type="submit" name="submit" value="Delete" class="delete-button">
 </div>
 </fieldset>
 </form>
</div>
<?php
}
/**
 * Runs the main functionality of the plugin.
 */
function run_web_avif_converter()
{
 // The 'Web_Avif_Converter' class code is included in the 'includes/class-web-avif-converter.php' file.
 require plugin_dir_path(__FILE__) . 'includes/class-web-avif-converter.php';
 // echo print_r
 $plugin = new Web_Avif_Converter();
 $plugin->run();
}
run_web_avif_converter();
<?php
namespace WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
use WebAvifConverter\GeneratorUtils;
// function p($a, $die = 0){
 // echo '<pre>';
 // echo print_r($a);
 // echo '</pre>';
 // if ($die) { wp_die(); }
// }
apply_filters('jepg_quality', get_option('wac_quality_jpeg', DEFAULT_QUALITY));
add_filter('wp_generate_attachment_metadata', 'WebAvifConverter\Hooks\convert_images_on_generate_attachment_metadata', 10, 2);
function convert_images_on_generate_attachment_metadata($metadata, $attachment_id)
{
 if (!isset($metadata['file'])) { return $metadata; }
 $extension = pathinfo($metadata['file'], PATHINFO_EXTENSION);
 if (!in_array($extension, ['jpg', 'jpeg', 'png'])) { return $metadata; }
 
 $metadata['quality_jpeg'] = get_option('wac_quality_jpeg', DEFAULT_QUALITY);
 wp_update_attachment_metadata($attachment_id, $metadata);
 // Generating JPEGs with adjusted quality is handled by jepg_quality filter
 GeneratorUtils\generate_webp_sizes($attachment_id, get_option('wac_quality_webp', DEFAULT_QUALITY));
 GeneratorUtils\generate_avif_sizes($attachment_id, get_option('wac_quality_avif', DEFAULT_QUALITY));
 return wp_get_attachment_metadata($attachment_id);
}
add_action('edit_attachment', 'WebAvifConverter\Hooks\save_image_quality_metadata');
function save_image_quality_metadata($attachment_id)
{ 
 $metadata = wp_get_attachment_metadata($attachment_id);
 $filed_names = ['quality_jpeg', 'quality_avif', 'quality_webp' ];
 foreach ($filed_names as $filed_name) {
 if (empty($_REQUEST['attachments'][$attachment_id][$filed_name])) { continue; }
 $quality = intval($_REQUEST['attachments'][$attachment_id][$filed_name]);
 if ($quality < 1 || $quality > 100 || isset($metadata[$filed_name]) && $quality === $metadata[$filed_name]) { continue; }
 if ($filed_name === 'quality_jpeg') { GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_webp') { GeneratorUtils\generate_webp_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_avif') { GeneratorUtils\generate_avif_sizes($attachment_id, $quality); }
 } 
}
function update_attachment_quality($attachment_id, $quality_webp = DEFAULT_QUALITY, $quality_avif = DEFAULT_QUALITY, $quality_jpeg = DEFAULT_QUALITY)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata) || !isset($metadata['file']) || !isset($metadata['sizes'])) {
 return; // No metadata found for this attachment.
 }
 if(!isset($metadata['quality_jpeg']) || intval($metadata['quality_jpeg']) !== $quality_jpeg){
 
 GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality_jpeg);
 }
 if(!isset($metadata['quality_webp']) || intval($metadata['quality_webp']) !== $quality_webp){
 
 
 GeneratorUtils\generate_webp_sizes($attachment_id, $quality_webp);
 }
 
 if(!isset($metadata['quality_avif']) || intval($metadata['quality_avif']) !== $quality_avif){
 GeneratorUtils\generate_avif_sizes($attachment_id, $quality_avif);
 }
}
function update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg)
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_status' => null,
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 
 foreach ($attachments as $attachment) {
 $progress++;
 $percent = intval($progress / $total_attachments * 100);
 Utils\update_progress_bar($percent);
 update_attachment_quality($attachment->ID, $quality_webp, $quality_avif, $quality_jpeg);
 }
}
add_filter('delete_attachment', 'WebAvifConverter\Hooks\delete_attachment_files');
function delete_attachment_files($attachment_id)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 $upload_dir = wp_upload_dir()['basedir'];
 if (array_key_exists('file_webp', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_webp']);
 unset($metadata['file_webp']);
 }
 if (array_key_exists('file_avif', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_avif']);
 unset($metadata['file_avif']);
 }
 $attachment_subdir = dirname($metadata['file']);
 $attachment_files_dir = $upload_dir . '/' . $attachment_subdir . '/';
 if (array_key_exists('sizes_avif', $metadata)) {
 foreach ($metadata['sizes_avif'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_avif']);
 }
 
 if (array_key_exists('quality_webp', $metadata)){
 unset($metadata['quality_webp']);
 }
 
 if (array_key_exists('quality_avif', $metadata)){
 unset($metadata['quality_avif']);
 }
 if (array_key_exists('sizes_webp', $metadata)) {
 foreach ($metadata['sizes_webp'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_webp']);
 }wp_update_attachment_metadata($attachment_id, $metadata);
}
function delete_all_attachments_avif_and_webp()
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_mime_type' => 'image',
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 foreach ($attachments as $attachment) {
 delete_attachment_files($attachment->ID); 
 $progress++;
 $percent = intval($progress / $total_attachments * 100) . "%";
 Utils\update_progress_bar($percent);
 }
}
<?php
namespace WebAvifConverter\GeneratorUtils;
/**
 * Convert image to WebP format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted WebP image or void if unable to create an image resource.
 */
 function p($a, $die = 0){
 echo '<pre>';
 echo print_r($a);
 echo '</pre>';
 if ($die) { wp_die(); }
}
function generate_jpeg(string $path, int $quality = 80){
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagejpeg($image, $output_path . '/' . $filename , $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename;
}
function generate_webp(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagewebp($image, $output_path . '/' . $filename . '.webp', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.webp';
}
/**
 * Convert image to AVIF format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted AVIF image or void if unable to create an image resource.
 */
function generate_avif(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imageavif($image, $output_path . '/' . $filename . '.avif', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.avif';
}
function generate_jpeg_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_jpeg'] = $quality;
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 // p($metadata['sizes'], 1);
 foreach($metadata['sizes'] as $size_name => $size){
 $subsize_path = $image_subdir_path . '/' . $size['file'];
 $image = wp_get_image_editor($subsize_path);
 $image->set_quality( $quality );
 $saved = $image->save($subsize_path);
 $metadata['sizes'][$size_name]['filesize'] = filesize($subsize_path);
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_webp_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_webp'] = $quality;
 $metadata['sizes_webp'] = [];
 $metadata['file_webp'] = generate_webp(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['webp_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_webp']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 
 //create or overwrite the subsize image
 $subsize_subpath = generate_webp($original_subsize_path, $quality);
 $metadata['sizes_webp'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/webp',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_avif_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_avif'] = $quality;
 $metadata['sizes_avif'] = [];
 $metadata['file_avif'] = generate_avif(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['avif_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_avif']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 //create or overwrite the subsize image
 $subsize_subpath = generate_avif($original_subsize_path, $quality);
 $metadata['sizes_avif'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/avif',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
<?php
namespace WebAvifConverter\Utils;
/**
 * Helper function for deleting files.
 */
function safe_unlink($path)
{
 if (file_exists($path)) {
 unlink($path);
 }
}
function update_progress_bar($percent) {
 $percent = strval($percent);
 echo "<script>
 var progressBar = document.getElementById('progress-bar');
 progressBar.style.width = '$percent%';
 progressBar.innerHTML = '$percent%';
 </script>";
 ob_flush();
 flush();
}
function get_php_version_info()
{
 if(version_compare(phpversion(), PHP_REQUIRED_VERSION, '>=')){
 return 'PHP Version is: <span class="php-version-good">' . phpversion() . '</span><b> version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 } else {
 return 'PHP Version: <span class="php-version-bad">' . phpversion() . '</span> is too low <.>version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 }
}
```
<?php
/**
 * The plugin bootstrap file
 *
 * This file is read by WordPress to generate the plugin information in the plugin
 * admin area. This file also includes all of the dependencies used by the plugin,
 * registers the activation and deactivation functions, and defines a function
 * that starts the plugin.
 *
 * @link https://rekurencja.com/
 * @since 1.0.0
 * @package Web_Avif_Converter
 *
 * @wordpress-plugin
 * Plugin Name: WebP & Avif Converter
 * Plugin URI: https://images.rekurencja.com
 * Description: Fast and simple plugin to automatically convert and serve WebP & AVIF images.
 * Version: 1.0.0
 * Author: Rekurencja
 * Author URI: https://rekurencja.com/
 * License: GPL-2.0+
 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
 * Text Domain: web-avif-converter
 * Domain Path: /languages
 */
// If this file is called directly, abort.
if (!defined('WPINC')) {
 die;
}
define('PHP_REQUIRED_VERSION', '8.1.0');
define('PHP_VERSION_OK', version_compare(phpversion(), PHP_REQUIRED_VERSION, '>='));
define('DEFAULT_QUALITY', 82);
require plugin_dir_path(__FILE__) . 'public/src/utils/utils.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/activation_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/hooks/attachment_hooks.php';
require plugin_dir_path(__FILE__) . 'public/src/utils/generator-utils.php';
// exceptions
require plugin_dir_path(__FILE__) . 'public/src/exceptions/exceptions.php';
// Include admin.php for admin page functionality
if (is_admin()) {
 require plugin_dir_path(__FILE__) . 'public/src/admin.php';
}
register_activation_hook(__FILE__, 'WebAvifConverter\Hooks\activate_web_avif_converter');
register_deactivation_hook(__FILE__, 'WebAvifConverter\Hooks\deactivate_web_avif_converter');
add_filter('attachment_fields_to_edit', 'add_image_quality_field', 10, 2);
add_filter('manage_media_columns', 'add_image_quality_column');
add_action('manage_media_custom_column', 'display_image_quality_column', 10, 2);
add_filter('jpeg_quality', 'get_jpeg_quality');
function get_jpeg_quality($quality)
{
 return get_option('wac_quality_jpeg', 82);
}
use WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
function add_image_quality_column($columns)
{
 $columns['quality_webp'] = 'WebP Quality';
 $columns['quality_avif'] = 'Avif Quality';
 $columns['quality_jpeg'] = 'Jpeg Quality';
 return $columns;
}
function add_image_quality_field($form_fields, $post)
{
 // wp_die( print_r( $form_fields ));
 $form_fields['quality_webp'] = generate_quality_field($post->ID, 'quality_webp', 'Quality of WEBP');
 $form_fields['quality_avif'] = generate_quality_field($post->ID, 'quality_avif', 'Quality of AVIF');
 $form_fields['quality_jpeg'] = generate_quality_field($post->ID, 'quality_jpeg', 'Quality of JPEG');
 return $form_fields;
}
function determine_image_extension($image_url)
{
 $extension = pathinfo($image_url, PATHINFO_EXTENSION);
 return strtolower($extension);
}
function generate_quality_field($post_id, $field_name, $field_label)
{
 // get post metadata
 $metadata = wp_get_attachment_metadata($post_id);
 // echo $post_id;
 // wp_die(print_r($metadata));
 if (isset(wp_get_attachment_metadata($post_id)[$field_name])) {
 $field_value = wp_get_attachment_metadata($post_id)[$field_name];
 $placeholder_value = $field_value;
 } else {
 $field_value = '';
 $placeholder_value = 'Quality is not set';
 }
 $input_html = "<input type='number' min='0' max='100' step='1' ";
 $input_html .= "name='attachments[$post_id][$field_name]' ";
 $input_html .= "value='" . esc_attr($field_value ? $field_value : '') . "' ";
 $input_html .= "placeholder='" . esc_attr($placeholder_value) . "'/>";
 $field = array(
 'label' => $field_label,
 'input' => 'html',
 'helps' => 'Enter a value between 1 and 100 for image quality (100 = best quality, 1 = worst quality)',
 'html' => $input_html,
 );
 return $field;
}
function display_image_quality_column($column_name, $attachment_id)
{
 $allowed_columns = ['quality_avif', 'quality_webp', 'quality_jpeg'];
 if (in_array($column_name, $allowed_columns)) {
 $attachment_metadata = wp_get_attachment_metadata($attachment_id);
 if (isset($attachment_metadata[$column_name])) {
 echo $attachment_metadata[$column_name];
 } else {
 echo 'N/A';
 }
 }
}
add_action('admin_menu', 'webp_avif_bulk_convert_menu');
function webp_avif_bulk_convert_menu()
{
 add_submenu_page(
 'options-general.php',
 'WebP & Avif Converter',
 'WebP & Avif Converter',
 'manage_options',
 'webp_avif_bulk_convert',
 'webp_avif_bulk_convert_page'
 );
}
function get_images_size_info()
{
 // loop through all images
 $images = get_posts(
 array(
 'post_type' => 'attachment',
 'post_mime_type' => 'image',
 'numberposts' => -1,
 )
 );
 $images_size_info = [
 "total_original_size" => 0,
 "total_avif_size" => 0,
 "total_webp_size" => 0,
 ];
 echo "<div class='summary-wrapper'>";
 foreach ($images as $image) {
 try {
 // Determine the extension
 $extension = determine_image_extension($image->guid);
 // Handle unsupported extensions
 if ($extension === 'svg' || $extension === 'gif') {
 throw new FilesizeUnavailableException($extension, 'Unsupported extension: ' . $extension);
 }
 $metadata = wp_get_attachment_metadata($image->ID);
 $cur_image_size_info = [
 "original_size" => isset($metadata['filesize']) ? $metadata['filesize'] : 0,
 "avif_size" => 0,
 "webp_size" => 0,
 ];
 if (isset($metadata['sizes'])) {
 foreach ($metadata['sizes'] as $size_name => $size) {
 $cur_image_size_info["original_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_avif'])) {
 foreach ($metadata['sizes_avif'] as $size_name => $size) {
 $cur_image_size_info["avif_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (isset($metadata['sizes_webp'])) {
 foreach ($metadata['sizes_webp'] as $size_name => $size) {
 $cur_image_size_info["webp_size"] += isset($size['filesize']) ? $size['filesize'] : 0;
 }
 }
 if (!isset($metadata['sizes'])) {
 throw new FilesizeUnavailableException('Unknown', 'Filesize information not available for this file.');
 }
 $images_size_info['total_original_size'] += $cur_image_size_info['original_size'];
 $images_size_info['total_avif_size'] += $cur_image_size_info['avif_size'];
 $images_size_info['total_webp_size'] += $cur_image_size_info['webp_size'];
 echo "<div class='summary-item'>";
 echo "<img src='" . $image->guid . "' alt='Image ID: " . $image->ID . "' width='150px'>";
 echo "<h4>Image ID: " . $image->ID . "</h4>";
 echo "<p>Image Title: <b>" . $image->post_title . "</b></p>";
 echo "<p>Original size: " . size_format($cur_image_size_info['original_size']) . " </p>";
 echo "<p>Avif size: " . size_format($cur_image_size_info['avif_size']) . "</p>";
 echo "<p>Webp size: " . size_format($cur_image_size_info['webp_size']) . "</p>";
 echo "</div>";
 } catch (FilesizeUnavailableException $e) {
 echo "Filesize information not available for image ID " . $image->ID . ". " . $e->getMessage();
 } catch (Exception $e) {
 echo "An error occurred: " . $e->getMessage();
 }
 }
 
 echo "</div>";
 echo "<div class='total-summary-item'>";
 echo "<h4>Total Summary:</h4>";
 echo "<p>Total Original Image Size: " . size_format($images_size_info['total_original_size']) . "</p>";
 echo "<p>Total AVIF Image Size: " . size_format($images_size_info['total_avif_size']) . "</p>";
 echo "<p>Total WebP Image Size: " . size_format($images_size_info['total_webp_size']) . "</p>";
 echo "</div>";
 return $images_size_info;
}
function webp_avif_bulk_convert_page()
{
 if (isset($_POST['submit'])) {
 $quality_webp = isset($_POST['quality_webp']) ? intval($_POST['quality_webp']) : DEFAULT_QUALITY;
 $quality_avif = isset($_POST['quality_avif']) ? intval($_POST['quality_avif']) : DEFAULT_QUALITY;
 $quality_jpeg = isset($_POST['quality_jpeg']) ? intval($_POST['quality_jpeg']) : DEFAULT_QUALITY;
 if ($_POST['submit'] === 'Set') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 update_option('wac_quality_webp', $quality_webp);
 update_option('wac_quality_avif', $quality_avif);
 update_option('wac_quality_jpeg', $quality_jpeg);
 if (isset($_POST['regenerate']) && $_POST['regenerate'] === 'on') {
 echo '<span class="closebtn icon" onclick="this.parentElement.style.display=\'none\';"></span>';
 echo '<div class="progress-bar" id="progress-bar" style="width: 0%">0%;
 </div>';
 Hooks\update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg);
 echo '<p class="notification notification-good">
 All images have been converted to WebP and Avif formats.
 </p>';
 }
 } else if ($_POST['submit'] === 'Delete') {
 echo '<div class="success alert conversion-wrapper" id="alert" [class.visible]="isVisible">';
 echo '<div class="content">';
 Hooks\delete_all_attachments_avif_and_webp();
 echo '<p class="notification notification-bad">
 All WebP and Avif images have been deleted.
 </p>';
 }
 echo '</div>';
 echo '</div>';
 }
 ?>
<div class="image-conversion-wrapper">
 <h1 class="conversion-heading">WebP & Avif Converter </h1>
 <form method="post">
 <?php $isPhpVersionOk = true; ?> <!-- Define PHP_VERSION_OK -->
 <fieldset <?php echo $isPhpVersionOk ? '' : 'disabled' ?>>
 <p class="conversion-description">Tool for WebP and Avif format conversion of all images in the
 uploads/media library directory. <br>
 <b>Choose quality</b> - choose the quality of the converted images (the lower the quality, the smaller
 the size) <br>
 <b>Delete function</b> - deletes all WebP and Avif images from the uploads/media library directory.
 <br>
 <b>Convert function</b> - converts all images in the uploads/media library directory to WebP and Avif
 formats. <br>
 <b>Note: </b> This tool will not convert images that are not in the uploads/media library directory.<br>
 <?php echo Utils\get_php_version_info(); ?>
 </p>
 <div class="conversion-options">
 <label class="option-label">Quality of WEBP: (0 - 100%)</label>
 <input type="number" name="quality_webp" value="<?php echo get_option('wac_quality_webp', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of AVIF: (0 - 100%)</label>
 <input type="number" name="quality_avif" value="<?php echo get_option('wac_quality_avif', DEFAULT_QUALITY); ?>" min="0" max="100">
 <label class="option-label">Quality of JPEG: (0 - 100%)</label>
 <input type="number" name="quality_jpeg" value="<?php echo get_option('wac_quality_jpeg', DEFAULT_QUALITY); ?>" min="0" max="100">
 <input type="checkbox" name="regenerate" id="regenerate" checked>
 <label for="regenerate" class="option-label">
 Update qualities of existing images
 </label>
 
 <div class="toggle-summary_w">
 <button id="toggle-summary">Show / Hide Podsumowanie</button>
 </div>
 <div class="conversion-summary-toggle">
 <?php
 // You need to define the get_images_size_info function or include the file that contains it.
 get_images_size_info();
 ?>
 </div>
 </div>
 
 <div class="conversion-buttons">
 <input type="submit" name="submit" value="Set" class="convert-button">
 <input type="submit" name="submit" value="Delete" class="delete-button">
 </div>
 </fieldset>
 </form>
</div>
<?php
}
/**
 * Runs the main functionality of the plugin.
 */
function run_web_avif_converter()
{
 // The 'Web_Avif_Converter' class code is included in the 'includes/class-web-avif-converter.php' file.
 require plugin_dir_path(__FILE__) . 'includes/class-web-avif-converter.php';
 // echo print_r
 $plugin = new Web_Avif_Converter();
 $plugin->run();
}
run_web_avif_converter();
<?php
namespace WebAvifConverter\Hooks;
use WebAvifConverter\Utils;
use WebAvifConverter\GeneratorUtils;
// function p($a, $die = 0){
 // echo '<pre>';
 // echo print_r($a);
 // echo '</pre>';
 // if ($die) { wp_die(); }
// }
apply_filters('jepg_quality', get_option('wac_quality_jpeg', DEFAULT_QUALITY));
add_filter('wp_generate_attachment_metadata', 'WebAvifConverter\Hooks\convert_images_on_generate_attachment_metadata', 10, 2);
function convert_images_on_generate_attachment_metadata($metadata, $attachment_id)
{
 if (!isset($metadata['file'])) { return $metadata; }
 $extension = pathinfo($metadata['file'], PATHINFO_EXTENSION);
 if (!in_array($extension, ['jpg', 'jpeg', 'png'])) { return $metadata; }
 
 $metadata['quality_jpeg'] = get_option('wac_quality_jpeg', DEFAULT_QUALITY);
 wp_update_attachment_metadata($attachment_id, $metadata);
 // Generating JPEGs with adjusted quality is handled by jepg_quality filter
 GeneratorUtils\generate_webp_sizes($attachment_id, get_option('wac_quality_webp', DEFAULT_QUALITY));
 GeneratorUtils\generate_avif_sizes($attachment_id, get_option('wac_quality_avif', DEFAULT_QUALITY));
 return wp_get_attachment_metadata($attachment_id);
}
add_action('edit_attachment', 'WebAvifConverter\Hooks\save_image_quality_metadata');
function save_image_quality_metadata($attachment_id)
{ 
 $metadata = wp_get_attachment_metadata($attachment_id);
 $filed_names = ['quality_jpeg', 'quality_avif', 'quality_webp' ];
 foreach ($filed_names as $filed_name) {
 if (empty($_REQUEST['attachments'][$attachment_id][$filed_name])) { continue; }
 $quality = intval($_REQUEST['attachments'][$attachment_id][$filed_name]);
 if ($quality < 1 || $quality > 100 || isset($metadata[$filed_name]) && $quality === $metadata[$filed_name]) { continue; }
 if ($filed_name === 'quality_jpeg') { GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_webp') { GeneratorUtils\generate_webp_sizes($attachment_id, $quality); }
 if ($filed_name === 'quality_avif') { GeneratorUtils\generate_avif_sizes($attachment_id, $quality); }
 } 
}
function update_attachment_quality($attachment_id, $quality_webp = DEFAULT_QUALITY, $quality_avif = DEFAULT_QUALITY, $quality_jpeg = DEFAULT_QUALITY)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata) || !isset($metadata['file']) || !isset($metadata['sizes'])) {
 return; // No metadata found for this attachment.
 }
 if(!isset($metadata['quality_jpeg']) || intval($metadata['quality_jpeg']) !== $quality_jpeg){
 
 GeneratorUtils\generate_jpeg_sizes($attachment_id, $quality_jpeg);
 }
 if(!isset($metadata['quality_webp']) || intval($metadata['quality_webp']) !== $quality_webp){
 
 
 GeneratorUtils\generate_webp_sizes($attachment_id, $quality_webp);
 }
 
 if(!isset($metadata['quality_avif']) || intval($metadata['quality_avif']) !== $quality_avif){
 GeneratorUtils\generate_avif_sizes($attachment_id, $quality_avif);
 }
}
function update_all_attachments_quality($quality_webp, $quality_avif, $quality_jpeg)
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_status' => null,
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 
 foreach ($attachments as $attachment) {
 $progress++;
 $percent = intval($progress / $total_attachments * 100);
 Utils\update_progress_bar($percent);
 update_attachment_quality($attachment->ID, $quality_webp, $quality_avif, $quality_jpeg);
 }
}
add_filter('delete_attachment', 'WebAvifConverter\Hooks\delete_attachment_files');
function delete_attachment_files($attachment_id)
{
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 $upload_dir = wp_upload_dir()['basedir'];
 if (array_key_exists('file_webp', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_webp']);
 unset($metadata['file_webp']);
 }
 if (array_key_exists('file_avif', $metadata)) {
 Utils\safe_unlink($upload_dir . '/' . $metadata['file_avif']);
 unset($metadata['file_avif']);
 }
 $attachment_subdir = dirname($metadata['file']);
 $attachment_files_dir = $upload_dir . '/' . $attachment_subdir . '/';
 if (array_key_exists('sizes_avif', $metadata)) {
 foreach ($metadata['sizes_avif'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_avif']);
 }
 
 if (array_key_exists('quality_webp', $metadata)){
 unset($metadata['quality_webp']);
 }
 
 if (array_key_exists('quality_avif', $metadata)){
 unset($metadata['quality_avif']);
 }
 if (array_key_exists('sizes_webp', $metadata)) {
 foreach ($metadata['sizes_webp'] as $size) {
 Utils\safe_unlink($attachment_files_dir . $size['file']);
 }
 unset($metadata['sizes_webp']);
 }wp_update_attachment_metadata($attachment_id, $metadata);
}
function delete_all_attachments_avif_and_webp()
{
 Utils\update_progress_bar(0);
 $attachments = get_posts(array(
 'post_type' => 'attachment',
 'numberposts' => -1,
 'post_mime_type' => 'image',
 'exclude' => get_post_thumbnail_id()
 ));
 $total_attachments = count($attachments);
 $progress = 0;
 foreach ($attachments as $attachment) {
 delete_attachment_files($attachment->ID); 
 $progress++;
 $percent = intval($progress / $total_attachments * 100) . "%";
 Utils\update_progress_bar($percent);
 }
}
<?php
namespace WebAvifConverter\GeneratorUtils;
/**
 * Convert image to WebP format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted WebP image or void if unable to create an image resource.
 */
 function p($a, $die = 0){
 echo '<pre>';
 echo print_r($a);
 echo '</pre>';
 if ($die) { wp_die(); }
}
function generate_jpeg(string $path, int $quality = 80){
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagejpeg($image, $output_path . '/' . $filename , $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename;
}
function generate_webp(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imagewebp($image, $output_path . '/' . $filename . '.webp', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.webp';
}
/**
 * Convert image to AVIF format
 *
 * @param string $path Path to the image file.
 * @param int $quality Image quality (0 to 100, default is 80).
 *
 * @return string|void Returns the relative path to the converted AVIF image or void if unable to create an image resource.
 */
function generate_avif(string $path, int $quality = 80)
{
 $output_path = dirname($path);
 $extension = pathinfo($path, PATHINFO_EXTENSION);
 $filename = basename($path, '.' . $extension);
 $image = null;
 if ($extension === 'jpeg' || $extension === 'jpg') {
 $image = imagecreatefromjpeg($path);
 } elseif ($extension === 'png') {
 $image = imagecreatefrompng($path);
 } elseif ($extension === 'gif') {
 $image = imagecreatefromgif($path);
 } else {
 return; // Unsupported format.
 }
 if (!$image) {
 return; // Unable to create image resource, possibly unsupported format.
 }
 imageavif($image, $output_path . '/' . $filename . '.avif', $quality);
 imagedestroy($image);
 $directories = explode('/', dirname($path));
 $upload_subdir = implode('/', array_slice($directories, -2));
 return $upload_subdir . '/' . $filename . '.avif';
}
function generate_jpeg_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_jpeg'] = $quality;
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 // p($metadata['sizes'], 1);
 foreach($metadata['sizes'] as $size_name => $size){
 $subsize_path = $image_subdir_path . '/' . $size['file'];
 $image = wp_get_image_editor($subsize_path);
 $image->set_quality( $quality );
 $saved = $image->save($subsize_path);
 $metadata['sizes'][$size_name]['filesize'] = filesize($subsize_path);
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_webp_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_webp'] = $quality;
 $metadata['sizes_webp'] = [];
 $metadata['file_webp'] = generate_webp(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['webp_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_webp']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 
 //create or overwrite the subsize image
 $subsize_subpath = generate_webp($original_subsize_path, $quality);
 $metadata['sizes_webp'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/webp',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
function generate_avif_sizes($attachment_id, $quality){
 $metadata = wp_get_attachment_metadata($attachment_id);
 if (empty($metadata)) { return; }
 
 $image_subdir_path = wp_get_upload_dir()['basedir'] . '/' . dirname($metadata['file']);
 $metadata['quality_avif'] = $quality;
 $metadata['sizes_avif'] = [];
 $metadata['file_avif'] = generate_avif(
 wp_get_upload_dir()['basedir'] . '/' . $metadata['file'],
 $quality
 );
 $metadata['avif_filesize'] = filesize(wp_get_upload_dir()['basedir'] . '/'. $metadata['file_avif']);
 $original_image_path = wp_get_upload_dir()['basedir'] . '/' . $metadata['file'];
 // skip svg files path info
 if (pathinfo($original_image_path, PATHINFO_EXTENSION) === 'svg') {
 return;
 }
 foreach($metadata['sizes'] as $size_name => $size){
 $original_subsize_path = $image_subdir_path . '/' . $size['file'];
 //create or overwrite the subsize image
 $subsize_subpath = generate_avif($original_subsize_path, $quality);
 $metadata['sizes_avif'][$size_name] = [
 'file' => basename($subsize_subpath),
 'width' => $size['width'],
 'height' => $size['height'],
 'mime-type' => 'image/avif',
 'filesize' => filesize(wp_get_upload_dir()['basedir'] . '/' . $subsize_subpath)
 ];
 }
 wp_update_attachment_metadata($attachment_id, $metadata);
};
<?php
namespace WebAvifConverter\Utils;
/**
 * Helper function for deleting files.
 */
function safe_unlink($path)
{
 if (file_exists($path)) {
 unlink($path);
 }
}
function update_progress_bar($percent) {
 $percent = strval($percent);
 echo "<script>
 var progressBar = document.getElementById('progress-bar');
 progressBar.style.width = '$percent%';
 progressBar.innerHTML = '$percent%';
 </script>";
 ob_flush();
 flush();
}
function get_php_version_info()
{
 if(version_compare(phpversion(), PHP_REQUIRED_VERSION, '>=')){
 return 'PHP Version is: <span class="php-version-good">' . phpversion() . '</span><b> version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 } else {
 return 'PHP Version: <span class="php-version-bad">' . phpversion() . '</span> is too low <.>version >= ' . PHP_REQUIRED_VERSION . '</b> is required.';
 }
}
deleted 28 characters in body
Source Link
Your Common Sense
  • 9.1k
  • 1
  • 22
  • 51
Loading
Source Link
Loading
lang-php

AltStyle によって変換されたページ (->オリジナル) /