PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.0
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.0
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 2.0, at classes/Optimization/File.php

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