PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 1.9.13
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v1.9.13
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 / classes / Optimization / File.php

File.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 1.9.13, at classes/Optimization/File.php

882 lines 22.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Imagify\Optimization;
3
4 use Imagify_Requirements;
5
6 defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
7
8 /**
9 * A generic optimization class focussed on the file itself.
10 *
11 * @since 1.9
12 * @author Grégory Viguier
13 */
14 class File {
15
16 /**
17 * Absolute path to the file.
18 *
19 * @var string
20 * @since 1.9
21 * @access protected
22 * @author Grégory Viguier
23 */
24 protected $path;
25
26 /**
27 * Tell if the file is an image.
28 *
29 * @var bool
30 * @since 1.9
31 * @access protected
32 * @see $this->is_image()
33 * @author Grégory Viguier
34 */
35 protected $is_image;
36
37 /**
38 * Store the file mime type + file extension (if the file is supported).
39 *
40 * @var array
41 * @since 1.9
42 * @access protected
43 * @see $this->get_file_type()
44 * @author Grégory Viguier
45 */
46 protected $file_type;
47
48 /**
49 * Filesystem object.
50 *
51 * @var \Imagify_Filesystem
52 * @since 1.9
53 * @access protected
54 * @author Grégory Viguier
55 */
56 protected $filesystem;
57
58 /**
59 * The editor instance used to resize the file.
60 *
61 * @var \WP_Image_Editor_Imagick|\WP_Image_Editor_GD|WP_Error.
62 * @since 1.9
63 * @access protected
64 * @author Grégory Viguier
65 */
66 protected $editor;
67
68 /**
69 * Used to cache the plugin’s options.
70 *
71 * @var array
72 * @since 1.9
73 * @access protected
74 * @author Grégory Viguier
75 */
76 protected $options = [];
77
78 /**
79 * The constructor.
80 *
81 * @since 1.9
82 * @access public
83 * @author Grégory Viguier
84 *
85 * @param string $file_path Absolute path to the file.
86 */
87 public function __construct( $file_path ) {
88 $this->path = $file_path;
89 $this->filesystem = \Imagify_Filesystem::get_instance();
90 }
91
92 /**
93 * Tell if the file is valid.
94 *
95 * @since 1.9
96 * @access public
97 * @author Grégory Viguier
98 *
99 * @return bool
100 */
101 public function is_valid() {
102 return (bool) $this->path;
103 }
104
105 /**
106 * Tell if the file can be processed.
107 *
108 * @since 1.9
109 * @access public
110 * @author Grégory Viguier
111 *
112 * @return bool|WP_Error
113 */
114 public function can_be_processed() {
115 if ( ! $this->path ) {
116 return new \WP_Error( 'empty_path', __( 'File path is empty.', 'imagify' ) );
117 }
118
119 if ( ! empty( $this->filesystem->errors->errors ) ) {
120 return new \WP_Error( 'filesystem_error', __( 'Filesystem error.', 'imagify' ), $this->filesystem->errors );
121 }
122
123 if ( ! $this->filesystem->exists( $this->path ) ) {
124 return new \WP_Error(
125 'not_exists',
126 sprintf(
127 /* translators: %s is a file path. */
128 __( 'The file %s does not seem to exist.', 'imagify' ),
129 '<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
130 )
131 );
132 }
133
134 if ( ! $this->filesystem->is_file( $this->path ) ) {
135 return new \WP_Error(
136 'not_a_file',
137 sprintf(
138 /* translators: %s is a file path. */
139 __( 'This does not seem to be a file: %s.', 'imagify' ),
140 '<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
141 )
142 );
143 }
144
145 if ( ! $this->filesystem->is_writable( $this->path ) ) {
146 return new \WP_Error(
147 'not_writable',
148 sprintf(
149 /* translators: %s is a file path. */
150 __( 'The file %s does not seem to be writable.', 'imagify' ),
151 '<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
152 )
153 );
154 }
155
156 $parent_folder = $this->filesystem->dir_path( $this->path );
157
158 if ( ! $this->filesystem->is_writable( $parent_folder ) ) {
159 return new \WP_Error(
160 'folder_not_writable',
161 sprintf(
162 /* translators: %s is a file path. */
163 __( 'The folder %s does not seem to be writable.', 'imagify' ),
164 '<code>' . esc_html( $this->filesystem->make_path_relative( $parent_folder ) ) . '</code>'
165 )
166 );
167 }
168
169 return true;
170 }
171
172
173 /** ----------------------------------------------------------------------------------------- */
174 /** EDITION ================================================================================= */
175 /** ----------------------------------------------------------------------------------------- */
176
177 /**
178 * Resize (and rotate) an image if it is bigger than the maximum width provided.
179 *
180 * @since 1.9
181 * @access public
182 * @author Grégory Viguier
183 * @author Remy Perona
184 *
185 * @param array $dimensions {
186 * Array of image dimensions.
187 *
188 * @type int $width The image width.
189 * @type int $height The image height.
190 * }
191 * @param int $max_width Maximum width to resize to.
192 * @return string|WP_Error Path the the resized image. A WP_Error object on failure.
193 */
194 public function resize( $dimensions = [], $max_width = 0 ) {
195 $can_be_processed = $this->can_be_processed();
196
197 if ( is_wp_error( $can_be_processed ) ) {
198 return $can_be_processed;
199 }
200
201 if ( ! $max_width ) {
202 return new \WP_Error(
203 'no_resizing_threshold',
204 __( 'No threshold provided for resizing.', 'imagify' )
205 );
206 }
207
208 if ( ! $this->is_image() ) {
209 return new \WP_Error(
210 'not_an_image',
211 sprintf(
212 /* translators: %s is a file path. */
213 __( 'The file %s does not seem to be an image, and cannot be resized.', 'imagify' ),
214 '<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
215 )
216 );
217 }
218
219 $editor = $this->get_editor();
220
221 if ( is_wp_error( $editor ) ) {
222 return $editor;
223 }
224
225 // Try to correct the auto-rotation if the info is available.
226 if ( $this->filesystem->can_get_exif() && 'image/jpeg' === $this->get_mime_type() ) {
227 $exif = $this->filesystem->get_image_exif( $this->path );
228 $orientation = isset( $exif['Orientation'] ) ? (int) $exif['Orientation'] : 1;
229
230 switch ( $orientation ) {
231 case 2:
232 // Flip horizontally.
233 $editor->flip( true, false );
234 break;
235 case 3:
236 // Rotate 180 degrees or flip horizontally and vertically.
237 // Flipping seems faster/uses less resources.
238 $editor->flip( true, true );
239 break;
240 case 4:
241 // Flip vertically.
242 $editor->flip( false, true );
243 break;
244 case 5:
245 // Rotate 90 degrees counter-clockwise and flip vertically.
246 $result = $editor->rotate( 90 );
247
248 if ( ! is_wp_error( $result ) ) {
249 $editor->flip( false, true );
250 }
251 break;
252 case 6:
253 // Rotate 90 degrees clockwise (270 counter-clockwise).
254 $editor->rotate( 270 );
255 break;
256 case 7:
257 // Rotate 90 degrees counter-clockwise and flip horizontally.
258 $result = $editor->rotate( 90 );
259
260 if ( ! is_wp_error( $result ) ) {
261 $editor->flip( true, false );
262 }
263 break;
264 case 8:
265 // Rotate 90 degrees counter-clockwise.
266 $editor->rotate( 90 );
267 break;
268 }
269 }
270
271 if ( ! $dimensions ) {
272 $dimensions = $this->get_dimensions();
273 }
274
275 // Prevent removal of the exif data when resizing (only works with Imagick).
276 add_filter( 'image_strip_meta', '__return_false', 789 );
277
278 // Resize.
279 $new_sizes = wp_constrain_dimensions( $dimensions['width'], $dimensions['height'], $max_width );
280 $resized = $editor->resize( $new_sizes[0], $new_sizes[1], false );
281
282 // Remove the filter when we're done to prevent any conflict.
283 remove_filter( 'image_strip_meta', '__return_false', 789 );
284
285 if ( is_wp_error( $resized ) ) {
286 return $resized;
287 }
288
289 $resized_image_path = $editor->generate_filename( 'imagifyresized' );
290 $resized_image_saved = $editor->save( $resized_image_path );
291
292 if ( is_wp_error( $resized_image_saved ) ) {
293 return $resized_image_saved;
294 }
295
296 return $resized_image_path;
297 }
298
299 /**
300 * Create a thumbnail.
301 * Warning: If the destination file already exists, it will be overwritten.
302 *
303 * @since 1.9
304 * @access protected
305 * @author Grégory Viguier
306 *
307 * @param array $destination {
308 * The thumbnail data.
309 *
310 * @type string $path Path to the destination file.
311 * @type int $width The image width.
312 * @type int $height The image height.
313 * @type bool $crop True to crop, false to resize.
314 * @type bool $adjust_filename True to adjust the file name like what `$editor->multi_resize()` returns, like WP default behavior (default). False to prevent it, and use the file name from $path instead.
315 * }
316 * @return bool|array|WP_Error {
317 * A WP_Error object on error. True if the file exists.
318 * An array of thumbnail data if the file has just been created:
319 *
320 * @type string $file File name.
321 * @type int $width The image width.
322 * @type int $height The image height.
323 * @type string $mime-type The mime type.
324 * }
325 */
326 public function create_thumbnail( $destination ) {
327 $can_be_processed = $this->can_be_processed();
328
329 if ( is_wp_error( $can_be_processed ) ) {
330 return $can_be_processed;
331 }
332
333 if ( ! $this->is_image() ) {
334 return new \WP_Error(
335 'not_an_image',
336 sprintf(
337 /* translators: %s is a file path. */
338 __( 'The file %s does not seem to be an image, and cannot be resized.', 'imagify' ),
339 '<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
340 )
341 );
342 }
343
344 $editor = $this->get_editor();
345
346 if ( is_wp_error( $editor ) ) {
347 return $editor;
348 }
349
350 // Create the file.
351 $result = $editor->multi_resize( [ $destination ] );
352
353 if ( ! $result ) {
354 return new \WP_Error( 'image_resize_error', __( 'The thumbnail could not be created.', 'imagify' ) );
355 }
356
357 $result = reset( $result );
358
359 $filename = $result['file'];
360 $source_thumb_path = $this->filesystem->dir_path( $this->path ) . $filename;
361
362 if ( ! isset( $destination['adjust_filename'] ) || $destination['adjust_filename'] ) {
363 // The file name can change from what we expected (1px wider, etc), let's use the resulting data to move the file to the right place.
364 $destination_thumb_path = $this->filesystem->dir_path( $destination['path'] ) . $filename;
365 } else {
366 // Respect what is set in $path.
367 $destination_thumb_path = $destination['path'];
368 $result['file'] = $this->filesystem->file_name( $destination['path'] );
369 }
370
371 if ( $source_thumb_path === $destination_thumb_path ) {
372 return $result;
373 }
374
375 $moved = $this->filesystem->move( $source_thumb_path, $destination_thumb_path, true );
376
377 if ( ! $moved ) {
378 return new \WP_Error( 'move_error', __( 'The file could not be moved to its final destination.', 'imagify' ) );
379 }
380
381 return $result;
382 }
383
384 /**
385 * Backup a file.
386 *
387 * @since 1.9
388 * @since 1.9.8 Added $backup_source argument.
389 * @access public
390 * @author Grégory Viguier
391 *
392 * @param string $backup_path The backup path.
393 * @param string $backup_source Path to the file to backup. This is useful in WP 5.3+ when we want to optimize the full size: in that case we need to backup the original file.
394 * @return bool|WP_Error True on success. False if the backup option is disabled. A WP_Error object on failure.
395 */
396 public function backup( $backup_path = null, $backup_source = null ) {
397 $can_be_processed = $this->can_be_processed();
398
399 if ( is_wp_error( $can_be_processed ) ) {
400 return $can_be_processed;
401 }
402
403 // Make sure the backups directory has no errors.
404 if ( ! $backup_path ) {
405 return new \WP_Error( 'wp_upload_error', __( 'Error while retrieving the backups directory path.', 'imagify' ) );
406 }
407
408 // Create sub-directories.
409 $created = $this->filesystem->make_dir( $this->filesystem->dir_path( $backup_path ) );
410
411 if ( ! $created ) {
412 return new \WP_Error( 'backup_dir_not_writable', __( 'The backup directory is not writable.', 'imagify' ) );
413 }
414
415 $path = $backup_source && $this->filesystem->exists( $backup_source ) ? $backup_source : $this->path;
416
417 /**
418 * Allow to overwrite the backup file if it already exists.
419 *
420 * @since 1.6.9
421 * @author Grégory Viguier
422 *
423 * @param bool $overwrite Whether to overwrite the backup file.
424 * @param string $path The file path.
425 * @param string $backup_path The backup path.
426 */
427 $overwrite = apply_filters( 'imagify_backup_overwrite_backup', false, $path, $backup_path );
428
429 // Copy the file.
430 $this->filesystem->copy( $path, $backup_path, $overwrite, FS_CHMOD_FILE );
431
432 // Make sure the backup copy exists.
433 if ( ! $this->filesystem->exists( $backup_path ) ) {
434 return new \WP_Error( 'backup_doesnt_exist', __( 'The file could not be saved.', 'imagify' ), array(
435 'file_path' => $this->filesystem->make_path_relative( $path ),
436 'backup_path' => $this->filesystem->make_path_relative( $backup_path ),
437 ) );
438 }
439
440 return true;
441 }
442
443 /**
444 * Optimize a file with Imagify.
445 *
446 * @since 1.9
447 * @access public
448 * @author Grégory Viguier
449 *
450 * @param array $args {
451 * Optional. An array of arguments.
452 *
453 * @type bool $backup False to prevent backup. True to follow the user's setting. A backup can't be forced.
454 * @type string $backup_path If a backup must be done, this is the path to use. Default is the backup path used for the WP Media Library.
455 * @type int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal).
456 * @type bool $keep_exif To keep exif data or not.
457 * @type string $convert Set to 'webp' to convert the image to webp.
458 * @type string $context The context.
459 * @type int $original_size The file size, sent to the API.
460 * }
461 * @return \sdtClass|\WP_Error Optimized image data. A \WP_Error object on error.
462 */
463 public function optimize( $args = [] ) {
464 $args = array_merge( [
465 'backup' => true,
466 'backup_path' => null,
467 'backup_source' => null,
468 'optimization_level' => 0,
469 'keep_exif' => true,
470 'convert' => '',
471 'context' => 'wp',
472 'original_size' => 0,
473 ], $args );
474
475 $can_be_processed = $this->can_be_processed();
476
477 if ( is_wp_error( $can_be_processed ) ) {
478 return $can_be_processed;
479 }
480
481 // Check if external HTTP requests are blocked.
482 if ( Imagify_Requirements::is_imagify_blocked() ) {
483 return new \WP_Error( 'http_block_external', __( 'External HTTP requests are blocked.', 'imagify' ) );
484 }
485
486 /**
487 * Fires before a media file optimization.
488 *
489 * @since 1.9
490 * @author Grégory Viguier
491 *
492 * @param string $path Absolute path to the media file.
493 * @param array $args Arguments passed to the method.
494 */
495 do_action( 'imagify_before_optimize_file', $this->path, $args );
496
497 /**
498 * Fires before to optimize the Image with Imagify.
499 *
500 * @since 1.0
501 * @deprecated
502 *
503 * @param string $path Absolute path to the image file.
504 * @param bool $backup True if a backup will be make.
505 */
506 do_action_deprecated( 'before_do_imagify', [ $this->path, $args['backup'] ], '1.9', 'imagify_before_optimize_file' );
507
508 if ( $args['backup'] ) {
509 $backup_result = $this->backup( $args['backup_path'], $args['backup_source'] );
510
511 if ( is_wp_error( $backup_result ) ) {
512 // Stop the process if we can't backup the file.
513 return $backup_result;
514 }
515 }
516
517 // Send file for optimization and fetch the response.
518 $data = [
519 'normal' => 0 === $args['optimization_level'],
520 'aggressive' => 1 === $args['optimization_level'],
521 'ultra' => 2 === $args['optimization_level'],
522 'keep_exif' => $args['keep_exif'],
523 'original_size' => $args['original_size'],
524 'context' => $args['context'],
525 ];
526
527 if ( $args['convert'] ) {
528 $data['convert'] = $args['convert'];
529 }
530
531 $response = upload_imagify_image( [
532 'image' => $this->path,
533 'data' => wp_json_encode( $data ),
534 ] );
535
536 if ( is_wp_error( $response ) ) {
537 return new \WP_Error( 'api_error', $response->get_error_message() );
538 }
539
540 if ( ! function_exists( 'download_url' ) ) {
541 require_once ABSPATH . 'wp-admin/includes/file.php';
542 }
543
544 $temp_file = download_url( $response->image );
545
546 if ( is_wp_error( $temp_file ) ) {
547 return new \WP_Error( 'temp_file_not_found', $temp_file->get_error_message() );
548 }
549
550 if ( 'webp' === $args['convert'] ) {
551 $destination_path = $this->get_path_to_webp();
552 $this->path = $destination_path;
553 $this->file_type = null;
554 $this->editor = null;
555 } else {
556 $destination_path = $this->path;
557 }
558
559 $moved = $this->filesystem->move( $temp_file, $destination_path, true );
560
561 if ( ! $moved ) {
562 return new \WP_Error( 'move_error', __( 'The file could not be moved to its final destination.', 'imagify' ) );
563 }
564
565 /**
566 * Fires after to optimize the Image with Imagify.
567 *
568 * @since 1.0
569 * @deprecated
570 *
571 * @param string $path Absolute path to the image file.
572 * @param bool $backup True if a backup has been made.
573 */
574 do_action_deprecated( 'after_do_imagify', [ $this->path, $args['backup'] ], '1.9', 'imagify_before_optimize_file' );
575
576 /**
577 * Fires after a media file optimization.
578 *
579 * @since 1.9
580 * @author Grégory Viguier
581 *
582 * @param string $path Absolute path to the media file.
583 * @param array $args Arguments passed to the method.
584 */
585 do_action( 'imagify_after_optimize_file', $this->path, $args );
586
587 return $response;
588 }
589
590
591 /** ----------------------------------------------------------------------------------------- */
592 /** IMAGE EDITOR (GD/IMAGEMAGICK) =========================================================== */
593 /** ----------------------------------------------------------------------------------------- */
594
595 /**
596 * Get an image editor instance (WP_Image_Editor_Imagick, WP_Image_Editor_GD).
597 *
598 * @since 1.9
599 * @access protected
600 * @author Grégory Viguier
601 *
602 * @return WP_Image_Editor_Imagick|WP_Image_Editor_GD|WP_Error
603 */
604 protected function get_editor() {
605 if ( isset( $this->editor ) ) {
606 return $this->editor;
607 }
608
609 $this->editor = wp_get_image_editor( $this->path, [
610 'methods' => $this->get_editor_methods(),
611 ] );
612
613 if ( ! is_wp_error( $this->editor ) ) {
614 return $this->editor;
615 }
616
617 $this->editor = new \WP_Error(
618 'image_editor',
619 sprintf(
620 /* translators: %1$s is an error message, %2$s is a "More info?" link. */
621 __( 'No php extensions are available to edit images on the server. ImageMagick or GD is required. The internal error is: %1$s. %2$s', 'imagify' ),
622 $this->editor->get_error_message(),
623 '<a href="' . esc_url( imagify_get_external_url( 'documentation-imagick-gd' ) ) . '" target="_blank">' . __( 'More info?', 'imagify' ) . '</a>'
624 )
625 );
626
627 return $this->editor;
628 }
629
630 /**
631 * Get the image editor methods we will use.
632 *
633 * @since 1.9
634 * @access protected
635 * @author Grégory Viguier
636 *
637 * @return array
638 */
639 protected function get_editor_methods() {
640 static $methods;
641
642 if ( isset( $methods ) ) {
643 return $methods;
644 }
645
646 $methods = [
647 'resize',
648 'multi_resize',
649 'generate_filename',
650 'save',
651 ];
652
653 if ( $this->filesystem->can_get_exif() ) {
654 $methods[] = 'rotate';
655 }
656
657 return $methods;
658 }
659
660
661 /** ----------------------------------------------------------------------------------------- */
662 /** VARIOUS TOOLS =========================================================================== */
663 /** ----------------------------------------------------------------------------------------- */
664
665 /**
666 * Check if a file exceeds the weight limit (> 5mo).
667 *
668 * @since 1.9
669 * @access public
670 * @author Grégory Viguier
671 *
672 * @return bool
673 */
674 public function is_exceeded() {
675 if ( ! $this->is_valid() ) {
676 return false;
677 }
678
679 $size = $this->filesystem->size( $this->path );
680
681 return $size > IMAGIFY_MAX_BYTES;
682 }
683
684 /**
685 * Tell if the current file is supported for a given context.
686 *
687 * @since 1.9
688 * @access public
689 * @see imagify_get_mime_types()
690 * @author Grégory Viguier
691 *
692 * @param array $allowed_mime_types A list of allowed mime types.
693 * @return bool
694 */
695 public function is_supported( $allowed_mime_types ) {
696 return in_array( $this->get_mime_type(), $allowed_mime_types, true );
697 }
698
699 /**
700 * Tell if the file is an image.
701 *
702 * @since 1.9
703 * @access public
704 * @author Grégory Viguier
705 *
706 * @return bool
707 */
708 public function is_image() {
709 if ( isset( $this->is_image ) ) {
710 return $this->is_image;
711 }
712
713 $this->is_image = strpos( $this->get_mime_type(), 'image/' ) === 0;
714
715 return $this->is_image;
716 }
717
718 /**
719 * Tell if the file is a pdf.
720 *
721 * @since 1.9
722 * @access public
723 * @author Grégory Viguier
724 *
725 * @return bool
726 */
727 public function is_pdf() {
728 return 'application/pdf' === $this->get_mime_type();
729 }
730
731 /**
732 * Get the file mime type.
733 *
734 * @since 1.9
735 * @access public
736 * @author Grégory Viguier
737 *
738 * @return string
739 */
740 public function get_mime_type() {
741 return $this->get_file_type()->type;
742 }
743
744 /**
745 * Get the file extension.
746 *
747 * @since 1.9
748 * @access public
749 * @author Grégory Viguier
750 *
751 * @return string|null
752 */
753 public function get_extension() {
754 return $this->get_file_type()->ext;
755 }
756
757 /**
758 * Get the file path.
759 *
760 * @since 1.9
761 * @access public
762 * @author Grégory Viguier
763 *
764 * @return string
765 */
766 public function get_path() {
767 return $this->path;
768 }
769
770 /**
771 * Replace the file extension by webp.
772 *
773 * @since 1.9
774 * @access public
775 * @author Grégory Viguier
776 *
777 * @return string|bool The file path on success. False if not an image or on failure.
778 */
779 public function get_path_to_webp() {
780 if ( ! $this->is_image() ) {
781 return false;
782 }
783
784 if ( $this->is_webp() ) {
785 return false;
786 }
787
788 return imagify_path_to_webp( $this->path );
789 }
790
791 /**
792 * Tell if the file is a webp image.
793 * Rejects "path/to/.webp" files.
794 *
795 * @since 1.9
796 * @access public
797 * @author Grégory Viguier
798 *
799 * @return bool
800 */
801 public function is_webp() {
802 return preg_match( '@(?!^|/|\\\)\.webp$@i', $this->path );
803 }
804
805 /**
806 * Get the file mime type + file extension.
807 *
808 * @since 1.9
809 * @access protected
810 * @see wp_check_filetype()
811 * @author Grégory Viguier
812 *
813 * @return object {
814 * @type string $ext The file extension.
815 * @type string $type The mime type.
816 * }
817 */
818 protected function get_file_type() {
819 if ( isset( $this->file_type ) ) {
820 return $this->file_type;
821 }
822
823 $this->file_type = (object) [
824 'ext' => '',
825 'type' => '',
826 ];
827
828 if ( ! $this->is_valid() ) {
829 return $this->file_type;
830 }
831
832 $this->file_type = (object) wp_check_filetype( $this->path );
833
834 return $this->file_type;
835 }
836
837 /**
838 * If the media is an image, get its width and height.
839 *
840 * @since 1.9
841 * @access public
842 * @author Grégory Viguier
843 *
844 * @return array
845 */
846 public function get_dimensions() {
847 if ( ! $this->is_image() ) {
848 return [
849 'width' => 0,
850 'height' => 0,
851 ];
852 }
853
854 $values = $this->filesystem->get_image_size( $this->path );
855
856 return [
857 'width' => $values['width'],
858 'height' => $values['height'],
859 ];
860 }
861
862 /**
863 * Get a plugin’s option.
864 *
865 * @since 1.9
866 * @access protected
867 * @author Grégory Viguier
868 *
869 * @param string $option_name The option nme.
870 * @return mixed
871 */
872 protected function get_option( $option_name ) {
873 if ( isset( $this->options[ $option_name ] ) ) {
874 return $this->options[ $option_name ];
875 }
876
877 $this->options[ $option_name ] = get_imagify_option( $option_name );
878
879 return $this->options[ $option_name ];
880 }
881 }
882