PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / trunk
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF vtrunk
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 / deprecated / classes / class-imagify-abstract-attachment.php

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

1,238 lines 27.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
3
4 /**
5 * Imagify Attachment base class.
6 *
7 * @since 1.0
8 * @since 1.9 Deprecated
9 * @deprecated
10 */
11 abstract class Imagify_Abstract_Attachment {
12
13 /**
14 * Class version.
15 *
16 * @var string
17 */
18 const VERSION = '1.3.2';
19
20 /**
21 * The attachment ID.
22 *
23 * @var int
24 * @since 1.0
25 * @access public
26 */
27 public $id = 0;
28
29 /**
30 * Context.
31 *
32 * @var string
33 * @since 1.7.1
34 * @access protected
35 * @author Grégory Viguier
36 */
37 protected $context;
38
39 /**
40 * The attachment SQL DB class.
41 *
42 * @var string
43 * @since 1.7
44 * @access protected
45 */
46 protected $db_class_name = '';
47
48 /**
49 * The attachment SQL data row.
50 *
51 * @var array
52 * @since 1.7
53 * @access protected
54 */
55 protected $row;
56
57 /**
58 * Tell if the file is an image.
59 *
60 * @var bool
61 * @since 1.8
62 * @access protected
63 * @see $this->is_image()
64 */
65 protected $is_image;
66
67 /**
68 * Tell if the file is a pdf.
69 *
70 * @var bool
71 * @since 1.8
72 * @access protected
73 * @see $this->is_pdf()
74 */
75 protected $is_pdf;
76
77 /**
78 * Stores the file extension (even if the extension is not supported by Imagify).
79 *
80 * @var string|null
81 * @since 1.8
82 * @access protected
83 * @see $this->get_extension()
84 */
85 protected $extension = false;
86
87 /**
88 * Stores the file mime type + file extension (if the file is supported).
89 *
90 * @var array
91 * @since 1.8
92 * @access protected
93 * @see $this->get_file_type()
94 */
95 protected $file_type;
96
97 /**
98 * Filesystem object.
99 *
100 * @var object Imagify_Filesystem
101 * @since 1.7.1
102 * @access protected
103 * @author Grégory Viguier
104 */
105 protected $filesystem;
106
107 /**
108 * The editor instances used to resize files.
109 *
110 * @var array An array of image editor objects (WP_Image_Editor_Imagick, WP_Image_Editor_GD).
111 * @since 1.7.1
112 * @access protected
113 * @author Grégory Viguier
114 */
115 protected $editors = array();
116
117 /**
118 * The name of the transient that tells if optimization is processing.
119 *
120 * @var string
121 * @since 1.7.1
122 * @access protected
123 * @author Grégory Viguier
124 */
125 protected $optimization_state_transient;
126
127 /**
128 * Tell if the optimization status is network-wide.
129 *
130 * @var bool
131 * @since 1.7.1
132 * @access protected
133 * @author Grégory Viguier
134 */
135 protected $optimization_state_network_wide = false;
136
137 /**
138 * The constructor.
139 *
140 * @since 1.0
141 * @access public
142 *
143 * @param int|object $id The attachment ID or the attachment itself.
144 * If an integer, make sure the attachment exists.
145 */
146 public function __construct( $id = 0 ) {
147 global $post;
148
149 if ( $id ) {
150 if ( $id instanceof WP_Post ) {
151 $this->id = $id->ID;
152 } elseif ( is_numeric( $id ) ) {
153 $this->id = $id;
154 }
155 } elseif ( $post && $id instanceof WP_Post ) {
156 $this->id = $post->ID;
157 }
158
159 $this->id = (int) $this->id;
160 $this->filesystem = Imagify_Filesystem::get_instance();
161 $this->optimization_state_transient = 'wp' !== $this->get_context() ? strtolower( $this->get_context() ) . '-' : '';
162 $this->optimization_state_transient = 'imagify-' . $this->optimization_state_transient . 'async-in-progress-' . $this->id;
163 }
164
165 /**
166 * Get the attachment context.
167 *
168 * @since 1.7.1
169 * @access public
170 * @author Grégory Viguier
171 *
172 * @return string
173 */
174 public function get_context() {
175 if ( $this->context ) {
176 return $this->context;
177 }
178
179 $this->context = str_replace( array( 'Imagify_', 'Attachment' ), '', get_class( $this ) );
180 $this->context = trim( $this->context, '_' );
181 $this->context = $this->context ? $this->context : 'wp';
182
183 return $this->context;
184 }
185
186 /**
187 * Tell if the current attachment is valid.
188 *
189 * @since 1.7
190 * @author Grégory Viguier
191 * @access public
192 *
193 * @return bool
194 */
195 public function is_valid() {
196 return $this->id > 0;
197 }
198
199 /**
200 * Get the attachment ID.
201 *
202 * @since 1.7
203 * @author Grégory Viguier
204 * @access public
205 *
206 * @return int
207 */
208 public function get_id() {
209 return $this->id;
210 }
211
212 /**
213 * Get the original attachment path.
214 *
215 * @since 1.0
216 * @access public
217 *
218 * @return string
219 */
220 abstract public function get_original_path();
221
222 /**
223 * Get the original attachment URL.
224 *
225 * @since 1.0
226 * @access public
227 *
228 * @return string
229 */
230 abstract public function get_original_url();
231
232 /**
233 * Get the attachment backup file path, even if the file doesn't exist.
234 *
235 * @since 1.6.13
236 * @access public
237 * @author Grégory Viguier
238 *
239 * @return string|bool The file path. False on failure.
240 */
241 abstract public function get_raw_backup_path();
242
243 /**
244 * Get the attachment backup file path.
245 *
246 * @since 1.0
247 * @access public
248 *
249 * @return string|false The file path. False if it doesn't exist.
250 */
251 public function get_backup_path() {
252 if ( ! $this->is_valid() ) {
253 return false;
254 }
255
256 $backup_path = $this->get_raw_backup_path();
257
258 if ( $backup_path && $this->filesystem->exists( $backup_path ) ) {
259 return $backup_path;
260 }
261
262 return false;
263 }
264
265 /**
266 * Get the attachment backup URL.
267 *
268 * @since 1.4
269 * @access public
270 *
271 * @return string|false
272 */
273 public function get_backup_url() {
274 if ( ! $this->is_valid() ) {
275 return false;
276 }
277
278 return get_imagify_attachment_url( $this->get_raw_backup_path() );
279 }
280
281 /**
282 * Get the attachment optimization data.
283 *
284 * @since 1.0
285 * @access public
286 *
287 * @return array
288 */
289 abstract public function get_data();
290
291 /**
292 * Get the attachment optimization level.
293 *
294 * @since 1.0
295 * @access public
296 *
297 * @return int
298 */
299 abstract public function get_optimization_level();
300
301 /**
302 * Get the attachment optimization status (success or error).
303 *
304 * @since 1.0
305 * @access public
306 *
307 * @return string
308 */
309 abstract public function get_status();
310
311 /**
312 * Get the attachment error if there is one.
313 *
314 * @since 1.1.5
315 * @access public
316 *
317 * @return string The message error
318 */
319 public function get_optimized_error() {
320 $error = $this->get_size_data( 'full', 'error' );
321
322 if ( is_string( $error ) ) {
323 return trim( $error );
324 }
325
326 return '';
327 }
328
329 /**
330 * Count number of optimized sizes.
331 *
332 * @since 1.0
333 * @access public
334 *
335 * @return int
336 */
337 public function get_optimized_sizes_count() {
338 $data = $this->get_data();
339 $sizes = ! empty( $data['sizes'] ) && is_array( $data['sizes'] ) ? $data['sizes'] : array();
340 $count = 0;
341
342 unset( $sizes['full'] );
343
344 if ( ! $sizes ) {
345 return 0;
346 }
347
348 foreach ( $sizes as $size ) {
349 if ( ! empty( $size['success'] ) ) {
350 $count++;
351 }
352 }
353
354 return $count;
355 }
356
357 /**
358 * Delete the 3 metas used by Imagify.
359 *
360 * @since 1.6.6
361 * @access public
362 * @author Grégory Viguier
363 */
364 public function delete_imagify_data() {
365 if ( ! $this->is_valid() ) {
366 return;
367 }
368
369 delete_post_meta( $this->id, '_imagify_data' );
370 delete_post_meta( $this->id, '_imagify_status' );
371 delete_post_meta( $this->id, '_imagify_optimization_level' );
372 }
373
374 /**
375 * Get width and height of the original image.
376 *
377 * @since 1.7
378 * @author Grégory Viguier
379 * @access public
380 *
381 * @return array
382 */
383 public function get_dimensions() {
384 return array(
385 'width' => 0,
386 'height' => 0,
387 );
388 }
389
390 /**
391 * Tell if the current item refers to an image, based on file extension.
392 *
393 * @since 1.8
394 * @access public
395 * @author Grégory Viguier
396 *
397 * @return bool Returns false in case it's an image but not in a supported format (bmp for example).
398 */
399 public function is_image() {
400 if ( isset( $this->is_image ) ) {
401 return $this->is_image;
402 }
403
404 $this->is_image = strpos( (string) $this->get_mime_type(), 'image/' ) === 0;
405
406 return $this->is_image;
407 }
408
409 /**
410 * Tell if the current item refers to a pdf, based on file extension.
411 *
412 * @since 1.8
413 * @access public
414 * @author Grégory Viguier
415 *
416 * @return bool
417 */
418 public function is_pdf() {
419 if ( isset( $this->is_pdf ) ) {
420 return $this->is_pdf;
421 }
422
423 $this->is_pdf = 'application/pdf' === $this->get_mime_type();
424
425 return $this->is_pdf;
426 }
427
428 /**
429 * Get the file mime type.
430 *
431 * @since 1.8
432 * @access public
433 * @author Grégory Viguier
434 *
435 * @return bool
436 */
437 public function get_mime_type() {
438 return $this->get_file_type()->type;
439 }
440
441 /**
442 * Get the file mime type + file extension (if the file is supported).
443 *
444 * @since 1.8
445 * @access public
446 * @see wp_check_filetype()
447 * @author Grégory Viguier
448 *
449 * @return object
450 */
451 public function get_file_type() {
452 if ( isset( $this->file_type ) ) {
453 return $this->file_type;
454 }
455
456 if ( ! $this->is_valid() ) {
457 $this->file_type = (object) array(
458 'ext' => '',
459 'type' => '',
460 );
461 return $this->file_type;
462 }
463
464 $path = $this->get_original_path();
465
466 if ( ! $path ) {
467 $this->file_type = (object) array(
468 'ext' => '',
469 'type' => '',
470 );
471 return $this->file_type;
472 }
473
474 $this->file_type = (object) wp_check_filetype( $path, imagify_get_mime_types() );
475
476 return $this->file_type;
477 }
478
479 /**
480 * Get the attachment extension.
481 *
482 * @since 1.0
483 * @access public
484 *
485 * @return string|null
486 */
487 public function get_extension() {
488 if ( false !== $this->extension ) {
489 return $this->extension;
490 }
491
492 if ( ! $this->is_valid() ) {
493 $this->extension = null;
494 return $this->extension;
495 }
496
497 $this->extension = $this->filesystem->path_info( $this->get_original_path(), 'extension' );
498
499 return $this->extension;
500 }
501
502 /**
503 * Tell if the current file extension is supported.
504 *
505 * @since 1.7
506 * @access public
507 * @author Grégory Viguier
508 *
509 * @return bool
510 */
511 public function is_extension_supported() {
512 return (bool) $this->get_file_type()->ext;
513 }
514
515 /**
516 * Tell if the current file mime type is supported.
517 *
518 * @since 1.6.9
519 * @since 1.8 Does the same has this->is_extension_supported().
520 * @access public
521 * @author Grégory Viguier
522 *
523 * @return bool
524 */
525 public function is_mime_type_supported() {
526 return (bool) $this->get_mime_type();
527 }
528
529 /**
530 * Tell if the current attachment has the required WP metadata.
531 *
532 * @since 1.6.12
533 * @access public
534 * @author Grégory Viguier
535 *
536 * @return bool
537 */
538 public function has_required_metadata() {
539 if ( ! $this->is_valid() ) {
540 return false;
541 }
542
543 return imagify_attachment_has_required_metadata( $this->id );
544 }
545
546 /**
547 * Get the attachment optimization level label.
548 *
549 * @since 1.2
550 * @since 1.7 Added $format parameter.
551 * @access public
552 *
553 * @param string $format Format to display the label. Use %ICON% for the icon and %s for the label.
554 * @return string
555 */
556 public function get_optimization_level_label( $format = '%s' ) {
557 return imagify_get_optimization_level_label( $this->get_optimization_level(), $format );
558 }
559
560 /**
561 * Get the original attachment size.
562 *
563 * @since 1.0
564 * @access public
565 *
566 * @param bool $human_format True to display the image human format size (1Mb).
567 * @param int $decimals Precision of number of decimal places.
568 * @return string|int
569 */
570 public function get_original_size( $human_format = true, $decimals = 2 ) {
571 if ( ! $this->is_valid() ) {
572 return $human_format ? imagify_size_format( 0, $decimals ) : 0;
573 }
574
575 $size = $this->get_size_data( 'full', 'original_size' );
576
577 if ( ! $size ) {
578 // Check for the backup file first.
579 $filepath = $this->get_backup_path();
580
581 if ( ! $filepath ) {
582 $filepath = $this->get_original_path();
583 $filepath = $filepath && $this->filesystem->exists( $filepath ) ? $filepath : false;
584 }
585
586 $size = $filepath ? $this->filesystem->size( $filepath ) : 0;
587 }
588
589 if ( $human_format ) {
590 return imagify_size_format( (int) $size, $decimals );
591 }
592
593 return (int) $size;
594 }
595
596 /**
597 * Get the optimized attachment size.
598 *
599 * @since 1.7
600 * @access public
601 * @author Grégory Viguier
602 *
603 * @param bool $human_format True to display the image human format size (1Mb).
604 * @param int $decimals Precision of number of decimal places.
605 * @return string|int
606 */
607 public function get_optimized_size( $human_format = true, $decimals = 2 ) {
608 if ( ! $this->is_valid() ) {
609 return $human_format ? imagify_size_format( 0, $decimals ) : 0;
610 }
611
612 $size = $this->get_size_data( 'full', 'optimized_size' );
613
614 if ( ! $size ) {
615 $filepath = $this->get_original_path();
616 $filepath = $filepath && $this->filesystem->exists( $filepath ) ? $filepath : false;
617 $size = $filepath ? $this->filesystem->size( $filepath ) : 0;
618 }
619
620 if ( $human_format ) {
621 return imagify_size_format( (int) $size, $decimals );
622 }
623
624 return (int) $size;
625 }
626
627 /**
628 * Get the optimized attachment size.
629 *
630 * @since 1.7
631 * @access public
632 * @author Grégory Viguier
633 *
634 * @return float A 2-decimals float.
635 */
636 public function get_saving_percent() {
637 if ( ! $this->is_valid() ) {
638 return round( (float) 0, 2 );
639 }
640
641 $percent = $this->get_size_data( 'full', 'percent' );
642 $percent = $percent ? $percent : (float) 0;
643
644 return round( $percent, 2 );
645 }
646
647 /**
648 * Get the overall optimized size (all thumbnails).
649 *
650 * @since 1.7
651 * @access public
652 * @author Grégory Viguier
653 *
654 * @return float A 2-decimals float.
655 */
656 public function get_overall_saving_percent() {
657 if ( ! $this->is_valid() ) {
658 return round( (float) 0, 2 );
659 }
660
661 $percent = $this->get_data();
662 $percent = ! empty( $percent['stats']['percent'] ) ? $percent['stats']['percent'] : (float) 0;
663
664 return round( $percent, 2 );
665 }
666
667 /**
668 * Get the statistics of a specific size.
669 *
670 * @since 1.0
671 * @access public
672 *
673 * @param string $size The thumbnail slug.
674 * @param string $key The specific data slug.
675 * @return array|string
676 */
677 public function get_size_data( $size = 'full', $key = '' ) {
678 $data = $this->get_data();
679 $stats = array();
680
681 if ( isset( $data['sizes'][ $size ] ) ) {
682 $stats = $data['sizes'][ $size ];
683 }
684
685 if ( isset( $stats[ $key ] ) ) {
686 $stats = $stats[ $key ];
687 }
688
689 return $stats;
690 }
691
692 /**
693 * Get the global statistics data or a specific one.
694 *
695 * @since 1.0
696 * @access public
697 *
698 * @param string $key The specific data slug.
699 * @return array|string
700 */
701 public function get_stats_data( $key = '' ) {
702 $data = $this->get_data();
703 $stats = '';
704
705 if ( isset( $data['stats'] ) ) {
706 $stats = $data['stats'];
707 }
708
709 if ( isset( $stats[ $key ] ) ) {
710 $stats = $stats[ $key ];
711 }
712
713 return $stats;
714 }
715
716 /**
717 * Check if the attachment is already optimized (before Imagify).
718 *
719 * @since 1.1.6
720 * @access public
721 *
722 * @return bool True if the attachment is optimized.
723 */
724 public function is_already_optimized() {
725 return 'already_optimized' === $this->get_status();
726 }
727
728 /**
729 * Check if the attachment is optimized.
730 *
731 * @since 1.0
732 * @access public
733 *
734 * @return bool True if the attachment is optimized.
735 */
736 public function is_optimized() {
737 return 'success' === $this->get_status();
738 }
739
740 /**
741 * Check if the attachment exceeding the limit size (> 5mo).
742 *
743 * @since 1.0
744 * @access public
745 *
746 * @return bool True if the attachment is skipped.
747 */
748 public function is_exceeded() {
749 $filepath = $this->get_original_path();
750 $size = 0;
751
752 if ( $filepath && $this->filesystem->exists( $filepath ) ) {
753 $size = $this->filesystem->size( $filepath );
754 }
755
756 return $size > IMAGIFY_MAX_BYTES;
757 }
758
759 /**
760 * Check if the attachment has a backup of the original size.
761 *
762 * @since 1.0
763 * @access public
764 *
765 * @return bool True if the attachment has a backup.
766 */
767 public function has_backup() {
768 return (bool) $this->get_backup_path();
769 }
770
771 /**
772 * Check if the attachment has an error.
773 *
774 * @since 1.0
775 * @access public
776 *
777 * @return bool True if the attachment has an error.
778 */
779 public function has_error() {
780 return 'error' === $this->get_status();
781 }
782
783 /**
784 * Get an image editor instance (WP_Image_Editor_Imagick, WP_Image_Editor_GD).
785 *
786 * @since 1.7.1
787 * @access protected
788 * @author Grégory Viguier
789 *
790 * @param string $path A file path.
791 * @return object An image editor instance (WP_Image_Editor_Imagick, WP_Image_Editor_GD). A WP_Error object on error.
792 */
793 protected function get_editor( $path ) {
794 if ( isset( $this->editors[ $path ] ) ) {
795 return $this->editors[ $path ];
796 }
797
798 $this->editors[ $path ] = wp_get_image_editor( $path, array(
799 'methods' => self::get_editor_methods(),
800 ) );
801
802 return $this->editors[ $path ];
803 }
804
805 /**
806 * Get the image editor methods we will use.
807 *
808 * @since 1.7.1
809 * @access public
810 * @author Grégory Viguier
811 *
812 * @return array
813 */
814 public static function get_editor_methods() {
815 static $methods;
816
817 if ( isset( $methods ) ) {
818 return $methods;
819 }
820
821 $methods = array(
822 'resize',
823 'multi_resize',
824 'generate_filename',
825 'save',
826 );
827
828 if ( Imagify_Filesystem::get_instance()->can_get_exif() ) {
829 $methods[] = 'rotate';
830 }
831
832 return $methods;
833 }
834
835 /**
836 * Update the metadata size of the attachment
837 *
838 * @since 1.2
839 * @access public
840 *
841 * @return void
842 */
843 abstract public function update_metadata_size();
844
845 /**
846 * Delete the backup file.
847 *
848 * @since 1.0
849 * @access public
850 *
851 * @return void
852 */
853 public function delete_backup() {
854 $backup_path = $this->get_backup_path();
855
856 if ( $backup_path ) {
857 $this->filesystem->delete( $backup_path );
858 }
859 }
860
861 /**
862 * Get the registered sizes.
863 *
864 * @since 1.6.10
865 * @access public
866 * @author Grégory Viguier
867 *
868 * @return array Data for the registered thumbnail sizes.
869 */
870 public static function get_registered_sizes() {
871 static $registered_sizes;
872
873 if ( ! isset( $registered_sizes ) ) {
874 $registered_sizes = get_imagify_thumbnail_sizes();
875 }
876
877 return $registered_sizes;
878 }
879
880 /**
881 * Get the unoptimized sizes for a specific attachment.
882 *
883 * @since 1.6.10
884 * @access public
885 * @author Grégory Viguier
886 *
887 * @return array Data for the unoptimized thumbnail sizes.
888 * Each size data has a "file" key containing the name the thumbnail "should" have.
889 */
890 public function get_unoptimized_sizes() {
891 // The attachment must have been optimized once and have a backup.
892 if ( ! $this->is_valid() || ! $this->is_optimized() || ! $this->has_backup() || ! $this->is_image() ) {
893 return array();
894 }
895
896 $registered_sizes = self::get_registered_sizes();
897 $attachment_sizes = $this->get_data();
898 $attachment_sizes = ! empty( $attachment_sizes['sizes'] ) ? $attachment_sizes['sizes'] : array();
899 $missing_sizes = array_diff_key( $registered_sizes, $attachment_sizes );
900
901 if ( ! $missing_sizes ) {
902 // We have everything we need.
903 return array();
904 }
905
906 // Get full size dimensions.
907 $orig = wp_get_attachment_metadata( $this->id );
908 $orig_f = ! empty( $orig['file'] ) ? $orig['file'] : '';
909 $orig_w = ! empty( $orig['width'] ) ? (int) $orig['width'] : 0;
910 $orig_h = ! empty( $orig['height'] ) ? (int) $orig['height'] : 0;
911
912 if ( ! $orig_f || ! $orig_w || ! $orig_h ) {
913 return array();
914 }
915
916 $orig_f = $this->filesystem->path_info( $orig_f );
917 $orig_f = $orig_f['file_base'] . '-{%suffix%}.' . $orig_f['extension'];
918
919 // Test if the missing sizes are needed.
920 $disallowed_sizes = get_imagify_option( 'disallowed-sizes' );
921 $is_active_for_network = imagify_is_active_for_network();
922
923 foreach ( $missing_sizes as $size_name => $size_data ) {
924 $duplicate = ( $orig_w === $size_data['width'] ) && ( $orig_h === $size_data['height'] );
925
926 if ( $duplicate ) {
927 // Same dimensions as the full size.
928 unset( $missing_sizes[ $size_name ] );
929 continue;
930 }
931
932 if ( ! $is_active_for_network && isset( $disallowed_sizes[ $size_name ] ) ) {
933 // This size must be optimized.
934 unset( $missing_sizes[ $size_name ] );
935 continue;
936 }
937
938 $resize_result = image_resize_dimensions( $orig_w, $orig_h, $size_data['width'], $size_data['height'], $size_data['crop'] );
939
940 if ( ! $resize_result ) {
941 // This size is not needed.
942 unset( $missing_sizes[ $size_name ] );
943 continue;
944 }
945
946 // Provide what should be the file name.
947 list( , , , , $dst_w, $dst_h ) = $resize_result;
948 $missing_sizes[ $size_name ]['file'] = str_replace( '{%suffix%}', "{$dst_w}x{$dst_h}", $orig_f );
949 }
950
951 return $missing_sizes;
952 }
953
954 /**
955 * Fills statistics data with values from $data array.
956 *
957 * @since 1.0
958 * @since 1.6.5 Not static anymore.
959 * @since 1.6.6 Removed the attachment ID parameter.
960 * @since 1.7 Removed the image URL parameter.
961 * @access public
962 *
963 * @param array $data The statistics data.
964 * @param object $response The API response.
965 * @param string $size The attachment size key.
966 * @return bool|array False if the original size has an error or an array contains the data for other result.
967 */
968 abstract public function fill_data( $data, $response, $size = 'full' );
969
970 /**
971 * Optimize all sizes with Imagify.
972 *
973 * @since 1.0
974 * @access public
975 *
976 * @param int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal).
977 * @param array $metadata The attachment meta data.
978 * @return array $optimized_data The optimization data.
979 */
980 abstract public function optimize( $optimization_level = null, $metadata = array() );
981
982 /**
983 * Optimize missing sizes with Imagify.
984 *
985 * @since 1.6.10
986 * @access public
987 * @author Grégory Viguier
988 *
989 * @param int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal).
990 * @return array|object An array of thumbnail data, size by size. A WP_Error object on failure.
991 */
992 abstract public function optimize_missing_thumbnails( $optimization_level = null );
993
994 /**
995 * Re-optimize the given thumbnail sizes to the same level.
996 * Before doing this, the given sizes must be restored.
997 *
998 * @since 1.7.1
999 * @access public
1000 * @author Grégory Viguier
1001 *
1002 * @param array $sizes The sizes to optimize.
1003 * @return array|void A WP_Error object on failure.
1004 */
1005 abstract public function reoptimize_thumbnails( $sizes );
1006
1007 /**
1008 * Process an attachment restoration from the backup file.
1009 *
1010 * @since 1.0
1011 * @access public
1012 *
1013 * @return void
1014 */
1015 abstract public function restore();
1016
1017 /**
1018 * Resize an image if bigger than the maximum width defined in the settings.
1019 *
1020 * @since 1.5.7
1021 * @since 1.7.1 Keys for width and height in $attachment_sizes are now 'width' and 'height' instead of 0 and 1.
1022 * @access public
1023 * @author Remy Perona
1024 *
1025 * @param string $attachment_path Path to the image.
1026 * @param array $attachment_sizes Array of original image dimensions.
1027 * @param int $max_width Maximum width defined in the settings.
1028 * @return string Path the the resized image or the original image if the resize failed.
1029 */
1030 public function resize( $attachment_path, $attachment_sizes, $max_width ) {
1031 if ( ! $this->is_valid() || ! $this->is_image() ) {
1032 return '';
1033 }
1034
1035 $editor = $this->get_editor( $attachment_path );
1036
1037 if ( is_wp_error( $editor ) ) {
1038 return $editor;
1039 }
1040
1041 $new_sizes = wp_constrain_dimensions( $attachment_sizes['width'], $attachment_sizes['height'], $max_width );
1042 $image_type = strtolower( (string) $this->filesystem->path_info( $attachment_path, 'extension' ) );
1043
1044 // Try to correct for auto-rotation if the info is available.
1045 if ( $this->filesystem->can_get_exif() && ( 'jpg' === $image_type || 'jpe' === $image_type || 'jpeg' === $image_type ) ) {
1046 $exif = $this->filesystem->get_image_exif( $attachment_path );
1047 $orientation = isset( $exif['Orientation'] ) ? (int) $exif['Orientation'] : 1;
1048
1049 switch ( $orientation ) {
1050 case 3:
1051 $editor->rotate( 180 );
1052 break;
1053 case 6:
1054 $editor->rotate( -90 );
1055 break;
1056 case 8:
1057 $editor->rotate( 90 );
1058 }
1059 }
1060
1061 // Prevent removal of the exif data when resizing (only works with Imagick).
1062 add_filter( 'image_strip_meta', '__return_false', 789 );
1063
1064 $resized = $editor->resize( $new_sizes[0], $new_sizes[1], false );
1065
1066 // Remove the filter when we're done to prevent any conflict.
1067 remove_filter( 'image_strip_meta', '__return_false', 789 );
1068
1069 if ( is_wp_error( $resized ) ) {
1070 return $resized;
1071 }
1072
1073 $resized_image_path = $editor->generate_filename( 'imagifyresized' );
1074 $resized_image_saved = $editor->save( $resized_image_path );
1075
1076 if ( is_wp_error( $resized_image_saved ) ) {
1077 return $resized_image_saved;
1078 }
1079
1080 return $resized_image_path;
1081 }
1082
1083
1084 /** ----------------------------------------------------------------------------------------- */
1085 /** WORKING STATUS ========================================================================== */
1086 /** ----------------------------------------------------------------------------------------- */
1087
1088 /**
1089 * Tell if the file is currently being optimized (or restored, etc).
1090 *
1091 * @since 1.7.1
1092 * @author Grégory Viguier
1093 * @access public
1094 *
1095 * @return bool
1096 */
1097 public function is_running() {
1098 $callback = $this->optimization_state_network_wide ? 'get_site_transient' : 'get_transient';
1099
1100 return false !== call_user_func( $callback, $this->optimization_state_transient );
1101 }
1102
1103 /**
1104 * Set the running status to "running" for 10 minutes.
1105 *
1106 * @since 1.7.1
1107 * @author Grégory Viguier
1108 * @access public
1109 */
1110 public function set_running_status() {
1111 $callback = $this->optimization_state_network_wide ? 'set_site_transient' : 'set_transient';
1112
1113 call_user_func( $callback, $this->optimization_state_transient, true, 10 * MINUTE_IN_SECONDS );
1114 }
1115
1116 /**
1117 * Unset the running status.
1118 *
1119 * @since 1.7.1
1120 * @author Grégory Viguier
1121 * @access public
1122 */
1123 public function delete_running_status() {
1124 $callback = $this->optimization_state_network_wide ? 'delete_site_transient' : 'delete_transient';
1125
1126 call_user_func( $callback, $this->optimization_state_transient );
1127 }
1128
1129
1130 /** ----------------------------------------------------------------------------------------- */
1131 /** DB ROW ================================================================================== */
1132 /** ----------------------------------------------------------------------------------------- */
1133
1134 /**
1135 * Get the data row.
1136 *
1137 * @since 1.7
1138 * @author Grégory Viguier
1139 * @access public
1140 *
1141 * @return array
1142 */
1143 public function get_row() {
1144 if ( isset( $this->row ) ) {
1145 return $this->row;
1146 }
1147
1148 if ( ! $this->db_class_name || ! $this->is_valid() ) {
1149 return $this->invalidate_row();
1150 }
1151
1152 $this->row = $this->get_row_db_instance()->get( $this->id );
1153
1154 if ( ! $this->row ) {
1155 return $this->invalidate_row();
1156 }
1157
1158 return $this->row;
1159 }
1160
1161 /**
1162 * Update the data row.
1163 *
1164 * @since 1.7
1165 * @author Grégory Viguier
1166 * @access public
1167 *
1168 * @param array $data The data to update.
1169 */
1170 public function update_row( $data ) {
1171 if ( ! $this->db_class_name || ! $this->is_valid() ) {
1172 return;
1173 }
1174
1175 $this->get_row_db_instance()->update( $this->id, $data );
1176
1177 $this->reset_row_cache();
1178 }
1179
1180 /**
1181 * Delete the data row.
1182 *
1183 * @since 1.7
1184 * @author Grégory Viguier
1185 * @access public
1186 */
1187 public function delete_row() {
1188 if ( ! $this->db_class_name || ! $this->is_valid() ) {
1189 return;
1190 }
1191
1192 $this->get_row_db_instance()->delete( $this->id );
1193
1194 $this->invalidate_row();
1195 }
1196
1197 /**
1198 * Shorthand to get the DB table instance.
1199 *
1200 * @since 1.7.1
1201 * @author Grégory Viguier
1202 * @access public
1203 *
1204 * @return object The DB table instance.
1205 */
1206 public function get_row_db_instance() {
1207 return call_user_func( array( $this->db_class_name, 'get_instance' ) );
1208 }
1209
1210 /**
1211 * Invalidate the row.
1212 *
1213 * @since 1.7
1214 * @author Grégory Viguier
1215 * @access public
1216 *
1217 * @return array The row
1218 */
1219 public function invalidate_row() {
1220 $this->row = array();
1221 return $this->row;
1222 }
1223
1224 /**
1225 * Reset the row cache.
1226 *
1227 * @since 1.7
1228 * @author Grégory Viguier
1229 * @access public
1230 *
1231 * @return null The row.
1232 */
1233 public function reset_row_cache() {
1234 $this->row = null;
1235 return $this->row;
1236 }
1237 }
1238