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-ngg-attachment.php

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

1,012 lines 26.6 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 NextGen Gallery attachment class.
6 *
7 * @since 1.5
8 * @since 1.9 Deprecated
9 * @author Jonathan Buttigieg
10 * @deprecated
11 */
12 class Imagify_NGG_Attachment extends Imagify_Attachment {
13
14 /**
15 * Class version.
16 *
17 * @var string
18 */
19 const VERSION = '1.4';
20
21 /**
22 * The attachment SQL DB class.
23 *
24 * @var string
25 * @since 1.7
26 * @access protected
27 */
28 protected $db_class_name = '\Imagify\ThirdParty\NGG\DB';
29
30 /**
31 * The image object.
32 *
33 * @var object A nggImage object.
34 * @since 1.5
35 * @since 1.7 Not public anymore.
36 * @access protected
37 */
38 protected $image;
39
40 /**
41 * The storage object used by NGG.
42 *
43 * @var object A C_Gallery_Storage object (by default).
44 * @since 1.8.
45 * @access protected
46 */
47 protected $storage;
48
49 /**
50 * Tell if the file mime type can be optimized by Imagify.
51 *
52 * @var bool
53 * @since 1.6.9
54 * @since 1.7 Not public anymore.
55 * @access protected
56 * @see $this->is_mime_type_supported()
57 */
58 protected $is_mime_type_supported;
59
60 /**
61 * The constructor.
62 *
63 * @since 1.5
64 * @author Jonathan Buttigieg
65 *
66 * @param int|object $id An image attachment ID or a NGG object.
67 */
68 public function __construct( $id ) {
69 imagify_deprecated_class( get_class( $this ), '1.9', '\\Imagify\\ThirdParty\\NGG\\Optimization\\Process\\NGG( $id )' );
70
71 if ( is_object( $id ) ) {
72 if ( $id instanceof nggImage ) {
73 $this->image = $id;
74 $this->id = (int) $id->pid;
75 } else {
76 $this->image = nggdb::find_image( (int) $id->pid );
77 $this->id = ! empty( $this->image->pid ) ? (int) $this->image->pid : 0;
78 }
79 } else {
80 $this->image = nggdb::find_image( absint( $id ) );
81 $this->id = ! empty( $this->image->pid ) ? (int) $this->image->pid : 0;
82 }
83
84 $this->get_row();
85
86 if ( ! empty( $this->image->_ngiw ) ) {
87 $this->storage = $this->image->_ngiw->get_storage()->object;
88 } else {
89 $this->storage = C_Gallery_Storage::get_instance()->object;
90 }
91
92 $this->filesystem = Imagify_Filesystem::get_instance();
93 $this->optimization_state_transient = 'imagify-ngg-async-in-progress-' . $this->id;
94
95 // Load nggAdmin class.
96 $ngg_admin_functions_path = WP_PLUGIN_DIR . '/' . NGGFOLDER . '/products/photocrati_nextgen/modules/ngglegacy/admin/functions.php';
97
98 if ( ! class_exists( 'nggAdmin' ) && $this->filesystem->exists( $ngg_admin_functions_path ) ) {
99 require_once $ngg_admin_functions_path;
100 }
101 }
102
103 /**
104 * Get the original attachment path.
105 *
106 * @since 1.5
107 * @author Jonathan Buttigieg
108 *
109 * @access public
110 * @return string
111 */
112 public function get_original_path() {
113 if ( ! $this->is_valid() ) {
114 return '';
115 }
116
117 return $this->image->imagePath;
118 }
119
120 /**
121 * Get the original attachment URL.
122 *
123 * @since 1.5
124 * @author Jonathan Buttigieg
125 *
126 * @access public
127 * @return string
128 */
129 public function get_original_url() {
130 if ( ! $this->is_valid() ) {
131 return '';
132 }
133
134 return $this->image->imageURL;
135 }
136
137 /**
138 * Get the attachment backup file path, even if the file doesn't exist.
139 *
140 * @since 1.6.13
141 * @author Grégory Viguier
142 * @access public
143 *
144 * @return string|bool The file path. False on failure.
145 */
146 public function get_raw_backup_path() {
147 if ( ! $this->is_valid() ) {
148 return false;
149 }
150
151 return get_imagify_ngg_attachment_backup_path( $this->get_original_path() );
152 }
153
154 /**
155 * Get the attachment backup URL.
156 *
157 * @since 1.6.8
158 * @author Grégory Viguier
159 *
160 * @return string|false
161 */
162 public function get_backup_url() {
163 if ( ! $this->is_valid() ) {
164 return false;
165 }
166
167 return site_url( '/' ) . $this->filesystem->make_path_relative( $this->get_raw_backup_path() );
168 }
169
170 /**
171 * Get the attachment optimization data.
172 *
173 * @since 1.5
174 * @author Jonathan Buttigieg
175 *
176 * @access public
177 * @return array
178 */
179 public function get_data() {
180 $row = $this->get_row();
181 return isset( $row['data'] ) ? $row['data'] : array();
182 }
183
184 /**
185 * Get the attachment optimization level.
186 *
187 * @since 1.5
188 * @author Jonathan Buttigieg
189 *
190 * @access public
191 * @return int|bool
192 */
193 public function get_optimization_level() {
194 $row = $this->get_row();
195 return isset( $row['optimization_level'] ) ? (int) $row['optimization_level'] : false;
196 }
197
198 /**
199 * Get the attachment optimization status (success or error).
200 *
201 * @since 1.5
202 * @author Jonathan Buttigieg
203 *
204 * @access public
205 * @return string|bool
206 */
207 public function get_status() {
208 $row = $this->get_row();
209 return isset( $row['status'] ) ? $row['status'] : false;
210 }
211
212 /**
213 * Delete the data related to optimization.
214 *
215 * @since 1.7
216 * @access public
217 * @author Grégory Viguier
218 */
219 public function delete_imagify_data() {
220 if ( ! $this->get_row() ) {
221 return;
222 }
223
224 $this->delete_row();
225 }
226
227 /**
228 * Get width and height of the original image.
229 *
230 * @since 1.7
231 * @access public
232 * @author Grégory Viguier
233 *
234 * @return array
235 */
236 public function get_dimensions() {
237 return array(
238 'width' => ! empty( $this->image->meta_data['width'] ) ? (int) $this->image->meta_data['width'] : 0,
239 'height' => ! empty( $this->image->meta_data['height'] ) ? (int) $this->image->meta_data['height'] : 0,
240 );
241 }
242
243 /**
244 * Get the file mime type + file extension (if the file is supported).
245 *
246 * @since 1.8
247 * @access public
248 * @see wp_check_filetype()
249 * @author Grégory Viguier
250 *
251 * @return object
252 */
253 public function get_file_type() {
254 if ( isset( $this->file_type ) ) {
255 return $this->file_type;
256 }
257
258 if ( ! $this->is_valid() ) {
259 $this->file_type = (object) array(
260 'ext' => '',
261 'type' => '',
262 );
263 return $this->file_type;
264 }
265
266 $this->file_type = (object) wp_check_filetype( $this->get_original_path(), imagify_get_mime_types( 'image' ) );
267
268 return $this->file_type;
269 }
270
271 /**
272 * Tell if the current attachment has the required WP metadata.
273 *
274 * @since 1.6.12
275 * @author Grégory Viguier
276 *
277 * @return bool
278 */
279 public function has_required_metadata() {
280 static $sizes;
281
282 if ( ! isset( $sizes ) ) {
283 $sizes = $this->get_image_sizes();
284 }
285
286 return $sizes && $this->get_original_path();
287 }
288
289 /**
290 * Update the metadata size of the attachment.
291 *
292 * @since 1.5
293 *
294 * @access public
295 * @return void
296 */
297 public function update_metadata_size() {
298 $size = $this->filesystem->get_image_size( $this->get_original_path() );
299
300 if ( ! $size ) {
301 return;
302 }
303
304 $this->image->meta_data['width'] = $size['width'];
305 $this->image->meta_data['height'] = $size['height'];
306 $this->image->meta_data['full']['width'] = $size['width'];
307 $this->image->meta_data['full']['height'] = $size['height'];
308
309 nggdb::update_image_meta( $this->id, $this->image->meta_data );
310 }
311
312 /**
313 * Fills statistics data with values from $data array.
314 *
315 * @since 1.5
316 * @since 1.6.5 Not static anymore.
317 * @since 1.6.6 Removed the attachment ID parameter.
318 * @since 1.7 Removed the image URL parameter.
319 * @author Jonathan Buttigieg
320 * @access public
321 *
322 * @param array $data The statistics data.
323 * @param object $response The API response.
324 * @param string $size The attachment size key.
325 * @return bool|array False if the original size has an error or an array contains the data for other result.
326 */
327 public function fill_data( $data, $response, $size = 'full' ) {
328 $data = is_array( $data ) ? $data : array();
329 $data['sizes'] = ! empty( $data['sizes'] ) && is_array( $data['sizes'] ) ? $data['sizes'] : array();
330
331 if ( empty( $data['stats'] ) ) {
332 $data['stats'] = array(
333 'original_size' => 0,
334 'optimized_size' => 0,
335 'percent' => 0,
336 );
337 }
338
339 if ( is_wp_error( $response ) ) {
340 // Error or already optimized.
341 $error = $response->get_error_message();
342 $error_status = 'error';
343
344 $data['sizes'][ $size ] = array(
345 'success' => false,
346 'error' => $error,
347 );
348
349 // Update the error status for the original size.
350 if ( 'full' === $size ) {
351 if ( false !== strpos( $error, 'This image is already compressed' ) ) {
352 $error_status = 'already_optimized';
353 }
354
355 $this->update_row( array(
356 // The pid column is needed in case the row doesn't exist yet.
357 'pid' => $this->id,
358 'status' => $error_status,
359 'data' => $data,
360 ) );
361
362 return false;
363 }
364
365 return $data;
366 }
367
368 // Success.
369 $old_data = $this->get_data();
370 $original_size = ! empty( $old_data['sizes'][ $size ]['original_size'] ) ? (int) $old_data['sizes'][ $size ]['original_size'] : 0;
371
372 $response = (object) array_merge( array(
373 'original_size' => 0,
374 'new_size' => 0,
375 'percent' => 0,
376 ), (array) $response );
377
378 if ( ! empty( $response->original_size ) && ! $original_size ) {
379 $original_size = (int) $response->original_size;
380 }
381
382 if ( ! empty( $response->new_size ) ) {
383 $optimized_size = (int) $response->new_size;
384 } else {
385 $file_path = $this->get_original_path();
386 $file_path = $file_path && $this->filesystem->exists( $file_path ) ? $file_path : false;
387 $optimized_size = $file_path ? $this->filesystem->size( $file_path ) : 0;
388 }
389
390 if ( $original_size && $optimized_size ) {
391 $percent = round( ( $original_size - $optimized_size ) / $original_size * 100, 2 );
392 } elseif ( ! empty( $response->percent ) ) {
393 $percent = round( $response->percent, 2 );
394 } else {
395 $percent = 0;
396 }
397
398 $data['sizes'][ $size ] = array(
399 'success' => true,
400 'original_size' => $original_size,
401 'optimized_size' => $optimized_size,
402 'percent' => $percent,
403 );
404
405 $data['stats']['original_size'] += $original_size;
406 $data['stats']['optimized_size'] += $optimized_size;
407 $data['stats']['percent'] = round( ( ( $data['stats']['original_size'] - $data['stats']['optimized_size'] ) / $data['stats']['original_size'] ) * 100, 2 );
408
409 return $data;
410 }
411
412 /**
413 * Optimize all sizes with Imagify.
414 *
415 * @since 1.5
416 * @author Jonathan Buttigieg
417 *
418 * @access public
419 * @param int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal).
420 * @param array $metadata The attachment meta data (not used here).
421 * @return array $data The optimization data.
422 */
423 public function optimize( $optimization_level = null, $metadata = array() ) {
424 // Check if the attachment extension is allowed.
425 if ( ! $this->is_extension_supported() ) {
426 return;
427 }
428
429 $optimization_level = isset( $optimization_level ) ? (int) $optimization_level : get_imagify_option( 'optimization_level' );
430
431 // To avoid issue with "original_size" at 0 in "_imagify_data".
432 if ( 0 === (int) $this->get_stats_data( 'original_size' ) ) {
433 $this->delete_imagify_data();
434 }
435
436 // Check if the full size is already optimized.
437 if ( $this->is_optimized() && $this->get_optimization_level() === $optimization_level ) {
438 return;
439 }
440
441 // Get file path for original image.
442 $attachment_path = $this->get_original_path();
443 $attachment_url = $this->get_original_url();
444
445 /**
446 * Fires before optimizing an attachment.
447 *
448 * @since 1.5
449 * @author Jonathan Buttigieg
450 *
451 * @param int $id The image ID
452 */
453 do_action( 'before_imagify_ngg_optimize_attachment', $this->id );
454
455 $this->set_running_status();
456
457 // Optimize the original size.
458 $response = do_imagify( $attachment_path, array(
459 'optimization_level' => $optimization_level,
460 'context' => 'NGG',
461 'keep_exif' => true,
462 'original_size' => $this->get_original_size( false ),
463 'backup_path' => $this->get_raw_backup_path(),
464 ) );
465
466 $data = $this->fill_data( null, $response );
467
468 /**
469 * Filter the optimization data of the full size.
470 *
471 * @since 1.8
472 * @author Grégory Viguier
473 *
474 * @param array $data The statistics data.
475 * @param object $response The API response.
476 * @param int $id The attachment ID.
477 * @param string $attachment_path The attachment path.
478 * @param string $attachment_url The attachment URL.
479 * @param string $size_key The attachment size key. The value is obviously 'full' but it's kept for concistancy with other filters.
480 * @param int $optimization_level The optimization level.
481 */
482 $data = apply_filters( 'imagify_fill_ngg_full_size_data', $data, $response, $this->id, $attachment_path, $attachment_url, 'full', $optimization_level );
483
484 // Save the optimization level.
485 $this->update_row( array(
486 // The pid column is needed in case the row doesn't exist yet.
487 'pid' => $this->id,
488 'optimization_level' => $optimization_level,
489 ) );
490
491 if ( ! $data ) {
492 // Error or already optimized.
493 $this->delete_running_status();
494 return;
495 }
496
497 // Optimize thumbnails.
498 $data = $this->optimize_thumbnails( $optimization_level, $data );
499
500 // Save the status to success.
501 $this->update_row( array(
502 'status' => 'success',
503 ) );
504
505 /**
506 * Update NGG meta data.
507 */
508 $image_data = $this->storage->_image_mapper->find( $this->id );
509
510 if ( ! $image_data ) {
511 $this->delete_running_status();
512 return $data;
513 }
514
515 $dimensions = $this->filesystem->get_image_size( $attachment_path );
516 $md5 = md5_file( $attachment_path );
517
518 if ( ( $dimensions || $md5 ) && ( empty( $image_data->meta_data['full'] ) || ! is_array( $image_data->meta_data['full'] ) ) ) {
519 $image_data->meta_data['full'] = array(
520 'width' => 0,
521 'height' => 0,
522 'md5' => '',
523 );
524 }
525
526 if ( $dimensions ) {
527 $image_data->meta_data['width'] = $dimensions['width'];
528 $image_data->meta_data['height'] = $dimensions['height'];
529 $image_data->meta_data['full']['width'] = $dimensions['width'];
530 $image_data->meta_data['full']['height'] = $dimensions['height'];
531 }
532
533 if ( $md5 ) {
534 $image_data->meta_data['md5'] = $md5;
535 $image_data->meta_data['full']['md5'] = $md5;
536 }
537
538 /**
539 * Fires after optimizing an attachment.
540 *
541 * @since 1.5
542 *
543 * @param int $id The attachment ID.
544 * @param array $data The optimization data.
545 */
546 do_action( 'after_imagify_ngg_optimize_attachment', $this->id, $data );
547
548 $this->delete_running_status();
549
550 return $data;
551 }
552
553 /**
554 * Optimize all thumbnails of an image.
555 *
556 * @since 1.5
557 * @author Jonathan Buttigieg
558 *
559 * @access public
560 * @param int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal).
561 * @param array $data The optimization data.
562 * @return array $data The optimization data.
563 */
564 public function optimize_thumbnails( $optimization_level = null, $data = array() ) {
565 $sizes = $this->get_image_sizes();
566 $data = $data ? $data : $this->get_data();
567
568 // Stop if the original image has an error.
569 if ( $this->has_error() ) {
570 return $data;
571 }
572
573 $optimization_level = isset( $optimization_level ) ? (int) $optimization_level : get_imagify_option( 'optimization_level' );
574
575 /**
576 * Fires before optimizing all thumbnails.
577 *
578 * @since 1.5
579 * @author Jonathan Buttigieg
580 *
581 * @param int $id The image ID.
582 */
583 do_action( 'before_imagify_ngg_optimize_thumbnails', $this->id );
584
585 if ( $sizes ) {
586 $image_data = $this->storage->_image_mapper->find( $this->id );
587
588 foreach ( $sizes as $size_key ) {
589 if ( 'full' === $size_key || isset( $data['sizes'][ $size_key ]['success'] ) ) {
590 continue;
591 }
592
593 $thumbnail_path = $this->storage->get_image_abspath( $image_data, $size_key );
594 $thumbnail_url = $this->storage->get_image_url( $image_data, $size_key );
595
596 // Optimize the thumbnail size.
597 $response = do_imagify( $thumbnail_path, array(
598 'optimization_level' => $optimization_level,
599 'context' => 'NGG',
600 'keep_exif' => true,
601 'backup' => false,
602 ) );
603
604 $data = $this->fill_data( $data, $response, $size_key );
605
606 /**
607 * Filter the optimization data of a specific thumbnail.
608 *
609 * @since 1.5
610 * @author Jonathan Buttigieg
611 *
612 * @param array $data The statistics data.
613 * @param object $response The API response.
614 * @param int $id The image ID.
615 * @param string $thumbnail_path The image path.
616 * @param string $thumbnail_url The image URL.
617 * @param string $size_key The image size key.
618 * @param bool $is_aggressive The optimization level.
619 * @return array $data The new optimization data.
620 */
621 $data = apply_filters( 'imagify_fill_ngg_thumbnail_data', $data, $response, $this->id, $thumbnail_path, $thumbnail_url, $size_key, $optimization_level );
622 }
623
624 $this->update_row( array(
625 'data' => $data,
626 ) );
627 } // End if().
628
629 /**
630 * Fires after optimizing all thumbnails.
631 *
632 * @since 1.5
633 * @author Jonathan Buttigieg
634 *
635 * @param int $id The image ID.
636 * @param array $data The optimization data.
637 */
638 do_action( 'after_imagify_ngg_optimize_thumbnails', $this->id, $data );
639
640 return $data;
641 }
642
643 /**
644 * Optimize one size.
645 *
646 * @since 1.8
647 * @access public
648 * @author Grégory Viguier
649 *
650 * @param string $size The thumbnail size.
651 */
652 public function optimize_new_thumbnail( $size ) {
653 // Check if the attachment extension is allowed.
654 if ( ! $this->is_extension_supported() ) {
655 return;
656 }
657
658 if ( ! $this->is_optimized() ) {
659 // The main image is not optimized.
660 return;
661 }
662
663 $data = $this->get_data();
664
665 if ( isset( $data['sizes'][ $size ]['success'] ) ) {
666 // This thumbnail has already been processed.
667 return;
668 }
669
670 $sizes = $this->get_image_sizes();
671 $sizes = array_flip( $sizes );
672
673 if ( ! isset( $sizes[ $size ] ) ) {
674 // This size doesn't exist.
675 return;
676 }
677
678 /**
679 * Fires before optimizing a thumbnail.
680 *
681 * @since 1.8
682 * @author Grégory Viguier
683 *
684 * @param int $id The image ID.
685 */
686 do_action( 'before_imagify_ngg_optimize_new_thumbnail', $this->id );
687
688 $this->set_running_status();
689
690 $image_data = $this->storage->_image_mapper->find( $this->id );
691 $thumbnail_path = $this->storage->get_image_abspath( $image_data, $size );
692 $thumbnail_url = $this->storage->get_image_url( $image_data, $size );
693 $optimization_level = $this->get_optimization_level();
694
695 // Optimize the thumbnail size.
696 $response = do_imagify( $thumbnail_path, array(
697 'optimization_level' => $optimization_level,
698 'context' => 'NGG',
699 'keep_exif' => true,
700 'backup' => false,
701 ) );
702
703 $data = $this->fill_data( $data, $response, $size );
704
705 /** This filter is documented in inc/3rd-party/nextgen-gallery/inc/classes/class-imagify-ngg-attachment.php. */
706 $data = apply_filters( 'imagify_fill_ngg_thumbnail_data', $data, $response, $this->id, $thumbnail_path, $thumbnail_url, $size, $optimization_level );
707
708 $this->update_row( array(
709 'data' => $data,
710 ) );
711
712 /**
713 * Fires after optimizing a thumbnail.
714 *
715 * @since 1.8
716 * @author Grégory Viguier
717 *
718 * @param int $id The image ID.
719 * @param array $data The optimization data.
720 */
721 do_action( 'after_imagify_ngg_optimize_new_thumbnail', $this->id, $data );
722
723 $this->delete_running_status();
724 }
725
726 /**
727 * Re-optimize the given thumbnail sizes to the same level.
728 * This is not used in this context.
729 *
730 * @since 1.7.1
731 * @access public
732 * @author Grégory Viguier
733 *
734 * @param array $sizes The sizes to optimize.
735 * @return array|void A WP_Error object on failure.
736 */
737 public function reoptimize_thumbnails( $sizes ) {}
738
739 /**
740 * Process an attachment restoration from the backup file.
741 *
742 * @since 1.5
743 * @since 1.6.9 Doesn't use NGG's recover_image() anymore, these are fundamentally not the same things. This also prevents alt text, description, and tags deletion.
744 * @since 1.6.9 Return true or a WP_Error object.
745 * @author Jonathan Buttigieg
746 *
747 * @access public
748 * @return bool|object True on success, a WP_Error object on error.
749 */
750 public function restore() {
751 // Check if the attachment extension is allowed.
752 if ( ! $this->is_extension_supported() ) {
753 return new WP_Error( 'mime_not_type_supported', __( 'Mime type not supported.', 'imagify' ) );
754 }
755
756 // Stop the process if there is no backup file to restore.
757 if ( ! $this->has_backup() ) {
758 return new WP_Error( 'no_backup', __( 'Backup image not found.', 'imagify' ) );
759 }
760
761 $image_data = $this->storage->_image_mapper->find( $this->id );
762
763 if ( ! $image_data ) {
764 return new WP_Error( 'no_image', __( 'Image not found in NextGen Gallery data.', 'imagify' ) );
765 }
766
767 /**
768 * Make some more tests before restoring the backup.
769 */
770 $full_abspath = $this->storage->get_image_abspath( $image_data );
771 $backup_abspath = $this->storage->get_image_abspath( $image_data, 'backup' );
772
773 if ( $backup_abspath === $full_abspath ) {
774 return new WP_Error( 'same_path', __( 'Image path and backup path are identical.', 'imagify' ) );
775 }
776
777 if ( ! $this->filesystem->is_writable( $full_abspath ) || ! $this->filesystem->is_writable( $this->filesystem->dir_path( $full_abspath ) ) ) {
778 return new WP_Error( 'destination_not_writable', __( 'The image to replace is not writable.', 'imagify' ) );
779 }
780
781 /**
782 * Fires before restoring an attachment.
783 *
784 * @since 1.5
785 * @author Jonathan Buttigieg
786 *
787 * @param int $id The attachment ID.
788 */
789 do_action( 'before_imagify_ngg_restore_attachment', $this->id );
790
791 if ( ! $this->filesystem->copy( $backup_abspath, $full_abspath, true, FS_CHMOD_FILE ) ) {
792 return new WP_Error( 'copy_failed', __( 'Restoration failed.', 'imagify' ) );
793 }
794
795 /**
796 * Remove Imagify data.
797 */
798 $this->delete_row();
799
800 /**
801 * Fill in the NGG meta data.
802 */
803 // 1- Meta data for the backup file.
804 $dimensions = $this->filesystem->get_image_size( $backup_abspath );
805 $backup_data = array(
806 'backup' => array(
807 'filename' => $this->filesystem->file_name( $full_abspath ), // Yes, $full_abspath.
808 'width' => 0,
809 'height' => 0,
810 'generated' => microtime(),
811 ),
812 );
813
814 if ( $dimensions ) {
815 $backup_data['backup']['width'] = $dimensions['width'];
816 $backup_data['backup']['height'] = $dimensions['height'];
817 }
818
819 // 2- Meta data for the full sized image.
820 $full_data = array(
821 'width' => 0,
822 'height' => 0,
823 'md5' => '',
824 'full' => array(
825 'width' => 0,
826 'height' => 0,
827 'md5' => '',
828 ),
829 );
830
831 $dimensions = $this->filesystem->get_image_size( $full_abspath );
832
833 if ( $dimensions ) {
834 $full_data['width'] = $dimensions['width'];
835 $full_data['height'] = $dimensions['height'];
836 $full_data['full']['width'] = $dimensions['width'];
837 $full_data['full']['height'] = $dimensions['height'];
838 }
839
840 $md5 = md5_file( $full_abspath );
841
842 if ( $md5 ) {
843 $full_data['md5'] = $md5;
844 $full_data['full']['md5'] = $md5;
845 }
846
847 // 3- Thumbnails meta data.
848 $thumbnails_data = array();
849
850 // 4- Common meta data.
851 require_once NGGALLERY_ABSPATH . '/lib/meta.php';
852 $meta_obj = new nggMeta( $image_data );
853 $common_data = $meta_obj->get_common_meta();
854
855 if ( $common_data ) {
856 unset( $common_data['width'], $common_data['height'] );
857 } else {
858 $common_data = array(
859 'aperture' => 0,
860 'credit' => '',
861 'camera' => '',
862 'caption' => '',
863 'created_timestamp' => 0,
864 'copyright' => '',
865 'focal_length' => 0,
866 'iso' => 0,
867 'shutter_speed' => 0,
868 'flash' => 0,
869 'title' => '',
870 'keywords' => '',
871 );
872
873 if ( ! empty( $image_data->meta_data ) && is_array( $image_data->meta_data ) ) {
874 $image_data->meta_data = array_merge( $common_data, $image_data->meta_data );
875 $common_data = array_intersect_key( $image_data->meta_data, $common_data );
876 }
877 }
878
879 $common_data['saved'] = true;
880
881 /**
882 * Re-create non-fullsize image sizes and add related data.
883 */
884 $failed = array();
885
886 foreach ( $this->get_image_sizes() as $named_size ) {
887 if ( 'full' === $named_size ) {
888 continue;
889 }
890
891 $params = $this->storage->get_image_size_params( $image_data, $named_size );
892 $thumbnail = $this->storage->generate_image_clone(
893 $backup_abspath,
894 $this->storage->get_image_abspath( $image_data, $named_size ),
895 $params
896 );
897
898 if ( ! $thumbnail ) {
899 // Failed.
900 $failed[] = $named_size;
901 continue;
902 }
903
904 $size_meta = array(
905 'width' => 0,
906 'height' => 0,
907 'filename' => M_I18n::mb_basename( $thumbnail->fileName ),
908 'generated' => microtime(),
909 );
910
911 $dimensions = $this->filesystem->get_image_size( $thumbnail->fileName );
912
913 if ( $dimensions ) {
914 $size_meta['width'] = $dimensions['width'];
915 $size_meta['height'] = $dimensions['height'];
916 }
917
918 if ( isset( $params['crop_frame'] ) ) {
919 $size_meta['crop_frame'] = $params['crop_frame'];
920 }
921
922 $thumbnails_data[ $named_size ] = $size_meta;
923 } // End foreach().
924
925 do_action( 'ngg_recovered_image', $image_data );
926
927 /**
928 * Save the meta data.
929 */
930 $image_data->meta_data = array_merge( $backup_data, $full_data, $thumbnails_data, $common_data );
931
932 // Keep our property up to date.
933 $this->image->_ngiw->_cache['meta_data'] = $image_data->meta_data;
934 $this->image->_ngiw->_orig_image = $image_data;
935
936 $post_id = $this->storage->_image_mapper->save( $image_data );
937
938 if ( ! $post_id ) {
939 return new WP_Error( 'meta_data_not_saved', __( 'Related data could not be saved.', 'imagify' ) );
940 }
941
942 if ( $failed ) {
943 return new WP_Error(
944 'thumbnail_restore_failed',
945 sprintf( _n( '%n thumbnail could not be restored.', '%n thumbnails could not be restored.', count( $failed ), 'imagify' ), count( $failed ) ),
946 array( 'failed_thumbnails' => $failed )
947 );
948 }
949
950 /**
951 * Fires after restoring an attachment.
952 *
953 * @since 1.5
954 * @author Jonathan Buttigieg
955 *
956 * @param int $id The attachment ID.
957 */
958 do_action( 'after_imagify_ngg_restore_attachment', $this->id );
959
960 return true;
961 }
962
963 /**
964 * Get the image sizes.
965 *
966 * @since 1.8
967 * @access public
968 * @author Grégory Viguier
969 *
970 * @return array
971 */
972 public function get_image_sizes() {
973 $sizes = array(
974 'full',
975 );
976
977 // Remove common values (that have no value for us here, lol).
978 $image_data = array_diff_key( $this->image->meta_data, array(
979 'backup' => 1,
980 'width' => 1,
981 'height' => 1,
982 'md5' => 1,
983 'full' => 1,
984 'aperture' => 1,
985 'credit' => 1,
986 'camera' => 1,
987 'caption' => 1,
988 'created_timestamp' => 1,
989 'copyright' => 1,
990 'focal_length' => 1,
991 'iso' => 1,
992 'shutter_speed' => 1,
993 'flash' => 1,
994 'title' => 1,
995 'keywords' => 1,
996 'saved' => 1,
997 ) );
998
999 if ( ! $image_data ) {
1000 return $sizes;
1001 }
1002
1003 foreach ( $image_data as $size_name => $size_data ) {
1004 if ( isset( $size_data['width'], $size_data['height'], $size_data['filename'], $size_data['generated'] ) ) {
1005 $sizes[] = $size_name;
1006 }
1007 }
1008
1009 return $sizes;
1010 }
1011 }
1012