PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 1.4.6
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v1.4.6
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
imagify / inc / classes / class-attachment.php

class-attachment.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 1.4.6, at inc/classes/class-attachment.php

625 lines 14.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined( 'ABSPATH' ) or die( 'Cheatin\' uh?' );
3
4 class Imagify_Attachment {
5 /**
6 * The attachment ID
7 *
8 * @since 1.0
9 *
10 * @var int
11 * @access public
12 */
13 public $id;
14
15 /**
16 * The constructor
17 *
18 * @since 1.0
19 *
20 * @return void
21 **/
22 function __construct( $id = 0 ) {
23 global $post;
24
25 if ( is_object( $post ) && ! $id ) {
26 $this->id = $post->ID;
27 } else {
28 $this->id = (int) $id;
29 }
30 }
31
32 /**
33 * Get the attachment backup filepath.
34 *
35 * @since 1.0
36 *
37 * @access public
38 * @return string|false
39 */
40 public function get_backup_path() {
41 $file_path = $this->get_original_path();
42 $backup_path = get_imagify_attachment_backup_path( $file_path );
43
44 if( file_exists( $backup_path ) ) {
45 return $backup_path;
46 }
47
48 return false;
49 }
50
51 /**
52 * Get the attachment backup URL.
53 *
54 * @since 1.4
55 *
56 * @access public
57 * @return string|false
58 */
59 public function get_backup_url() {
60 $backup_path = $this->get_backup_path();
61 $backup_url = str_replace( ABSPATH, site_url( '/' ), $backup_path );
62
63 return $backup_url;
64 }
65
66 /**
67 * Get the attachment optimization data.
68 *
69 * @since 1.0
70 *
71 * @access public
72 * @return array
73 */
74 public function get_data() {
75 return get_post_meta( $this->id, '_imagify_data', true );
76 }
77
78 /**
79 * Get the attachment extension.
80 *
81 * @since 1.0
82 *
83 * @access public
84 * @return string
85 */
86 public function get_extension() {
87 $fullsize_path = $this->get_original_path();
88 return pathinfo( $fullsize_path, PATHINFO_EXTENSION );
89 }
90
91 /**
92 * Get the attachment error if there is one.
93 *
94 * @since 1.1.5
95 *
96 * @access public
97 * @return string The message error
98 */
99 public function get_optimized_error() {
100 $error = $this->get_size_data( 'full', 'error' );
101
102 if ( is_string( $error ) ) {
103 return $error;
104 }
105
106 return false;
107 }
108
109 /**
110 * Get the attachment optimization level.
111 *
112 * @since 1.0
113 *
114 * @access public
115 * @return int
116 */
117 public function get_optimization_level() {
118 return get_post_meta( $this->id, '_imagify_optimization_level', true );
119 }
120
121 /**
122 * Get the attachment optimization level label.
123 *
124 * @since 1.2
125 *
126 * @access public
127 * @return string
128 */
129 public function get_optimization_level_label() {
130 $label = '';
131 $level = $this->get_optimization_level();
132
133 switch( $level ) {
134 case 2:
135 $label = __( 'Ultra', 'imagify' );
136 break;
137 case 1:
138 $label = __( 'Aggressive', 'imagify' );
139 break;
140 case 0:
141 $label = __( 'Normal', 'imagify' );
142 break;
143 }
144
145 return $label;
146 }
147
148 /**
149 * Count number of optimized sizes.
150 *
151 * @since 1.0
152 *
153 * @access public
154 * @return int
155 */
156 public function get_optimized_sizes_count() {
157 $data = $this->get_data();
158 $sizes = (array) $data['sizes'];
159 $count = 0;
160
161 if ( isset( $sizes['full'] ) ) {
162 unset( $sizes['full'] );
163 }
164
165 foreach ( $sizes as $size ) {
166 if ( $size['success'] ) {
167 $count++;
168 }
169 }
170
171 return (int) $count;
172 }
173
174 /**
175 * Get the attachment optimization status (success or error).
176 *
177 * @since 1.0
178 *
179 * @access public
180 * @return string
181 */
182 public function get_status() {
183 return get_post_meta( $this->id, '_imagify_status', true );
184 }
185
186 /**
187 * Get the original attachment path.
188 *
189 * @since 1.0
190 *
191 * @access public
192 * @return string
193 */
194 public function get_original_path() {
195 return get_attached_file( $this->id );
196 }
197
198 /**
199 * Get the original attachment size.
200 *
201 * @since 1.0
202 *
203 * @access public
204 * @return string
205 */
206 public function get_original_size() {
207 $original_size = $this->get_size_data( 'full', 'original_size' );
208 $original_size = ( empty( $original_size ) ) ? @filesize( $this->get_original_path() ) : $original_size;
209 $original_size = size_format( $original_size, 2 );
210
211 return $original_size;
212 }
213
214 /**
215 * Get the original attachment URL.
216 *
217 * @since 1.0
218 *
219 * @access public
220 * @return string
221 */
222 public function get_original_url() {
223 return wp_get_attachment_url( $this->id );
224 }
225
226 /*
227 * Get the statistics of a specific size.
228 *
229 * @since 1.0
230 *
231 * @access public
232 * @param string $size The thumbnail slug.
233 * @param string $key The specific data slug.
234 * @return array|string
235 */
236 public function get_size_data( $size = 'full', $key = '' ) {
237 $data = $this->get_data();
238 $stats = array();
239
240 if ( isset( $data['sizes'][ $size ] ) ) {
241 $stats = $data['sizes'][ $size ];
242 }
243
244 if ( isset( $stats[ $key ] ) ) {
245 $stats = $stats[ $key ];
246 }
247
248 return $stats;
249 }
250
251 /**
252 * Get the global statistics data or a specific one.
253 *
254 * @since 1.0
255 *
256 * @access public
257 * @param string $key The specific data slug.
258 * @return array|string
259 */
260 public function get_stats_data( $key = '' ) {
261 $data = $this->get_data();
262 $stats = '';
263
264 if ( isset( $data['stats'] ) ) {
265 $stats = $data['stats'];
266 }
267
268 if ( isset( $stats[ $key ] ) ) {
269 $stats = $stats[ $key ];
270 }
271
272 return $stats;
273 }
274
275 /**
276 * Check if the attachment is already optimized (before Imagify).
277 *
278 * @since 1.1.6
279 *
280 * @access public
281 * @return bool True if the attachment is optimized.
282 */
283 public function is_already_optimized() {
284 return ( 'already_optimized' === $this->get_status() ) > 0;
285 }
286
287 /**
288 * Check if the attachment is optimized.
289 *
290 * @since 1.0
291 *
292 * @access public
293 * @return bool True if the attachment is optimized.
294 */
295 public function is_optimized() {
296 return ( 'success' === $this->get_status() ) > 0;
297 }
298
299 /**
300 * Check if the attachment exceeding the limit size (> 5mo).
301 *
302 * @since 1.0
303 *
304 * @access public
305 * @return bool True if the attachment is skipped.
306 */
307 public function is_exceeded() {
308 $filepath = $this->get_original_path();
309 $size = 0;
310
311 if ( file_exists( $filepath ) ) {
312 $size = filesize( $filepath );
313 }
314
315 return ( $size > IMAGIFY_MAX_BYTES ) > 0;
316 }
317
318 /**
319 * Check if the attachment has a backup of the original size.
320 *
321 * @since 1.0
322 *
323 * @access public
324 * @return bool True if the attachment has a backup.
325 */
326 public function has_backup() {
327 return (bool) $this->get_backup_path();
328 }
329
330 /**
331 * Check if the attachment has an error.
332 *
333 * @since 1.0
334 *
335 * @access public
336 * @return bool True if the attachment has an error.
337 */
338 public function has_error() {
339 $has_error = $this->get_size_data( 'full', 'error' );
340 return ( is_string( $has_error ) ) > 0;
341 }
342
343 /**
344 * Update the metadata size of the attachment
345 *
346 * @since 1.2
347 *
348 * @access public
349 * @return void
350 */
351 public function update_metadata_size() {
352 if ( ! wp_attachment_is_image( $this->id ) ) {
353 return false;
354 }
355
356 $size = @getimagesize( $this->get_original_path() );
357
358 if ( isset( $size[0], $size[1] ) ) {
359 $metadata = wp_get_attachment_metadata( $this->id );
360 $metadata['width'] = $size[0];
361 $metadata['height'] = $size[1];
362
363 wp_update_attachment_metadata( $this->id, $metadata );
364 }
365 }
366
367 /**
368 * Delete the backup file.
369 *
370 * @since 1.0
371 *
372 * @access public
373 * @return void
374 */
375 public function delete_backup() {
376 $backup_path = $this->get_backup_path();
377
378 if ( ! empty( $backup_path ) ) {
379 @unlink( $backup_path );
380 }
381 }
382
383 /**
384 * Fills statistics data with values from $data array
385 *
386 * @since 1.0
387 *
388 * @access public
389 * @static
390 * @param array $data The statistics data
391 * @param object $response The API response
392 * @param int $id The attachment ID
393 * @param int $url The attachment URL
394 * @param string $size The attachment size key
395 * @return bool|array False if the original size has an error or an array contains the data for other result
396 */
397 static public function fill_data( $data, $response, $id, $url, $size = 'full' ) {
398 if ( is_wp_error( $response ) ) {
399 $error = $response->get_error_message();
400 $error_status = 'error';
401
402 $data['sizes'][ $size ] = array(
403 'success' => false,
404 'error' => $error
405 );
406
407 // Update the error status for the original size
408 if ( 'full' === $size ) {
409 update_post_meta( $id, '_imagify_data', $data );
410
411 if ( false !== strpos( $error, 'This image is already compressed' ) ) {
412 $error_status = 'already_optimized';
413 }
414
415 update_post_meta( $id, '_imagify_status', $error_status );
416
417 return false;
418 }
419 } else {
420 $data['sizes'][ $size ] = array(
421 'success' => true,
422 'file_url' => $url,
423 'original_size' => $response->original_size,
424 'optimized_size' => $response->new_size,
425 'percent' => $response->percent
426 );
427
428 $data['stats']['original_size'] += ( isset( $response->original_size ) ) ? $response->original_size : 0;
429 $data['stats']['optimized_size'] += ( isset( $response->new_size ) ) ? $response->new_size : 0;
430 }
431
432 return $data;
433 }
434
435 /**
436 * Optimize all sizes with Imagify.
437 *
438 * @since 1.0
439 *
440 * @access public
441 * @param int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal)
442 * @param array $metadata The attachment meta data
443 * @return array $optimized_data The optimization data
444 */
445 public function optimize( $optimization_level = null, $metadata = array() ) {
446 $optimization_level = ( is_null( $optimization_level ) ) ? (int) get_imagify_option( 'optimization_level', 1 ) : (int) $optimization_level;
447
448 $id = $this->id;
449 $metadata = ( (bool) $metadata ) ? $metadata : wp_get_attachment_metadata( $id );
450 $sizes = ( isset( $metadata['sizes'] ) ) ? (array) $metadata['sizes'] : array();
451 $data = array(
452 'stats' => array(
453 'original_size' => 0,
454 'optimized_size' => 0,
455 'percent' => 0,
456 )
457 );
458
459 // Get file path & URL for original image
460 $attachment_path = $this->get_original_path();
461 $attachment_url = $this->get_original_url();
462
463 // Check if the attachment extension is allowed
464 if ( ! $id || ! wp_attachment_is_image( $id ) ) {
465 return;
466 }
467
468 // Check if the full size is already optimized
469 if ( $this->is_optimized() && ( $this->get_optimization_level() == $optimization_level ) ) {
470 delete_transient( 'imagify-async-in-progress-' . $id );
471 return;
472 }
473
474 /**
475 * Fires before optimizing an attachment.
476 *
477 * @since 1.0
478 *
479 * @param int $id The attachment ID
480 */
481 do_action( 'before_imagify_optimize_attachment', $id );
482
483 // Get the resize values for the original size
484 $resize = array();
485 $do_resize = get_imagify_option( 'resize_larger', false );
486 $resize_width = get_imagify_option( 'resize_larger_w' );
487 $attachment_size = @getimagesize( $attachment_path );
488
489 if ( $do_resize && isset( $attachment_size[0] ) && $resize_width < $attachment_size[0] ) {
490 $resize['width'] = $resize_width;
491 }
492
493 // Optimize the original size
494 $response = do_imagify( $attachment_path, get_imagify_option( 'backup', false ), $optimization_level, $resize, get_imagify_option( 'exif', false ) );
495 $data = $this->fill_data( $data, $response, $id, $attachment_url );
496
497 // Save the optimization level
498 update_post_meta( $id, '_imagify_optimization_level', $optimization_level );
499
500 if( (bool) ! $data ) {
501 delete_transient( 'imagify-async-in-progress-' . $id );
502 return;
503 }
504
505 // If we resized the original with success, we have to update the attachment metadata
506 // If not, WordPress keeps the old attachment size.
507 if ( $do_resize && isset( $resize['width'] ) ) {
508 $this->update_metadata_size();
509 }
510
511 // Optimize all thumbnails
512 if ( (bool) $sizes ) {
513 foreach ( $sizes as $size_key => $size_data ) {
514 // Check if this size has to be optimized
515 if ( array_key_exists( $size_key, get_imagify_option( 'disallowed-sizes', array() ) ) && ! imagify_is_active_for_network() ) {
516 $data['sizes'][ $size_key ] = array(
517 'success' => false,
518 'error' => __( 'This size isn\'t authorized to be optimized. Update your Imagify settings if you want to optimize it.', 'imagify' )
519 );
520 continue;
521 }
522
523 $thumbnail_path = trailingslashit( dirname( $attachment_path ) ) . $size_data['file'];
524 $thumbnail_url = trailingslashit( dirname( $attachment_url ) ) . $size_data['file'];
525
526 // Optimize the thumbnail size
527 $response = do_imagify( $thumbnail_path, false, $optimization_level );
528 $data = $this->fill_data( $data, $response, $id, $thumbnail_url, $size_key );
529
530 /**
531 * Filter the optimization data of a specific thumbnail
532 *
533 * @since 1.0
534 *
535 * @param array $data The statistics data
536 * @param object $response The API response
537 * @param int $id The attachment ID
538 * @param string $thumbnail_path The attachment path
539 * @param string $thumbnail_url The attachment URL
540 * @param string $size_key The attachment size key
541 * @param bool $is_aggressive The optimization level
542 * @return array $data The new optimization data
543 */
544 $data = apply_filters( 'imagify_fill_thumbnail_data', $data, $response, $id, $thumbnail_path, $thumbnail_url, $size_key, $optimization_level );
545 }
546 }
547
548 $data['stats']['percent'] = round( ( ( $data['stats']['original_size'] - $data['stats']['optimized_size'] ) / $data['stats']['original_size'] ) * 100, 2 );
549
550 update_post_meta( $id, '_imagify_data', $data );
551 update_post_meta( $id, '_imagify_status', 'success' );
552
553 $optimized_data = $this->get_data();
554
555 /**
556 * Fires after optimizing an attachment.
557 *
558 * @since 1.0
559 *
560 * @param int $id The attachment ID
561 * @param array $optimized_data The optimization data
562 */
563 do_action( 'after_imagify_optimize_attachment', $id, $optimized_data );
564
565 delete_transient( 'imagify-async-in-progress-' . $id );
566
567 return $optimized_data;
568 }
569
570 /**
571 * Process an attachment restoration from the backup file.
572 *
573 * @since 1.0
574 *
575 * @access public
576 * @return void
577 */
578 public function restore() {
579 // Stop the process if there is no backup file to restore
580 if ( ! $this->has_backup() ) {
581 return;
582 }
583
584 $id = $this->id;
585 $backup_path = $this->get_backup_path();
586 $attachment_path = $this->get_original_path();
587
588 /**
589 * Fires before restoring an attachment.
590 *
591 * @since 1.0
592 *
593 * @param int $id The attachment ID
594 */
595 do_action( 'before_imagify_restore_attachment', $id );
596
597 // Create the original image from the backup
598 @copy( $backup_path, $attachment_path );
599 imagify_chmod_file( $attachment_path );
600
601 if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) {
602 require_once( ABSPATH . 'wp-admin/includes/image.php' );
603 }
604
605 remove_filter( 'wp_generate_attachment_metadata', '_imagify_optimize_attachment', PHP_INT_MAX );
606 wp_generate_attachment_metadata( $id, $attachment_path );
607
608 // Remove old optimization data
609 delete_post_meta( $id, '_imagify_data' );
610 delete_post_meta( $id, '_imagify_status' );
611 delete_post_meta( $id, '_imagify_optimization_level' );
612
613 // Restore the original size in the metadata
614 $this->update_metadata_size();
615
616 /**
617 * Fires after restoring an attachment.
618 *
619 * @since 1.0
620 *
621 * @param int $id The attachment ID
622 */
623 do_action( 'after_imagify_restore_attachment', $id );
624 }
625 }