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

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