PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.7.7
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.7.7
1.7.7 1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
← All changes | modules/optimization/classes/optimize-image.php +47 -57 1.4.11.7.7 View file →
@@ -11,9 +11,11 @@
11 11 Exceptions\Image_Backup_Creation_Error,
12 12 Exceptions\Invalid_Image_Exception,
13 13 Image,
14 14 Image_Backup,
15 + Image_Conversion,
15 16 Image_DB_Update,
17 + Image_Dimensions,
16 18 Image_Meta,
17 19 Image_Status,
18 20 WP_Image_Meta
19 21 };
@@ -19,9 +21,8 @@
19 21 };
20 22 use ImageOptimization\Classes\Logger;
21 23 use ImageOptimization\Classes\Utils;
22 24 use ImageOptimization\Classes\Exceptions\Quota_Exceeded_Error;
23 -use ImageOptimization\Modules\Oauth\Components\Connect;
24 25 use ImageOptimization\Modules\Optimization\Classes\{
25 26 Exceptions\Image_File_Already_Exists_Error,
26 27 Exceptions\Image_Optimization_Error,
27 28 Exceptions\Bulk_Token_Expired_Error,
@@ -26,8 +27,9 @@
26 27 Exceptions\Image_Optimization_Error,
27 28 Exceptions\Bulk_Token_Expired_Error,
28 29 Exceptions\Image_Already_Optimized_Error,
29 30 };
31 +use ImageOptimization\Modules\Connect\Classes\Exceptions\Connection_Error;
30 32 use ImageOptimization\Modules\Settings\Classes\Settings;
31 33 use Throwable;
32 34
33 35 use ImageOptimization\Plugin;
@@ -42,9 +44,9 @@
42 44 *
43 45 * This class is used by manual, bulk and on-upload optimization flows.
44 46 */
45 47 class Optimize_Image {
46 - private const IMAGE_OPTIMIZE_ENDPOINT = 'image/optimize';
48 + public const IMAGE_OPTIMIZE_ENDPOINT = 'image/optimize';
47 49
48 50 protected ?Image $image;
49 51 protected WP_Image_Meta $wp_meta;
50 52 protected string $initiator;
@@ -50,23 +52,21 @@
50 52 protected string $initiator;
51 53 protected ?string $bulk_token;
52 54 private string $current_image_path;
53 55 private string $current_image_size;
54 - private bool $convert_to_webp;
55 56 private bool $keep_backups;
56 57 private array $current_size_duplicates;
58 + protected Image_Conversion $image_conversion;
59 + private bool $is_reoptimize;
57 60
58 61 /**
59 - * @throws Quota_Exceeded_Error|Bulk_Token_Expired_Error|Image_File_Already_Exists_Error|Image_Optimization_Error
62 + * @throws Quota_Exceeded_Error|Connection_Error|Bulk_Token_Expired_Error|Image_File_Already_Exists_Error|Image_Optimization_Error
60 63 */
61 64 public function optimize(): void {
62 65 $sizes_enabled = Settings::get( Settings::CUSTOM_SIZES_OPTION_NAME );
63 66 $sizes_exist = $this->wp_meta->get_size_keys();
64 67
65 - Logger::log(
66 - Logger::LEVEL_INFO,
67 - "Start optimization of {$this->image->get_id()}"
68 - );
68 + Logger::debug( "Start optimization of {$this->image->get_id()}" );
69 69
70 70 foreach ( $sizes_exist as $size_exist ) {
71 71 // If some image sizes optimization is disabled in settings, we check if the current one is still enabled
72 72 if (
@@ -84,24 +84,18 @@
84 84
85 85 $image_meta = new Image_Meta( $this->image->get_id() );
86 86
87 87 // If the current size was already optimized -- ignore it.
88 - if ( in_array( $size_exist, $image_meta->get_optimized_sizes(), true ) ) {
89 - Logger::log(
90 - Logger::LEVEL_INFO,
91 - "Size `$size_exist` is already optimized"
92 - );
88 + if ( ! $this->is_reoptimize && in_array( $size_exist, $image_meta->get_optimized_sizes(), true ) ) {
89 + Logger::debug( "Size `$size_exist` is already optimized" );
93 90
94 91 continue;
95 92 }
96 93
97 94 if ( ! file_exists( $this->image->get_file_path( $size_exist ) ) ) {
98 - Logger::log(
99 - Logger::LEVEL_ERROR,
100 - "Can't access file for size `$size_exist`"
101 - );
95 + Logger::debug( "Can't access file for size `$size_exist`" );
102 96
103 - throw new Image_Optimization_Error( esc_html__( 'File is missing. Verify the upload', 'image-optimization' ) );
97 + continue;
104 98 }
105 99
106 100 $this->current_image_size = $size_exist;
107 101 $this->current_size_duplicates = $this->wp_meta->get_size_duplicates( $size_exist );
@@ -119,12 +113,9 @@
119 113 if ( ! $this->keep_backups ) {
120 114 Image_Backup::remove( $this->image->get_id() );
121 115 }
122 116
123 - Logger::log(
124 - Logger::LEVEL_INFO,
125 - "End optimization of {$this->image->get_id()}"
126 - );
117 + Logger::debug( "End optimization of {$this->image->get_id()}" );
127 118 }
128 119
129 120 private function optimize_current_size(): void {
130 121 try {
@@ -143,19 +134,19 @@
143 134
144 135 // This should only be updated after meta
145 136 $this->update_attachment_post();
146 137 } catch ( Image_Already_Optimized_Error $iao ) {
147 - // If we can't optimize it further, just file update the meta
138 + // If we can't optimize it further, just update the meta
148 139 $original_size = $this->wp_meta->get_file_size( $this->current_image_size )
149 140 ?? File_System::size( $this->image->get_file_path( $this->current_image_size ) );
150 141
151 - $this->update_attachment_meta( $original_size );
152 - $this->update_attachment_post();
153 - } catch ( Bulk_Token_Expired_Error | Quota_Exceeded_Error | Image_File_Already_Exists_Error $e ) {
142 + $this->update_attachment_meta( $original_size, true );
143 + $this->update_attachment_post( true );
144 + } catch ( Bulk_Token_Expired_Error | Quota_Exceeded_Error | Connection_Error | Image_File_Already_Exists_Error $e ) {
154 145 throw $e;
155 146 } catch ( Throwable $t ) {
156 147 // In case of anything else
157 - throw new Image_Optimization_Error( $t->getMessage() );
148 + throw new Image_Optimization_Error( esc_html( $t->getMessage() ) );
158 149 }
159 150 }
160 151
161 152 private function send_file() {
@@ -169,9 +160,9 @@
169 160 }
170 161
171 162 $optimization_options = [
172 163 'compression_level' => Settings::get( Settings::COMPRESSION_LEVEL_OPTION_NAME ),
173 - 'convert_to_webp' => $this->convert_to_webp,
164 + 'convert_to_format' => $this->image_conversion->get_current_conversion_option(),
174 165 'strip_exif' => Settings::get( Settings::STRIP_EXIF_METADATA_OPTION_NAME ),
175 166 ];
176 167
177 168 if ( Settings::get( Settings::RESIZE_LARGER_IMAGES_OPTION_NAME ) ) {
@@ -201,12 +192,9 @@
201 192 Plugin::instance()->modules_manager->get_modules( 'connect-manager' )->connect_instance->update_usage_data( $response->stats );
202 193 }
203 194
204 195 if ( ! isset( $response->imageKey ) || $image_key !== $response->imageKey ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
205 - Logger::log(
206 - Logger::LEVEL_ERROR,
207 - "Image key must be $image_key, instead got $response->imageKey"
208 - );
196 + Logger::error( "Image key must be $image_key, instead got $response->imageKey" );
209 197
210 198 throw new Image_Optimization_Error( esc_html__( 'Service response is incorrect', 'image-optimization' ) );
211 199 }
212 200
@@ -212,12 +200,9 @@
212 200
213 201 $received_file_hash = md5( base64_decode( $response->image, true ) );
214 202
215 203 if ( ! isset( $response->checksum ) || $received_file_hash !== $response->checksum ) {
216 - Logger::log(
217 - Logger::LEVEL_ERROR,
218 - "Image key must be $response->checksum, instead calculated $received_file_hash"
219 - );
204 + Logger::error( "Image key must be $response->checksum, instead calculated $received_file_hash" );
220 205
221 206 throw new Image_Optimization_Error( esc_html__( 'Service response is incorrect', 'image-optimization' ) );
222 207 }
223 208
@@ -235,18 +220,18 @@
235 220 $tmp_path = File_Utils::replace_extension( $path, 'tmp' );
236 221
237 222 File_System::put_contents( $tmp_path, $file_data );
238 223
239 - if ( $this->convert_to_webp ) {
240 - $webp_path = File_Utils::replace_extension( $tmp_path, 'webp' );
241 - $original_file_is_webp = strtolower( $path ) === strtolower( $webp_path );
224 + if ( $this->image_conversion->is_enabled() ) {
225 + $converted_path = File_Utils::replace_extension( $tmp_path, $this->image_conversion->get_current_file_extension() );
226 + $original_is_already_converted = strtolower( $path ) === strtolower( $converted_path );
242 227
243 - if ( ! $original_file_is_webp && File_System::exists( $webp_path ) ) {
228 + if ( ! $original_is_already_converted && File_System::exists( $converted_path ) ) {
244 229 throw new Image_File_Already_Exists_Error();
245 230 }
246 231
247 232 // We want to keep both original as a fallback and optimized webp to prevent 404s
248 - if ( ! $original_file_is_webp ) {
233 + if ( ! $original_is_already_converted ) {
249 234 $this->keep_backups = true;
250 235
251 236 ( new Image_Meta( $this->image->get_id() ) )
252 237 ->set_image_backup_path( $this->current_image_size, $this->current_image_path )
@@ -252,15 +237,15 @@
252 237 ->set_image_backup_path( $this->current_image_size, $this->current_image_path )
253 238 ->save();
254 239 }
255 240
256 - if ( $original_file_is_webp ) {
241 + if ( $original_is_already_converted ) {
257 242 Image_Backup::create( $this->image->get_id(), $this->current_image_size, $this->current_image_path );
258 243 }
259 244
260 - File_System::move( $tmp_path, $webp_path, true );
245 + File_System::move( $tmp_path, $converted_path, true );
261 246
262 - $path = $webp_path;
247 + $path = $converted_path;
263 248 } else {
264 249 Image_Backup::create( $this->image->get_id(), $this->current_image_size, $this->current_image_path );
265 250
266 251 File_System::move( $tmp_path, $path, true );
@@ -279,16 +264,20 @@
279 264 * Updates attachment records in the `wp_posts` table.
280 265 *
281 266 * @return void
282 267 */
283 - private function update_attachment_post() {
268 + private function update_attachment_post( ?bool $is_fully_optimized = false ) {
284 269 $update_query = [];
285 270
286 - if ( $this->convert_to_webp ) {
271 + if ( $this->image_conversion->is_enabled() && ! $is_fully_optimized ) {
287 272 $attachment_object = $this->image->get_attachment_object();
288 273
289 - $update_query['guid'] = File_Utils::replace_extension( $attachment_object->guid, 'webp' );
290 - $update_query['post_mime_type'] = 'image/webp';
274 + $update_query['guid'] = File_Utils::replace_extension(
275 + $attachment_object->guid,
276 + $this->image_conversion->get_current_file_extension()
277 + );
278 +
279 + $update_query['post_mime_type'] = $this->image_conversion->get_current_mime_type();
291 280 }
292 281
293 282 $update_query['post_modified'] = current_time( 'mysql' );
294 283 $update_query['post_modified_gmt'] = current_time( 'mysql', true );
@@ -299,16 +288,16 @@
299 288 /**
300 289 * Updates attachment records in the `wp_postmeta` table.
301 290 *
302 291 * @param int $optimized_size
292 + * @param bool|null $is_fully_optimized
303 293 *
304 294 * @return void
305 295 */
306 - private function update_attachment_meta( int $optimized_size ) {
296 + private function update_attachment_meta( int $optimized_size, ?bool $is_fully_optimized = false ) {
307 297 $meta = new Image_Meta( $this->image->get_id() );
298 + $dimensions = Image_Dimensions::get_by_path( $this->current_image_path );
308 299
309 - list($width, $height) = getimagesize( $this->current_image_path );
310 -
311 300 $sizes_to_update = [ $this->current_image_size, ...$this->current_size_duplicates ];
312 301
313 302 foreach ( $sizes_to_update as $size ) {
314 303 $meta
@@ -316,16 +305,16 @@
316 305 ->add_optimized_size( $size )
317 306 ->add_original_data( $size, $this->wp_meta->get_size_data( $size ) );
318 307
319 308 $this->wp_meta
320 - ->set_width( $size, $width )
321 - ->set_height( $size, $height )
309 + ->set_width( $size, $dimensions->width )
310 + ->set_height( $size, $dimensions->height )
322 311 ->set_file_size( $size, $optimized_size );
323 312
324 - if ( $this->convert_to_webp ) {
313 + if ( $this->image_conversion->is_enabled() && ! $is_fully_optimized ) {
325 314 $this->wp_meta
326 315 ->set_file_path( $size, $this->current_image_path )
327 - ->set_mime_type( $size, 'image/webp' );
316 + ->set_mime_type( $size, $this->image_conversion->get_current_mime_type() );
328 317 }
329 318 }
330 319
331 320 $meta->save();
@@ -362,13 +351,14 @@
362 351
363 352 /**
364 353 * @throws Invalid_Image_Exception
365 354 */
366 - public function __construct( int $image_id, string $initiator, ?string $bulk_token = null ) {
355 + public function __construct( int $image_id, string $initiator, ?string $bulk_token = null, ?bool $is_reoptimize = false ) {
367 356 $this->image = new Image( $image_id );
368 357 $this->wp_meta = new WP_Image_Meta( $image_id, $this->image );
369 358 $this->initiator = $initiator;
370 359 $this->bulk_token = $bulk_token;
371 - $this->convert_to_webp = Settings::get( Settings::CONVERT_TO_WEBP_OPTION_NAME );
360 + $this->is_reoptimize = $is_reoptimize;
361 + $this->image_conversion = new Image_Conversion();
372 362 $this->keep_backups = Settings::get( Settings::BACKUP_ORIGINAL_IMAGES_OPTION_NAME );
373 363 }
374 364 }