opticore/includes/class-image-optimizer.php

227 lines
6.4 KiB
PHP

<?php
/**
* Image Optimizer Class
*
* Handles image optimization and WebP conversion
*/
if (!defined('ABSPATH')) {
exit;
}
class OptiCore_Image_Optimizer {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
}
public function init() {
// Add WebP support
add_filter('the_content', array($this, 'convert_images_to_webp'), 999);
add_filter('post_thumbnail_html', array($this, 'convert_images_to_webp'), 999);
// Add responsive images
add_filter('wp_calculate_image_srcset', array($this, 'optimize_srcset'), 10, 5);
// Remove excessive image sizes
add_filter('intermediate_image_sizes_advanced', array($this, 'remove_unnecessary_image_sizes'));
// Add proper image dimensions
add_filter('the_content', array($this, 'add_image_dimensions'), 999);
}
/**
* Convert images to WebP if supported
*/
public function convert_images_to_webp($content) {
if (is_admin() || !$this->is_webp_supported()) {
return $content;
}
// Replace image sources with WebP versions if they exist
$content = preg_replace_callback(
'/<img([^>]+)src=[\'"]([^\'"]+)\.(jpg|jpeg|png)[\'"]([^>]*)>/i',
array($this, 'replace_with_webp'),
$content
);
return $content;
}
/**
* Replace image with WebP version
*/
private function replace_with_webp($matches) {
$full_tag = $matches[0];
$before = $matches[1];
$image_url = $matches[2];
$extension = $matches[3];
$after = $matches[4];
$webp_url = $image_url . '.webp';
// Check if WebP version exists
$upload_dir = wp_upload_dir();
$webp_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $webp_url);
if (file_exists($webp_path)) {
// Use picture element for better fallback
$picture = '<picture>';
$picture .= '<source srcset="' . esc_url($webp_url) . '" type="image/webp">';
$picture .= '<img' . $before . 'src="' . esc_url($image_url . '.' . $extension) . '"' . $after . '>';
$picture .= '</picture>';
return $picture;
}
return $full_tag;
}
/**
* Check if WebP is supported
*/
private function is_webp_supported() {
if (!isset($_SERVER['HTTP_ACCEPT'])) {
return false;
}
return strpos($_SERVER['HTTP_ACCEPT'], 'image/webp') !== false;
}
/**
* Optimize srcset
*/
public function optimize_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) {
// Remove unnecessary sizes from srcset
$allowed_sizes = array('thumbnail', 'medium', 'large', 'full');
foreach ($sources as $width => $source) {
// Remove very similar sizes (within 10% difference)
foreach ($sources as $width2 => $source2) {
if ($width !== $width2 && abs($width - $width2) / $width < 0.1) {
unset($sources[$width2]);
}
}
}
return $sources;
}
/**
* Remove unnecessary image sizes
*/
public function remove_unnecessary_image_sizes($sizes) {
// Remove sizes that are rarely used
$remove_sizes = array(
'medium_large',
'1536x1536',
'2048x2048',
);
foreach ($remove_sizes as $size) {
unset($sizes[$size]);
}
return $sizes;
}
/**
* Add image dimensions if missing
*/
public function add_image_dimensions($content) {
if (is_admin()) {
return $content;
}
// Add width and height attributes to images without them
$content = preg_replace_callback(
'/<img(?![^>]*(?:width|height))[^>]*src=[\'"]([^\'"]+)[\'"]([^>]*)>/i',
array($this, 'add_dimensions_to_image'),
$content
);
return $content;
}
/**
* Add dimensions to image tag
*/
private function add_dimensions_to_image($matches) {
$full_tag = $matches[0];
$image_url = $matches[1];
$after = $matches[2];
// Try to get image size
$upload_dir = wp_upload_dir();
$image_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $image_url);
if (file_exists($image_path)) {
$size = getimagesize($image_path);
if ($size) {
$full_tag = str_replace('<img', '<img width="' . $size[0] . '" height="' . $size[1] . '"', $full_tag);
}
}
return $full_tag;
}
/**
* Create WebP version of image
*/
public function create_webp_image($file_path) {
if (!file_exists($file_path)) {
return false;
}
$info = pathinfo($file_path);
$webp_path = $file_path . '.webp';
// Check if WebP already exists
if (file_exists($webp_path)) {
return $webp_path;
}
// Check if GD supports WebP
if (!function_exists('imagewebp')) {
return false;
}
$extension = strtolower($info['extension']);
$image = null;
// Load image based on type
switch ($extension) {
case 'jpg':
case 'jpeg':
$image = imagecreatefromjpeg($file_path);
break;
case 'png':
$image = imagecreatefrompng($file_path);
imagepalettetotruecolor($image);
imagealphablending($image, true);
imagesavealpha($image, true);
break;
default:
return false;
}
if (!$image) {
return false;
}
// Convert to WebP
$result = imagewebp($image, $webp_path, 80);
imagedestroy($image);
return $result ? $webp_path : false;
}
}