This commit is contained in:
2024-05-20 15:37:46 +03:00
commit 00b7dbd0b7
10404 changed files with 3285853 additions and 0 deletions

View File

@ -0,0 +1,121 @@
<?php
namespace Smush\Core\Webp;
use Smush\Core\Controller;
use Smush\Core\File_System;
use Smush\Core\Helper;
use Smush\Core\Media\Media_Item_Cache;
use Smush\Core\Stats\Global_Stats;
class Webp_Controller extends Controller {
const WEBP_OPTIMIZATION_ORDER = 20;
/**
* @var Webp_Helper
*/
private $helper;
/**
* @var Global_Stats
*/
private $global_stats;
/**
* @var Media_Item_Cache
*/
private $media_item_cache;
/**
* @var \WDEV_Logger|null
*/
private $logger;
/**
* @var File_System
*/
private $fs;
public function __construct() {
$this->helper = new Webp_Helper();
$this->global_stats = Global_Stats::get();
$this->media_item_cache = Media_Item_Cache::get_instance();
$this->logger = Helper::logger();
$this->fs = new File_System();
$this->register_action( 'wp_smush_png_jpg_converted', array( $this, 'delete_webp_versions_of_pngs' ), 10, 4 );
$this->register_action( 'delete_attachment', array( $this, 'delete_webp_versions_before_delete' ) );
$this->register_filter( 'wp_smush_optimizations', array(
$this,
'add_webp_optimization',
), self::WEBP_OPTIMIZATION_ORDER, 2 );
$this->register_filter( 'wp_smush_global_optimization_stats', array( $this, 'add_webp_global_stats' ) );
$this->register_action( 'wp_smush_before_restore_backup', array(
$this,
'delete_webp_versions_on_restore',
), 10, 2 );
$this->register_action( 'wp_smush_settings_updated', array(
$this,
'maybe_mark_global_stats_as_outdated',
), 10, 2 );
}
/**
* @param $backup_full_path
* @param $attachment_id
*
* @return bool
*/
public function delete_webp_versions_on_restore( $backup_full_path, $attachment_id ) {
$media_item = Media_Item_Cache::get_instance()->get( $attachment_id );
if ( ! $media_item->is_valid() ) {
return false;
}
$this->helper->delete_media_item_webp_versions( $media_item );
return true;
}
public function delete_webp_versions_before_delete( $attachment_id ) {
$media_item = $this->media_item_cache->get( $attachment_id );
if ( $media_item->is_valid() ) {
foreach ( $media_item->get_size_paths() as $size_path ) {
$this->delete_webp_version( $size_path );
}
} else {
$this->logger->error( sprintf( 'Count not delete webp versions of the media item [%d]', $attachment_id ) );
}
}
public function delete_webp_versions_of_pngs( $attachment_id, $meta, $stats, $png_paths ) {
foreach ( $png_paths as $png_path ) {
$this->delete_webp_version( $png_path );
}
$this->helper->unset_webp_flag( $attachment_id );
}
public function delete_webp_version( $original_path ) {
$webp_file_path = $this->helper->get_webp_file_path( $original_path );
if ( $this->fs->file_exists( $webp_file_path ) ) {
$this->fs->unlink( $webp_file_path );
}
}
public function add_webp_optimization( $optimizations, $media_item ) {
$optimization = new Webp_Optimization( $media_item );
$optimizations[ $optimization->get_key() ] = $optimization;
return $optimizations;
}
public function add_webp_global_stats( $stats ) {
$stats[ Webp_Optimization::OPTIMIZATION_KEY ] = new Webp_Optimization_Global_Stats_Persistable();
return $stats;
}
public function maybe_mark_global_stats_as_outdated( $old_settings, $settings ) {
$old_webp_status = ! empty( $old_settings['webp_mod'] );
$new_webp_status = ! empty( $settings['webp_mod'] );
if ( $old_webp_status !== $new_webp_status ) {
$this->global_stats->mark_as_outdated();
}
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Smush\Core\Webp;
use Smush\Core\Smush\Smusher;
class Webp_Converter extends Smusher {
/**
* @var Webp_Helper
*/
private $webp_helper;
public function __construct() {
parent::__construct();
$this->webp_helper = new Webp_Helper();
}
protected function get_api_request_headers( $file_path ) {
$headers = parent::get_api_request_headers( $file_path );
$headers['webp'] = 'true';
return $headers;
}
protected function save_smushed_image_file( $file_path, $image ) {
$webp_file_path = $this->webp_helper->get_webp_file_path( $file_path, true );
$file_saved = file_put_contents( $webp_file_path, $image );
if ( ! $file_saved ) {
return false;
}
return $webp_file_path;
}
}

View File

@ -0,0 +1,62 @@
<?php
namespace Smush\Core\Webp;
use Smush\Core\Upload_Dir;
class Webp_Dir extends Upload_Dir {
private $webp_path;
private $webp_rel_path;
private $webp_url;
/**
* @return string
*/
public function get_webp_path() {
if ( is_null( $this->webp_path ) ) {
$this->webp_path = $this->prepare_webp_path();
}
return $this->webp_path;
}
/**
* @return string
*/
public function get_webp_rel_path() {
if ( is_null( $this->webp_rel_path ) ) {
$this->webp_rel_path = $this->prepare_webp_rel_path();
}
return $this->webp_rel_path;
}
/**
* @return string
*/
public function get_webp_url() {
if ( is_null( $this->webp_url ) ) {
$this->webp_url = $this->prepare_webp_url();
}
return $this->webp_url;
}
private function prepare_webp_path() {
return dirname( $this->get_upload_path() ) . '/smush-webp';
}
private function prepare_webp_rel_path() {
return dirname( $this->get_upload_rel_path() ) . '/smush-webp';
}
private function prepare_webp_url() {
return dirname( $this->get_upload_url() ) . '/smush-webp';
}
protected function prepare_root_path() {
return apply_filters( 'smush_webp_rules_root_path_base', parent::prepare_root_path() );
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace Smush\Core\Webp;
use Smush\Core\File_System;
use Smush\Core\Media\Media_Item;
use Smush\Core\Smush\Smush_Optimization;
class Webp_Helper {
const WEBP_FLAG = 'webp_flag';
/**
* @var Webp_Dir
*/
private $webp_dir;
/**
* @var File_System
*/
private $fs;
public function __construct() {
$this->webp_dir = new Webp_Dir();
$this->fs = new File_System();
}
public function get_webp_file_path( $file_path, $make = false ) {
$file_rel_path = substr( $file_path, strlen( $this->webp_dir->get_upload_path() ) );
$webp_file_path = $this->webp_dir->get_webp_path() . $file_rel_path . '.webp';
if ( $make ) {
$webp_file_dir = dirname( $webp_file_path );
if ( ! $this->fs->is_dir( $webp_file_dir ) ) {
wp_mkdir_p( $webp_file_dir );
}
}
return $webp_file_path;
}
public function supported_mime_types() {
return array(
'image/jpg',
'image/jpeg',
'image/x-citrix-jpeg',
'image/png',
'image/x-png',
);
}
public function get_webp_flag( $attachment_id ) {
$meta = $this->get_smush_meta( $attachment_id );
return empty( $meta[ self::WEBP_FLAG ] ) ? '' : $meta[ self::WEBP_FLAG ];
}
public function update_webp_flag( $attachment_id, $value ) {
$meta = $this->get_smush_meta( $attachment_id );
if ( empty( $value ) ) {
unset( $meta[ self::WEBP_FLAG ] );
} else {
$meta[ self::WEBP_FLAG ] = $value;
}
update_post_meta( $attachment_id, Smush_Optimization::SMUSH_META_KEY, $meta );
}
public function unset_webp_flag( $attachment_id ) {
$this->update_webp_flag( $attachment_id, false );
}
/**
* @return array|mixed
*/
private function get_smush_meta( $attachment_id ) {
$meta = get_post_meta( $attachment_id, Smush_Optimization::SMUSH_META_KEY, true );
return empty( $meta ) ? array() : $meta;
}
/**
* @param $media_item Media_Item
*
* @return void
*/
public function delete_media_item_webp_versions( $media_item ) {
foreach ( $media_item->get_sizes() as $size ) {
$webp_file_path = $this->get_webp_file_path( $size->get_file_path() );
if ( $this->fs->file_exists( $webp_file_path ) ) {
$this->fs->unlink( $webp_file_path );
}
}
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace Smush\Core\Webp;
use Smush\Core\Stats\Media_Item_Optimization_Global_Stats_Persistable;
class Webp_Optimization_Global_Stats_Persistable extends Media_Item_Optimization_Global_Stats_Persistable {
const GLOBAL_STATS_OPTION_ID = 'wp-smush-webp-global-stats';
public function __construct() {
parent::__construct( self::GLOBAL_STATS_OPTION_ID );
}
public function save() {
// Doing nothing. Since we don't keep stats for individual media items we can't
}
}

View File

@ -0,0 +1,151 @@
<?php
namespace Smush\Core\Webp;
use Smush\Core\File_System;
use Smush\Core\Media\Media_Item;
use Smush\Core\Media\Media_Item_Optimization;
use Smush\Core\Media\Media_Item_Stats;
use Smush\Core\Settings;
/**
* TODO: the response from the API has webp: false and mime_content_type of the written file is not webp, investigate
*/
class Webp_Optimization extends Media_Item_Optimization {
const OPTIMIZATION_KEY = 'webp_optimization';
private $webp_dir;
/**
* @var Media_Item
*/
private $media_item;
/**
* @var Webp_Helper
*/
private $webp_helper;
/**
* @var Settings|null
*/
private $settings;
/**
* @var Webp_Converter
*/
private $converter;
/**
* @var File_System
*/
private $fs;
public function __construct( $media_item ) {
$this->webp_dir = new Webp_Dir();
$this->webp_helper = new Webp_Helper();
$this->media_item = $media_item;
$this->settings = Settings::get_instance();
$this->converter = new Webp_Converter();
$this->fs = new File_System();
}
public function get_key() {
return self::OPTIMIZATION_KEY;
}
public function is_optimized() {
$attachment_id = $this->media_item->get_id();
$webp_flag = $this->webp_helper->get_webp_flag( $attachment_id );
if ( empty( $webp_flag ) ) {
return false;
}
$webp_file_path = trailingslashit( $this->webp_dir->get_webp_path() ) . ltrim( $webp_flag, '/' );
return $this->fs->file_exists( $webp_file_path );
}
public function should_optimize() {
if (
$this->media_item->is_skipped()
|| $this->media_item->has_errors()
|| ! $this->settings->is_webp_module_active()
) {
return false;
}
return in_array(
$this->media_item->get_mime_type(),
$this->webp_helper->supported_mime_types(),
true
);
}
public function should_reoptimize() {
if ( ! $this->should_optimize() ) {
return false;
}
$smushable_sizes = $this->media_item->get_smushable_sizes();
foreach ( $smushable_sizes as $size ) {
$webp_file_path = $this->webp_helper->get_webp_file_path( $size->get_file_path() );
if ( ! $this->fs->file_exists( $webp_file_path ) ) {
return true;
}
}
return false;
}
public function save() {
$webp_file_path = $this->webp_helper->get_webp_file_path( $this->media_item->get_main_size()->get_file_path() );
if ( $this->fs->file_exists( $webp_file_path ) ) {
$relative_path = substr( $webp_file_path, strlen( $this->webp_dir->get_webp_path() . '/' ) );
$this->webp_helper->update_webp_flag( $this->media_item->get_id(), $relative_path );
}
}
public function get_stats() {
// Empty stats for now since we don't store webp savings
return new Media_Item_Stats();
}
public function get_size_stats( $size_key ) {
// Empty stats for now since we don't store webp savings
return new Media_Item_Stats();
}
public function should_optimize_size( $size ) {
if ( ! $this->should_optimize() ) {
return false;
}
return array_key_exists(
$size->get_key(),
$this->media_item->get_smushable_sizes()
);
}
public function delete_data() {
$this->webp_helper->unset_webp_flag( $this->media_item->get_id() );
}
public function optimize() {
$media_item = $this->media_item;
$file_paths = array_map( function ( $size ) {
return $size->get_file_path();
}, $media_item->get_smushable_sizes() );
$responses = $this->converter->smush( $file_paths );
$success_responses = array_filter( $responses );
if ( count( $success_responses ) !== count( $responses ) ) {
return false;
}
$this->save();
return true;
}
public function get_errors() {
return $this->converter->get_errors();
}
public function get_optimized_sizes_count() {
// We don't keep per-size stats
return 0;
}
}