PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.3.0
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.3.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 / Data / AbstractData.php

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

467 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Imagify\Optimization\Data;
3
4 use Imagify\Media\MediaInterface;
5
6 /**
7 * Abstract class used to handle the optimization data of "media groups" (aka attachments).
8 *
9 * @since 1.9
10 * @author Grégory Viguier
11 */
12 abstract class AbstractData implements DataInterface {
13
14 /**
15 * Optimization data structure.
16 * This is the format returned when we "get" optimization data from the DB.
17 *
18 * @var array
19 * @since 1.9
20 * @access protected
21 * @see $this->get_optimization_data()
22 * @author Grégory Viguier
23 */
24 protected $default_optimization_data = [
25 'status' => '',
26 'message' => '',
27 'level' => false,
28 'sizes' => [],
29 'stats' => [
30 'original_size' => 0,
31 'optimized_size' => 0,
32 'percent' => 0,
33 ],
34 ];
35
36 /**
37 * The media object.
38 *
39 * @var MediaInterface
40 * @since 1.9
41 * @access protected
42 * @author Grégory Viguier
43 */
44 protected $media;
45
46 /**
47 * Filesystem object.
48 *
49 * @var object Imagify_Filesystem
50 * @since 1.9
51 * @access protected
52 * @author Grégory Viguier
53 */
54 protected $filesystem;
55
56 /**
57 * The constructor.
58 *
59 * @since 1.9
60 * @access public
61 * @see self::constructor_accepts()
62 * @author Grégory Viguier
63 *
64 * @param mixed $id An ID, or whatever type the constructor accepts.
65 */
66 public function __construct( $id ) {
67 // Set the Media instance.
68 if ( $id instanceof MediaInterface ) {
69 $this->media = $id;
70 } elseif ( static::constructor_accepts( $id ) ) {
71 $media_class = str_replace( '\\Optimization\\Data\\', '\\Media\\', get_called_class() );
72 $media_class = '\\' . ltrim( $media_class, '\\' );
73 $this->media = new $media_class( $id );
74 } else {
75 $this->media = false;
76 }
77
78 $this->filesystem = \Imagify_Filesystem::get_instance();
79 }
80
81 /**
82 * Tell if the given entry can be accepted in the constructor.
83 *
84 * @since 1.9
85 * @access public
86 * @author Grégory Viguier
87 *
88 * @param mixed $id Whatever.
89 * @return bool
90 */
91 public static function constructor_accepts( $id ) {
92 if ( $id instanceof MediaInterface ) {
93 return true;
94 }
95
96 $media_class = str_replace( '\\Optimization\\Data\\', '\\Media\\', get_called_class() );
97 $media_class = '\\' . ltrim( $media_class, '\\' );
98
99 return $media_class::constructor_accepts( $id );
100 }
101
102 /**
103 * Get the media instance.
104 *
105 * @since 1.9
106 * @access public
107 * @author Grégory Viguier
108 *
109 * @return MediaInterface|false
110 */
111 public function get_media() {
112 return $this->media;
113 }
114
115 /**
116 * Tell if the current media is valid.
117 *
118 * @since 1.9
119 * @access public
120 * @author Grégory Viguier
121 *
122 * @return bool
123 */
124 public function is_valid() {
125 return $this->get_media() && $this->get_media()->is_valid();
126 }
127
128
129 /** ----------------------------------------------------------------------------------------- */
130 /** OPTIMIZATION DATA ======================================================================= */
131 /** ----------------------------------------------------------------------------------------- */
132
133 /**
134 * Check if the main file is optimized (by Imagify).
135 *
136 * @since 1.9
137 * @access public
138 * @author Grégory Viguier
139 *
140 * @return bool True if the media is optimized.
141 */
142 public function is_optimized() {
143 return 'success' === $this->get_optimization_status();
144 }
145
146 /**
147 * Check if the main file is optimized (NOT by Imagify).
148 *
149 * @since 1.9
150 * @access public
151 * @author Grégory Viguier
152 *
153 * @return bool True if the media is optimized.
154 */
155 public function is_already_optimized() {
156 return 'already_optimized' === $this->get_optimization_status();
157 }
158
159 /**
160 * Check if the main file is optimized (by Imagify).
161 *
162 * @since 1.9
163 * @access public
164 * @author Grégory Viguier
165 *
166 * @return bool True if the media is optimized.
167 */
168 public function is_error() {
169 return 'error' === $this->get_optimization_status();
170 }
171
172 /**
173 * Get the media's optimization level.
174 *
175 * @since 1.9
176 * @access public
177 * @author Grégory Viguier
178 *
179 * @return int|false The optimization level. False if not optimized.
180 */
181 public function get_optimization_level() {
182 if ( ! $this->is_valid() ) {
183 return false;
184 }
185
186 $data = $this->get_optimization_data();
187 return $data['level'];
188 }
189
190 /**
191 * Get the media's optimization status (success or error).
192 *
193 * @since 1.9
194 * @access public
195 * @author Grégory Viguier
196 *
197 * @return string The optimization status. An empty string if there is none.
198 */
199 public function get_optimization_status() {
200 if ( ! $this->is_valid() ) {
201 return '';
202 }
203
204 $data = $this->get_optimization_data();
205 return $data['status'];
206 }
207
208 /**
209 * Count number of optimized sizes.
210 *
211 * @since 1.9
212 * @access public
213 * @author Grégory Viguier
214 *
215 * @return int Number of optimized sizes.
216 */
217 public function get_optimized_sizes_count() {
218 $data = $this->get_optimization_data();
219 $count = 0;
220
221 if ( ! $data['sizes'] ) {
222 return 0;
223 }
224
225 $context_sizes = $this->get_media()->get_media_files();
226 $data['sizes'] = array_intersect_key( $data['sizes'], $context_sizes );
227
228 if ( ! $data['sizes'] ) {
229 return 0;
230 }
231
232 foreach ( $data['sizes'] as $size ) {
233 if ( ! empty( $size['success'] ) ) {
234 ++$count;
235 }
236 }
237
238 return $count;
239 }
240
241 /**
242 * Get the original media's size (weight).
243 *
244 * @since 1.9
245 * @access public
246 * @author Grégory Viguier
247 *
248 * @param bool $human_format True to display the image human format size (1Mb).
249 * @param int $decimals Precision of number of decimal places.
250 * @return string|int
251 */
252 public function get_original_size( $human_format = true, $decimals = 2 ) {
253 if ( ! $this->is_valid() ) {
254 return $human_format ? imagify_size_format( 0, $decimals ) : 0;
255 }
256
257 $size = $this->get_optimization_data();
258 $size = ! empty( $size['sizes']['full']['original_size'] ) ? $size['sizes']['full']['original_size'] : 0;
259
260 // If nothing in the database, try to get the info from the file.
261 if ( ! $size ) {
262 // Check for the backup file first.
263 $filepath = $this->get_media()->get_backup_path();
264
265 if ( ! $filepath ) {
266 // Try the original file then.
267 $filepath = $this->get_media()->get_original_path();
268 }
269
270 $size = $filepath ? $this->filesystem->size( $filepath ) : 0;
271 }
272
273 if ( $human_format ) {
274 return imagify_size_format( (int) $size, $decimals );
275 }
276
277 return (int) $size;
278 }
279
280 /**
281 * Get the file size of the full size file.
282 * If the Nextgen size is available, it is used.
283 *
284 * @since 1.9
285 * @access public
286 * @author Grégory Viguier
287 *
288 * @param bool $human_format True to display the image human format size (1Mb).
289 * @param int $decimals Precision of number of decimal places.
290 * @param bool $use_nextgen Use the Nextgen size if available.
291 * @return string|int
292 */
293 public function get_optimized_size( $human_format = true, $decimals = 2, $use_nextgen = true ) {
294 if ( ! $this->is_valid() ) {
295 return $human_format ? imagify_size_format( 0, $decimals ) : 0;
296 }
297
298 $data = $this->get_optimization_data();
299 $media = $this->get_media();
300 $format = 'webp';
301
302 $process_class_name = imagify_get_optimization_process_class_name( $media->get_context() );
303 $nextgen_avif_size_name = 'full' . constant( $process_class_name . '::AVIF_SUFFIX' );
304 $nextgen_webp_size_name = 'full' . constant( $process_class_name . '::WEBP_SUFFIX' );
305
306 $size = 0;
307
308 if ( $use_nextgen ) {
309 /**Checking for success status before size, some cases the response is false
310 * because the image is already compressed, or we have a connection timed out
311 * */
312 $size = ! empty( $data['sizes'][ $nextgen_webp_size_name ] ) && $data['sizes'][ $nextgen_webp_size_name ]['success'] ?
313 (int) $data['sizes'][ $nextgen_webp_size_name ]['optimized_size'] : 0;
314 if ( ! empty( $data['sizes'][ $nextgen_avif_size_name ]['optimized_size'] ) &&
315 $data['sizes'][ $nextgen_avif_size_name ] ) {
316 $size = (int) $data['sizes'][ $nextgen_avif_size_name ]['optimized_size'];
317 }
318 } elseif ( ! empty( $data['sizes']['full']['optimized_size'] ) ) {
319 $size = (int) $data['sizes']['full']['optimized_size'];
320 }
321
322 if ( $size ) {
323 return $human_format ? imagify_size_format( $size, $decimals ) : $size;
324 }
325
326 // If nothing in the database, try to get the info from the file.
327 $filepath = false;
328
329 if ( $use_nextgen ) {
330 if ( ! empty( $data['sizes'][ $nextgen_avif_size_name ]['success'] ) ) {
331 $format = 'avif';
332 }
333 // Try with the Nextgen file first.
334 $filepath = $media->get_raw_fullsize_path();
335 $filepath = $filepath ? imagify_path_to_nextgen( $filepath, $format ) : false;
336
337 if ( ! $filepath || ! $this->filesystem->exists( $filepath ) ) {
338 $filepath = false;
339 }
340 }
341
342 if ( ! $filepath ) {
343 // No Nextgen? The full size then.
344 $filepath = $media->get_fullsize_path();
345 }
346
347 if ( ! $filepath ) {
348 return $human_format ? imagify_size_format( 0, $decimals ) : 0;
349 }
350
351 $size = (int) $this->filesystem->size( $filepath );
352
353 return $human_format ? imagify_size_format( $size, $decimals ) : $size;
354 }
355
356
357 /** ----------------------------------------------------------------------------------------- */
358 /** OPTIMIZATION STATS ====================================================================== */
359 /** ----------------------------------------------------------------------------------------- */
360
361 /**
362 * Get one or all statistics of a specific size.
363 *
364 * @since 1.9
365 * @access public
366 * @author Grégory Viguier
367 *
368 * @param string $size The thumbnail slug.
369 * @param string $key The specific data slug.
370 * @return array|string
371 */
372 public function get_size_data( $size = 'full', $key = '' ) {
373 $data = $this->get_optimization_data();
374
375 if ( ! isset( $data['sizes'][ $size ] ) ) {
376 return $key ? '' : [];
377 }
378
379 if ( ! $key ) {
380 return $data['sizes'][ $size ];
381 }
382
383 if ( ! isset( $data['sizes'][ $size ][ $key ] ) ) {
384 return '';
385 }
386
387 return $data['sizes'][ $size ][ $key ];
388 }
389
390 /**
391 * Get the overall statistics data or a specific one.
392 *
393 * @since 1.9
394 * @access public
395 * @author Grégory Viguier
396 *
397 * @param string $key The specific data slug.
398 * @return array|string
399 */
400 public function get_stats_data( $key = '' ) {
401 $data = $this->get_optimization_data();
402 $stats = '';
403
404 if ( empty( $data['stats'] ) ) {
405 return $key ? '' : [];
406 }
407
408 if ( ! isset( $data['stats'][ $key ] ) ) {
409 return '';
410 }
411
412 return $data['stats'][ $key ];
413 }
414
415 /**
416 * Get the optimized/original saving of the original image in percent.
417 *
418 * @since 1.9
419 * @access public
420 * @author Grégory Viguier
421 *
422 * @return float A 2-decimals float.
423 */
424 public function get_saving_percent() {
425 if ( ! $this->is_valid() ) {
426 return round( (float) 0, 2 );
427 }
428
429 $process_class_name = imagify_get_optimization_process_class_name( $this->get_media()->get_context() );
430 $nextgen_webp_size_name = 'full' . constant( $process_class_name . '::WEBP_SUFFIX' );
431 $nextgen_avif_size_name = 'full' . constant( $process_class_name . '::AVIF_SUFFIX' );
432
433 $percent = $this->get_size_data( $nextgen_avif_size_name, 'percent' );
434
435 // Check for webp version if avif is not found.
436 if ( ! $percent ) {
437 $percent = $this->get_size_data( $nextgen_webp_size_name, 'percent' );
438 }
439
440 if ( ! $percent ) {
441 $percent = $this->get_size_data( 'full', 'percent' );
442 }
443 $percent = $percent ? $percent : 0;
444
445 return round( (float) $percent, 2 );
446 }
447
448 /**
449 * Get the overall optimized/original saving (original image + all thumbnails) in percent.
450 *
451 * @since 1.9
452 * @access public
453 * @author Grégory Viguier
454 *
455 * @return float A 2-decimals float.
456 */
457 public function get_overall_saving_percent() {
458 if ( ! $this->is_valid() ) {
459 return round( (float) 0, 2 );
460 }
461
462 $percent = $this->get_stats_data( 'percent' );
463
464 return round( (float) $percent, 2 );
465 }
466 }
467