PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 1.10
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v1.10
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 / 3rd-party / nextgen-gallery / classes / Media / NGG.php

NGG.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 1.10, at inc/3rd-party/nextgen-gallery/classes/Media/NGG.php

544 lines 14.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Imagify\ThirdParty\NGG\Media;
3
4 defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
5
6 /**
7 * Media class for the medias from NextGen Gallery.
8 *
9 * @since 1.9
10 * @author Grégory Viguier
11 */
12 class NGG extends \Imagify\Media\AbstractMedia {
13 use \Imagify\Deprecated\Traits\Media\NGGDeprecatedTrait;
14
15 /**
16 * Context (where the media "comes from").
17 *
18 * @var string
19 * @since 1.9
20 * @access protected
21 * @author Grégory Viguier
22 */
23 protected $context = 'ngg';
24
25 /**
26 * The image object.
27 *
28 * @var object A \nggImage object.
29 * @since 1.9
30 * @access protected
31 * @author Grégory Viguier
32 */
33 protected $image;
34
35 /**
36 * The storage object used by NGG.
37 *
38 * @var object A \C_Gallery_Storage object (by default).
39 * @since 1.8.
40 * @access protected
41 */
42 protected $storage;
43
44 /**
45 * The constructor.
46 *
47 * @since 1.9
48 * @access public
49 * @author Grégory Viguier
50 *
51 * @param int|\nggImage|\nggdb|\StdClass $id The NGG image ID, \nggImage object, \nggdb object, or an anonym object containing a pid property.
52 */
53 public function __construct( $id ) {
54 if ( ! static::constructor_accepts( $id ) ) {
55 parent::__construct( 0 );
56 return;
57 }
58
59 if ( is_numeric( $id ) ) {
60 $this->image = \nggdb::find_image( (int) $id );
61 $id = ! empty( $this->image->pid ) ? (int) $this->image->pid : 0;
62 } elseif ( $id instanceof \nggImage ) {
63 $this->image = $id;
64 $id = (int) $id->pid;
65 } elseif ( is_object( $id ) ) {
66 $this->image = \nggdb::find_image( (int) $id->pid );
67 $id = ! empty( $this->image->pid ) ? (int) $this->image->pid : 0;
68 } else {
69 $id = 0;
70 }
71
72 if ( ! $id ) {
73 $this->image = null;
74
75 parent::__construct( 0 );
76 return;
77 }
78
79 parent::__construct( $id );
80
81 // NGG storage.
82 if ( ! empty( $this->image->_ngiw ) ) {
83 $this->storage = $this->image->_ngiw->get_storage()->object;
84 } else {
85 $this->storage = \C_Gallery_Storage::get_instance()->object;
86 }
87
88 // Load nggAdmin class.
89 $ngg_admin_functions_path = WP_PLUGIN_DIR . '/' . NGGFOLDER . '/products/photocrati_nextgen/modules/ngglegacy/admin/functions.php';
90
91 if ( ! class_exists( 'nggAdmin' ) && $this->filesystem->exists( $ngg_admin_functions_path ) ) {
92 require_once $ngg_admin_functions_path;
93 }
94 }
95
96 /**
97 * Tell if the given entry can be accepted in the constructor.
98 *
99 * @since 1.9
100 * @access public
101 * @author Grégory Viguier
102 *
103 * @param mixed $id Whatever.
104 * @return bool
105 */
106 public static function constructor_accepts( $id ) {
107 if ( ! $id ) {
108 return false;
109 }
110
111 if ( is_numeric( $id ) || $id instanceof \nggImage ) {
112 return true;
113 }
114
115 return is_object( $id ) && ! empty( $id->pid ) && is_numeric( $id->pid );
116 }
117
118
119 /** ----------------------------------------------------------------------------------------- */
120 /** NGG SPECIFICS =========================================================================== */
121 /** ----------------------------------------------------------------------------------------- */
122
123 /**
124 * Get the NGG image object.
125 *
126 * @since 1.9
127 * @access public
128 * @author Grégory Viguier
129 *
130 * @return \nggImage
131 */
132 public function get_ngg_image() {
133 return $this->image;
134 }
135
136 /**
137 * Get the NGG storage object.
138 *
139 * @since 1.9
140 * @access public
141 * @author Grégory Viguier
142 *
143 * @return \C_Gallery_Storage
144 */
145 public function get_ngg_storage() {
146 return $this->storage;
147 }
148
149
150 /** ----------------------------------------------------------------------------------------- */
151 /** ORIGINAL FILE =========================================================================== */
152 /** ----------------------------------------------------------------------------------------- */
153
154 /**
155 * Get the original file path, even if the file doesn't exist.
156 *
157 * @since 1.9
158 * @access public
159 * @author Grégory Viguier
160 *
161 * @return string|bool The file path. False on failure.
162 */
163 public function get_raw_original_path() {
164 if ( ! $this->is_valid() ) {
165 return false;
166 }
167
168 if ( $this->get_cdn() ) {
169 return $this->get_cdn()->get_file_path( 'original' );
170 }
171
172 return ! empty( $this->image->imagePath ) ? $this->image->imagePath : false;
173 }
174
175
176 /** ----------------------------------------------------------------------------------------- */
177 /** FULL SIZE FILE ========================================================================== */
178 /** ----------------------------------------------------------------------------------------- */
179
180 /**
181 * Get the URL of the media’s full size file.
182 *
183 * @since 1.9.8
184 * @access public
185 * @author Grégory Viguier
186 *
187 * @return string|bool The file URL. False on failure.
188 */
189 public function get_fullsize_url() {
190 if ( ! $this->is_valid() ) {
191 return false;
192 }
193
194 if ( $this->get_cdn() ) {
195 return $this->get_cdn()->get_file_url();
196 }
197
198 return ! empty( $this->image->imageURL ) ? $this->image->imageURL : false;
199 }
200
201 /**
202 * Get the path to the media’s full size file, even if the file doesn't exist.
203 *
204 * @since 1.9.8
205 * @access public
206 * @author Grégory Viguier
207 *
208 * @return string|bool The file path. False on failure.
209 */
210 public function get_raw_fullsize_path() {
211 if ( ! $this->is_valid() ) {
212 return false;
213 }
214
215 if ( $this->get_cdn() ) {
216 return $this->get_cdn()->get_file_path();
217 }
218
219 return ! empty( $this->image->imagePath ) ? $this->image->imagePath : false;
220 }
221
222
223 /** ----------------------------------------------------------------------------------------- */
224 /** BACKUP FILE ============================================================================= */
225 /** ----------------------------------------------------------------------------------------- */
226
227 /**
228 * Get the backup URL, even if the file doesn't exist.
229 *
230 * @since 1.9
231 * @access public
232 * @author Grégory Viguier
233 *
234 * @return string|bool The file URL. False on failure.
235 */
236 public function get_backup_url() {
237 if ( ! $this->is_valid() ) {
238 return false;
239 }
240
241 return site_url( '/' . $this->filesystem->make_path_relative( $this->get_raw_backup_path() ) );
242 }
243
244 /**
245 * Get the backup file path, even if the file doesn't exist.
246 *
247 * @since 1.9
248 * @access public
249 * @author Grégory Viguier
250 *
251 * @return string|bool The file path. False on failure.
252 */
253 public function get_raw_backup_path() {
254 if ( ! $this->is_valid() ) {
255 return false;
256 }
257
258 return get_imagify_ngg_attachment_backup_path( $this->get_raw_original_path() );
259 }
260
261
262 /** ----------------------------------------------------------------------------------------- */
263 /** THUMBNAILS ============================================================================== */
264 /** ----------------------------------------------------------------------------------------- */
265
266 /**
267 * Create the media thumbnails.
268 *
269 * @since 1.9
270 * @access public
271 * @author Grégory Viguier
272 *
273 * @return bool|WP_Error True on success. A \WP_Error instance on failure.
274 */
275 public function generate_thumbnails() {
276 if ( ! $this->is_valid() ) {
277 return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
278 }
279
280 $image_data = $this->storage->_image_mapper->find( $this->get_id() ); // stdClass Object.
281
282 if ( ! $image_data ) {
283 // ¯\(°_o)/¯
284 return new \WP_Error( 'no_ngg_image', __( 'Image not found in NextGen Gallery data.', 'imagify' ) );
285 }
286
287 if ( empty( $image_data->meta_data['backup'] ) || ! is_array( $image_data->meta_data['backup'] ) ) {
288 $full_path = $this->storage->get_image_abspath( $image_data );
289
290 $image_data->meta_data['backup'] = [
291 'filename' => $this->filesystem->file_name( $full_path ), // Yes, $full_path.
292 'width' => $image_data->meta_data['width'], // Original image width.
293 'height' => $image_data->meta_data['height'], // Original image height.
294 'generated' => microtime(),
295 ];
296 }
297
298 $backup_path = $this->storage->get_image_abspath( $image_data, 'backup' );
299 $failed = [];
300
301 foreach ( $this->get_media_files() as $size_name => $size_data ) {
302 if ( 'full' === $size_name ) {
303 continue;
304 }
305
306 $params = $this->storage->get_image_size_params( $image_data, $size_name );
307 $thumbnail = @$this->storage->generate_image_clone( // Don't remove this @ or the sky will fall.
308 $backup_path,
309 $this->storage->get_image_abspath( $image_data, $size_name ),
310 $params
311 );
312
313 if ( ! $thumbnail ) {
314 // Failed.
315 $failed[] = $size_name;
316 unset( $image_data->meta_data[ $size_name ] );
317 continue;
318 }
319
320 $size_meta = [
321 'width' => 0,
322 'height' => 0,
323 'filename' => \M_I18n::mb_basename( $thumbnail->fileName ),
324 'generated' => microtime(),
325 ];
326
327 $dimensions = $this->filesystem->get_image_size( $thumbnail->fileName );
328
329 if ( $dimensions ) {
330 $size_meta['width'] = $dimensions['width'];
331 $size_meta['height'] = $dimensions['height'];
332 }
333
334 if ( isset( $params['crop_frame'] ) ) {
335 $size_meta['crop_frame'] = $params['crop_frame'];
336 }
337
338 $image_data->meta_data[ $size_name ] = $size_meta;
339 } // End foreach().
340
341 // Keep our property up to date.
342 $this->image->_ngiw->_cache['meta_data'] = $image_data->meta_data;
343 $this->image->_ngiw->_orig_image = $image_data;
344
345 $post_id = $this->storage->_image_mapper->save( $image_data );
346
347 if ( ! $post_id ) {
348 return new \WP_Error( 'meta_data_not_saved', __( 'Related NextGen Gallery data could not be saved.', 'imagify' ) );
349 }
350
351 if ( $failed ) {
352 return new \WP_Error(
353 'thumbnail_restore_failed',
354 sprintf( _n( '%n thumbnail could not be restored.', '%n thumbnails could not be restored.', count( $failed ), 'imagify' ), count( $failed ) ),
355 [ 'failed_thumbnails' => $failed ]
356 );
357 }
358
359 return true;
360 }
361
362
363 /** ----------------------------------------------------------------------------------------- */
364 /** MEDIA DATA ============================================================================== */
365 /** ----------------------------------------------------------------------------------------- */
366
367 /**
368 * Tell if the current media has the required data (the data containing the file paths and thumbnails).
369 *
370 * @since 1.9
371 * @access public
372 * @author Grégory Viguier
373 *
374 * @return bool
375 */
376 public function has_required_media_data() {
377 static $sizes;
378
379 if ( ! $this->is_valid() ) {
380 return false;
381 }
382
383 if ( ! isset( $sizes ) ) {
384 $sizes = $this->get_media_files();
385 }
386
387 return $sizes && ! empty( $this->image->imagePath );
388 }
389
390 /**
391 * Get the list of the files of this media, including the full size file.
392 *
393 * @since 1.9
394 * @access public
395 * @author Grégory Viguier
396 *
397 * @return array {
398 * An array with the size names as keys ('full' is used for the full size file), and arrays of data as values:
399 *
400 * @type string $size The size name.
401 * @type string $path Absolute path to the file.
402 * @type int $width The file width.
403 * @type int $height The file height.
404 * @type string $mime-type The file mime type.
405 * @type bool $disabled True if the size is disabled in the plugin’s settings.
406 * }
407 */
408 public function get_media_files() {
409 if ( ! $this->is_valid() ) {
410 return [];
411 }
412
413 $fullsize_path = $this->get_raw_fullsize_path();
414
415 if ( ! $fullsize_path ) {
416 return [];
417 }
418
419 $dimensions = $this->get_dimensions();
420 $all_sizes = [
421 'full' => [
422 'size' => 'full',
423 'path' => $fullsize_path,
424 'width' => $dimensions['width'],
425 'height' => $dimensions['height'],
426 'mime-type' => $this->get_mime_type(),
427 'disabled' => false,
428 ],
429 ];
430
431 if ( ! $this->is_image() ) {
432 return $this->filter_media_files( $all_sizes );
433 }
434
435 // Remove common values (that have no value for us here, lol). Also remove 'full' and 'backup'.
436 $image_data = array_diff_key( $this->image->meta_data, [
437 'full' => 1,
438 'backup' => 1,
439 'width' => 1,
440 'height' => 1,
441 'md5' => 1,
442 'aperture' => 1,
443 'credit' => 1,
444 'camera' => 1,
445 'caption' => 1,
446 'created_timestamp' => 1,
447 'copyright' => 1,
448 'focal_length' => 1,
449 'iso' => 1,
450 'shutter_speed' => 1,
451 'flash' => 1,
452 'title' => 1,
453 'keywords' => 1,
454 'saved' => 1,
455 ] );
456
457 if ( ! $image_data ) {
458 return $this->filter_media_files( $all_sizes );
459 }
460
461 $ngg_data = $this->storage->_image_mapper->find( $this->get_id() );
462
463 foreach ( $image_data as $size => $size_data ) {
464 if ( ! isset( $size_data['width'], $size_data['height'], $size_data['filename'], $size_data['generated'] ) ) {
465 continue;
466 }
467
468 $file_type = (object) wp_check_filetype( $size_data['filename'], $this->get_allowed_mime_types() );
469
470 if ( ! $file_type->type ) {
471 continue;
472 }
473
474 $all_sizes[ $size ] = [
475 'size' => $size,
476 'path' => $this->storage->get_image_abspath( $ngg_data, $size ),
477 'width' => (int) $size_data['width'],
478 'height' => (int) $size_data['height'],
479 'mime-type' => $file_type->type,
480 'disabled' => false,
481 ];
482 }
483
484 return $this->filter_media_files( $all_sizes );
485 }
486
487 /**
488 * If the media is an image, get its width and height.
489 *
490 * @since 1.9
491 * @access public
492 * @author Grégory Viguier
493 *
494 * @return array
495 */
496 public function get_dimensions() {
497 if ( ! $this->is_image() ) {
498 return [
499 'width' => 0,
500 'height' => 0,
501 ];
502 }
503
504 return [
505 'width' => ! empty( $this->image->meta_data['width'] ) ? (int) $this->image->meta_data['width'] : 0,
506 'height' => ! empty( $this->image->meta_data['height'] ) ? (int) $this->image->meta_data['height'] : 0,
507 ];
508 }
509
510 /**
511 * Update the media data dimensions.
512 *
513 * @since 1.9
514 * @access public
515 * @author Grégory Viguier
516 *
517 * @param array $dimensions {
518 * An array containing width and height.
519 *
520 * @type int $width The image width.
521 * @type int $height The image height.
522 * }
523 */
524 protected function update_media_data_dimensions( $dimensions ) {
525 $changed = false;
526 $data = [
527 'width' => $dimensions['width'],
528 'height' => $dimensions['height'],
529 'md5' => md5_file( $this->get_raw_fullsize_path() ),
530 ];
531
532 foreach ( $data as $k => $v ) {
533 if ( ! isset( $this->image->meta_data[ $k ] ) || $this->image->meta_data[ $k ] !== $v ) {
534 $this->image->meta_data[ $k ] = $v;
535 $changed = true;
536 }
537 }
538
539 if ( $changed ) {
540 \nggdb::update_image_meta( $this->id, $this->image->meta_data );
541 }
542 }
543 }
544