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 / functions / admin-stats.php

admin-stats.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF trunk, at inc/functions/admin-stats.php

853 lines 25.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined( 'ABSPATH' ) || exit;
3
4 /**
5 * Count number of attachments.
6 *
7 * @since 1.0
8 * @author Jonathan Buttigieg
9 *
10 * @return int The number of attachments.
11 */
12 function imagify_count_attachments() {
13 global $wpdb;
14 static $count;
15
16 /**
17 * Filter the number of attachments.
18 * 3rd party will be able to override the result.
19 *
20 * @since 1.5
21 *
22 * @param int|bool $pre_count Default is false. Provide an integer.
23 */
24 $pre_count = apply_filters( 'imagify_count_attachments', false );
25
26 if ( false !== $pre_count ) {
27 return (int) $pre_count;
28 }
29
30 if ( isset( $count ) ) {
31 return $count;
32 }
33
34 $mime_types = Imagify_DB::get_mime_types();
35 $statuses = Imagify_DB::get_post_statuses();
36 $nodata_join = '';
37 $nodata_where = '';
38
39 if ( ! imagify_has_attachments_without_required_metadata() ) {
40 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause(
41 'p.ID',
42 true,
43 true,
44 "AND p.post_mime_type IN ( $mime_types )
45 AND p.post_type = 'attachment'
46 AND p.post_status IN ( $statuses )"
47 );
48 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause();
49 }
50
51 $count = (int) $wpdb->get_var( // WPCS: unprepared SQL ok.
52 "
53 SELECT COUNT( p.ID )
54 FROM $wpdb->posts AS p
55 $nodata_join
56 WHERE p.post_mime_type IN ( $mime_types )
57 AND p.post_type = 'attachment'
58 AND p.post_status IN ( $statuses )
59 $nodata_where"
60 );
61
62 if ( $count > imagify_get_unoptimized_attachment_limit() ) {
63 set_transient( 'imagify_large_library', 1 );
64 } elseif ( get_transient( 'imagify_large_library' ) ) {
65 // In case the number is decreasing under our limit.
66 delete_transient( 'imagify_large_library' );
67 }
68
69 return $count;
70 }
71
72 /**
73 * Count number of optimized attachments with an error.
74 *
75 * @since 1.0
76 * @author Jonathan Buttigieg
77 *
78 * @return int The number of attachments.
79 */
80 function imagify_count_error_attachments() {
81 global $wpdb;
82 static $count;
83
84 /**
85 * Filter the number of optimized attachments with an error.
86 * 3rd party will be able to override the result.
87 *
88 * @since 1.5
89 *
90 * @param int|bool $pre_count Default is false. Provide an integer.
91 */
92 $pre_count = apply_filters( 'imagify_count_error_attachments', false );
93
94 if ( false !== $pre_count ) {
95 return (int) $pre_count;
96 }
97
98 if ( isset( $count ) ) {
99 return $count;
100 }
101
102 $mime_types = Imagify_DB::get_mime_types();
103 $statuses = Imagify_DB::get_post_statuses();
104 $nodata_join = '';
105 $nodata_where = '';
106
107 if ( ! imagify_has_attachments_without_required_metadata() ) {
108 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
109 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause();
110 }
111
112 $count = (int) $wpdb->get_var( // WPCS: unprepared SQL ok.
113 "
114 SELECT COUNT(*)
115 FROM (
116 SELECT p.ID
117 FROM $wpdb->posts AS p
118 $nodata_join
119 INNER JOIN $wpdb->postmeta AS mt1
120 ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
121 WHERE p.post_mime_type IN ( $mime_types )
122 AND p.post_type = 'attachment'
123 AND p.post_status IN ( $statuses )
124 AND mt1.meta_value = 'error'
125 $nodata_where GROUP BY p.ID
126 ) AS imagify_count_error"
127 );
128
129 return $count;
130 }
131
132 /**
133 * Count number of optimized attachments (by Imagify or an other tool before).
134 *
135 * @since 1.0
136 * @author Jonathan Buttigieg
137 *
138 * @return int The number of attachments.
139 */
140 function imagify_count_optimized_attachments() {
141 global $wpdb;
142 static $count;
143
144 /**
145 * Filter the number of optimized attachments.
146 * 3rd party will be able to override the result.
147 *
148 * @since 1.5
149 *
150 * @param int|bool $pre_count Default is false. Provide an integer.
151 */
152 $pre_count = apply_filters( 'imagify_count_optimized_attachments', false );
153
154 if ( false !== $pre_count ) {
155 return (int) $pre_count;
156 }
157
158 if ( isset( $count ) ) {
159 return $count;
160 }
161
162 $mime_types = Imagify_DB::get_mime_types();
163 $statuses = Imagify_DB::get_post_statuses();
164 $nodata_join = '';
165 $nodata_where = '';
166
167 if ( ! imagify_has_attachments_without_required_metadata() ) {
168 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
169 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause();
170 }
171
172 $count = (int) $wpdb->get_var( // WPCS: unprepared SQL ok.
173 "
174 SELECT COUNT( DISTINCT p.ID )
175 FROM $wpdb->posts AS p
176 $nodata_join
177 INNER JOIN $wpdb->postmeta AS mt1
178 ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
179 WHERE p.post_mime_type IN ( $mime_types )
180 AND p.post_type = 'attachment'
181 AND p.post_status IN ( $statuses )
182 AND mt1.meta_value IN ( 'success', 'already_optimized' )
183 $nodata_where"
184 );
185
186 return $count;
187 }
188
189 /**
190 * Count number of unoptimized attachments.
191 *
192 * @since 1.0
193 * @author Jonathan Buttigieg
194 *
195 * @return int The number of attachments.
196 */
197 function imagify_count_unoptimized_attachments() {
198 /**
199 * Filter the number of unoptimized attachments.
200 * 3rd party will be able to override the result.
201 *
202 * @since 1.5
203 *
204 * @param int|bool $pre_count Default is false. Provide an integer.
205 */
206 $pre_count = apply_filters( 'imagify_count_unoptimized_attachments', false );
207
208 if ( false !== $pre_count ) {
209 return (int) $pre_count;
210 }
211
212 return imagify_count_attachments() - imagify_count_optimized_attachments() - imagify_count_error_attachments();
213 }
214
215 /**
216 * Count percent of optimized attachments.
217 *
218 * @since 1.0
219 * @author Jonathan Buttigieg
220 *
221 * @return int The percent of optimized attachments.
222 */
223 function imagify_percent_optimized_attachments() {
224 /**
225 * Filter the percent of optimized attachments.
226 * 3rd party will be able to override the result.
227 *
228 * @since 1.5
229 *
230 * @param int|bool $percent Default is false. Provide an integer.
231 */
232 $percent = apply_filters( 'imagify_percent_optimized_attachments', false );
233
234 if ( false !== $percent ) {
235 return (int) $percent;
236 }
237
238 $total_attachments = imagify_count_attachments();
239 $total_optimized_attachments = imagify_count_optimized_attachments();
240
241 if ( ! $total_attachments || ! $total_optimized_attachments ) {
242 return 0;
243 }
244
245 return min( round( 100 * $total_optimized_attachments / $total_attachments ), 100 );
246 }
247
248 /**
249 * Count percent, original & optimized size of all images optimized by Imagify.
250 *
251 * @since 1.0
252 * @since 1.6.7 Revamped to handle huge libraries.
253 * @author Jonathan Buttigieg
254 *
255 * @param string $key What data to return. Choices are between 'count', 'original_size', 'optimized_size', and 'percent'. If left empty, the whole array is returned.
256 * @return array|int An array containing the optimization data. A single data if $key is provided.
257 */
258 function imagify_count_saving_data( $key = '' ) {
259 global $wpdb;
260
261 /**
262 * Filter the query to get all optimized attachments.
263 * 3rd party will be able to override the result.
264 *
265 * @since 1.5
266 * @since 1.6.7 This filter should return an array containing the following keys: 'count', 'original_size', and 'optimized_size'.
267 *
268 * @param bool|array $attachments An array containing the keys ('count', 'original_size', and 'optimized_size'), or an array of attachments (back compat', deprecated), or false.
269 */
270 $attachments = apply_filters( 'imagify_count_saving_data', false );
271
272 $original_size = 0;
273 $optimized_size = 0;
274 $count = 0;
275
276 if ( is_array( $attachments ) ) {
277 /**
278 * Bypass.
279 */
280 if ( isset( $attachments['count'], $attachments['original_size'], $attachments['optimized_size'] ) ) {
281 /**
282 * We have the results we need.
283 */
284 $attachments['percent'] = $attachments['optimized_size'] && $attachments['original_size'] ? ceil( ( ( $attachments['original_size'] - $attachments['optimized_size'] ) / $attachments['original_size'] ) * 100 ) : 0;
285
286 return $attachments;
287 }
288
289 /**
290 * Back compat'.
291 * The following shouldn't be used. Sites with a huge library won't like it.
292 */
293 $attachments = array_map( 'maybe_unserialize', (array) $attachments );
294
295 if ( $attachments ) {
296 foreach ( $attachments as $attachment_data ) {
297 if ( ! $attachment_data ) {
298 continue;
299 }
300
301 ++$count;
302 $original_data = $attachment_data['sizes']['full'];
303
304 // Increment the original sizes.
305 $original_size += $original_data['original_size'] ? $original_data['original_size'] : 0;
306 $optimized_size += $original_data['optimized_size'] ? $original_data['optimized_size'] : 0;
307
308 unset( $attachment_data['sizes']['full'] );
309
310 // Increment the thumbnails sizes.
311 if ( $attachment_data['sizes'] ) {
312 foreach ( $attachment_data['sizes'] as $size_data ) {
313 if ( ! empty( $size_data['success'] ) ) {
314 $original_size += $size_data['original_size'] ? $size_data['original_size'] : 0;
315 $optimized_size += $size_data['optimized_size'] ? $size_data['optimized_size'] : 0;
316 }
317 }
318 }
319 }
320 }
321 } else {
322 /**
323 * Filter the chunk size of the requests fetching the data.
324 * 2,000 seems to be a good balance between memory used, speed, and number of DB hits,
325 * while keeping the resulting `IN ()` clause well under hosts' SQL query size limits
326 * (e.g. WP Engine's query governor).
327 *
328 * @param int $limit The maximum number of elements per chunk.
329 */
330 $limit = apply_filters( 'imagify_count_saving_data_limit', 2000 );
331 $limit = absint( $limit );
332
333 $mime_types = Imagify_DB::get_mime_types();
334 $statuses = Imagify_DB::get_post_statuses();
335 $nodata_join = '';
336 $nodata_where = '';
337
338 if ( ! imagify_has_attachments_without_required_metadata() ) {
339 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
340 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause();
341 }
342
343 $attachment_ids = $wpdb->get_col( // WPCS: unprepared SQL ok.
344 "
345 SELECT p.ID
346 FROM $wpdb->posts AS p
347 $nodata_join
348 INNER JOIN $wpdb->postmeta AS mt1
349 ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
350 WHERE p.post_mime_type IN ( $mime_types )
351 AND p.post_type = 'attachment'
352 AND p.post_status IN ( $statuses )
353 AND mt1.meta_value = 'success'
354 $nodata_where
355 ORDER BY CAST( p.ID AS UNSIGNED )"
356 );
357 $wpdb->flush();
358
359 $attachment_ids = array_map( 'absint', array_unique( $attachment_ids ) );
360 $attachment_ids = array_chunk( $attachment_ids, $limit );
361
362 while ( $attachment_ids ) {
363 $limit_ids = array_shift( $attachment_ids );
364 // Safety net: further split the chunk if its rendered `IN ()` list would still be too long.
365 $id_chunks = Imagify_DB::chunk_in_values( $limit_ids );
366 $attachments = [];
367
368 foreach ( $id_chunks as $id_chunk ) {
369 $id_chunk_list = implode( ',', $id_chunk );
370
371 $chunk_attachments = $wpdb->get_col( // WPCS: unprepared SQL ok.
372 "
373 SELECT meta_value
374 FROM $wpdb->postmeta
375 WHERE post_id IN ( $id_chunk_list )
376 AND meta_key = '_imagify_data'"
377 );
378
379 if ( $chunk_attachments ) {
380 $attachments = array_merge( $attachments, $chunk_attachments );
381 }
382 }
383 $wpdb->flush();
384
385 unset( $limit_ids );
386
387 if ( ! $attachments ) {
388 continue;
389 }
390
391 $attachments = array_map( 'maybe_unserialize', $attachments );
392
393 foreach ( $attachments as $attachment_data ) {
394 if ( ! $attachment_data ) {
395 continue;
396 }
397
398 if ( empty( $attachment_data['sizes']['full']['success'] ) ) {
399 /**
400 * - Case where this attachment has multiple '_imagify_status' metas, and is fetched (in the above query) as a "success" while the '_imagify_data' says otherwise.
401 * - Case where this meta has no "full" entry.
402 * Don't ask how it's possible, I don't know ¯\(°_o)/¯
403 */
404 continue;
405 }
406
407 $original_data = $attachment_data['sizes']['full'];
408
409 ++$count;
410
411 // Increment the original sizes.
412 $original_size += ! empty( $original_data['original_size'] ) ? $original_data['original_size'] : 0;
413 $optimized_size += ! empty( $original_data['optimized_size'] ) ? $original_data['optimized_size'] : 0;
414
415 unset( $attachment_data['sizes']['full'], $original_data );
416
417 // Increment the thumbnails sizes.
418 if ( $attachment_data['sizes'] ) {
419 foreach ( $attachment_data['sizes'] as $size_data ) {
420 if ( ! empty( $size_data['success'] ) ) {
421 $original_size += ! empty( $size_data['original_size'] ) ? $size_data['original_size'] : 0;
422 $optimized_size += ! empty( $size_data['optimized_size'] ) ? $size_data['optimized_size'] : 0;
423 }
424 }
425 }
426
427 unset( $size_data );
428 }
429
430 unset( $attachments, $attachment_data );
431 }
432 }
433
434 $data = [
435 'count' => $count,
436 'original_size' => $original_size,
437 'optimized_size' => $optimized_size,
438 'percent' => $original_size && $optimized_size ? ceil( ( ( $original_size - $optimized_size ) / $original_size ) * 100 ) : 0,
439 ];
440
441 if ( ! empty( $key ) ) {
442 return isset( $data[ $key ] ) ? $data[ $key ] : 0;
443 }
444
445 return $data;
446 }
447
448 /**
449 * Returns the estimated total size of the images not optimized.
450 *
451 * We estimate the total size of the images in the library by getting the latest 250 images and their thumbnails
452 * add up their filesizes, and doing some maths to get the total size.
453 *
454 * @since 1.6
455 * @author Remy Perona
456 *
457 * @return int The current estimated total size of images not optimized.
458 */
459 function imagify_calculate_total_size_images_library() {
460 global $wpdb;
461
462 $mime_types = Imagify_DB::get_mime_types();
463 $statuses = Imagify_DB::get_post_statuses();
464 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
465 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause();
466 $image_ids = $wpdb->get_col( // WPCS: unprepared SQL ok.
467 "
468 SELECT p.ID
469 FROM $wpdb->posts AS p
470 $nodata_join
471 WHERE p.post_mime_type IN ( $mime_types )
472 AND p.post_type = 'attachment'
473 AND p.post_status IN ( $statuses )
474 $nodata_where
475 LIMIT 250
476 "
477 );
478
479 if ( ! $image_ids ) {
480 return 0;
481 }
482
483 $count_latest_images = count( $image_ids );
484 $count_total_images = imagify_count_attachments();
485
486 return imagify_calculate_total_image_size( $image_ids, $count_latest_images, $count_total_images );
487 }
488
489 /**
490 * Returns the estimated average size of the images uploaded per month.
491 *
492 * We estimate the average size of the images uploaded in the library per month by getting the latest 250 images and their thumbnails
493 * for the 3 latest months, add up their filesizes, and doing some maths to get the total average size.
494 *
495 * @since 1.6
496 * @since 1.7 Use wpdb instead of WP_Query.
497 * @author Remy Perona
498 *
499 * @return int The current estimated average size of images uploaded per month.
500 */
501 function imagify_calculate_average_size_images_per_month() {
502 global $wpdb;
503
504 $mime_types = Imagify_DB::get_mime_types();
505 $statuses = Imagify_DB::get_post_statuses();
506 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause( "$wpdb->posts.ID" );
507 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause();
508 $limit = ' LIMIT 0, 250';
509 $query = "
510 SELECT $wpdb->posts.ID
511 FROM $wpdb->posts
512 $nodata_join
513 WHERE $wpdb->posts.post_mime_type IN ( $mime_types )
514 AND $wpdb->posts.post_type = 'attachment'
515 AND $wpdb->posts.post_status IN ( $statuses )
516 $nodata_where
517 %date_query%";
518
519 // Queries per month.
520 $date_query = new WP_Date_Query(
521 [
522 [
523 'before' => 'now',
524 'after' => '1 month ago',
525 ],
526 ]
527 );
528
529 $partial_images_uploaded_last_month = $wpdb->get_col( str_replace( '%date_query%', $date_query->get_sql(), $query . $limit ) ); // WPCS: unprepared SQL ok.
530
531 $date_query = new WP_Date_Query(
532 [
533 [
534 'before' => '1 month ago',
535 'after' => '2 months ago',
536 ],
537 ]
538 );
539
540 $partial_images_uploaded_two_months_ago = $wpdb->get_col( str_replace( '%date_query%', $date_query->get_sql(), $query . $limit ) ); // WPCS: unprepared SQL ok.
541
542 $date_query = new WP_Date_Query(
543 [
544 [
545 'before' => '2 month ago',
546 'after' => '3 months ago',
547 ],
548 ]
549 );
550
551 $partial_images_uploaded_three_months_ago = $wpdb->get_col( str_replace( '%date_query%', $date_query->get_sql(), $query . $limit ) ); // WPCS: unprepared SQL ok.
552
553 // Total for the 3 months.
554 $partial_images_uploaded_id = array_merge( $partial_images_uploaded_last_month, $partial_images_uploaded_two_months_ago, $partial_images_uploaded_three_months_ago );
555
556 if ( ! $partial_images_uploaded_id ) {
557 return 0;
558 }
559
560 // Total for the 3 months, without the "250" limit.
561 $date_query = new WP_Date_Query(
562 [
563 [
564 'before' => 'now',
565 'after' => '3 month ago',
566 ],
567 ]
568 );
569
570 $images_uploaded_id = $wpdb->get_col( str_replace( '%date_query%', $date_query->get_sql(), $query ) ); // WPCS: unprepared SQL ok.
571
572 if ( ! $images_uploaded_id ) {
573 return 0;
574 }
575
576 // Number of image attachments uploaded for the 3 latest months, limited to 250 per month.
577 $partial_total_images_uploaded = count( $partial_images_uploaded_id );
578 // Total number of image attachments uploaded for the 3 latest months.
579 $total_images_uploaded = count( $images_uploaded_id );
580
581 return imagify_calculate_total_image_size( $partial_images_uploaded_id, $partial_total_images_uploaded, $total_images_uploaded ) / 3;
582 }
583
584 /**
585 * Returns the estimated total size of images.
586 *
587 * @since 1.6
588 * @author Remy Perona
589 *
590 * @param array $image_ids Array of image IDs.
591 * @param int $partial_total_images The number of image attachments we're doing the calculation with.
592 * @param int $total_images The total number of image attachments.
593 * @return int The estimated total size of images.
594 */
595 function imagify_calculate_total_image_size( $image_ids, $partial_total_images, $total_images ) {
596 global $wpdb;
597
598 $image_ids = array_filter( array_map( 'absint', $image_ids ) );
599
600 if ( ! $image_ids ) {
601 return 0;
602 }
603
604 $results = Imagify_DB::get_metas(
605 [
606 // Get attachments filename.
607 'filenames' => '_wp_attached_file',
608 // Get attachments data.
609 'data' => '_wp_attachment_metadata',
610 // Get Imagify data.
611 'imagify_data' => '_imagify_data',
612 // Get attachments status.
613 'statuses' => '_imagify_status',
614 ],
615 $image_ids
616 );
617
618 // Number of image attachments we're doing the calculation with. In case array_filter() removed results.
619 $partial_total_images = count( $image_ids );
620 // Total size of unoptimized size.
621 $partial_size_images = 0;
622 // Total number of thumbnails.
623 $partial_total_intermediate_images = 0;
624
625 $filesystem = imagify_get_filesystem();
626 $is_active_for_network = imagify_is_active_for_network();
627 $disallowed_sizes = get_imagify_option( 'disallowed-sizes' );
628
629 foreach ( $image_ids as $i => $image_id ) {
630 $attachment_status = isset( $results['statuses'][ $image_id ] ) ? $results['statuses'][ $image_id ] : false;
631
632 if ( 'success' === $attachment_status ) {
633 /**
634 * The image files have been optimized.
635 */
636 // Original size.
637 $partial_size_images += isset( $results['imagify_data'][ $image_id ]['stats']['original_size'] ) ? $results['imagify_data'][ $image_id ]['stats']['original_size'] : 0;
638 // Number of thumbnails.
639 $partial_total_intermediate_images += count( $results['imagify_data'][ $image_id ]['sizes'] );
640 unset(
641 $image_ids[ $i ],
642 $results['filenames'][ $image_id ],
643 $results['data'][ $image_id ],
644 $results['imagify_data'][ $image_id ],
645 $results['statuses'][ $image_id ]
646 );
647 continue;
648 }
649
650 /**
651 * The image files are not optimized.
652 */
653 // Create an array containing all this attachment files.
654 $files = [
655 'full' => get_imagify_attached_file( $results['filenames'][ $image_id ] ),
656 ];
657
658 $sizes = isset( $results['data'][ $image_id ]['sizes'] ) ? $results['data'][ $image_id ]['sizes'] : [];
659
660 if ( $sizes && is_array( $sizes ) ) {
661 if ( ! $is_active_for_network ) {
662 $sizes = array_diff_key( $sizes, $disallowed_sizes );
663 }
664
665 if ( $sizes ) {
666 $full_dirname = $filesystem->dir_path( $files['full'] );
667
668 foreach ( $sizes as $size_key => $size_data ) {
669 $files[ $size_key ] = $full_dirname . '/' . $size_data['file'];
670 }
671 }
672 }
673
674 /**
675 * Allow to provide all files size and the number of thumbnails.
676 *
677 * @since 1.6.7
678 * @author Grégory Viguier
679 *
680 * @param bool $size_and_count False by default.
681 * @param int $image_id The attachment ID.
682 * @param array $files An array of file paths with thumbnail sizes as keys.
683 * @param array $image_ids An array of all attachment IDs.
684 * @return bool|array False by default. Provide an array with the keys 'filesize' (containing the total filesize) and 'thumbnails' (containing the number of thumbnails).
685 */
686 $size_and_count = apply_filters( 'imagify_total_attachment_filesize', false, $image_id, $files, $image_ids );
687
688 if ( is_array( $size_and_count ) ) {
689 $partial_size_images += $size_and_count['filesize'];
690 $partial_total_intermediate_images += $size_and_count['thumbnails'];
691 } else {
692 foreach ( $files as $file ) {
693 if ( $filesystem->exists( $file ) ) {
694 $partial_size_images += $filesystem->size( $file );
695 }
696 }
697
698 unset( $files['full'] );
699 $partial_total_intermediate_images += count( $files );
700 }
701
702 unset(
703 $image_ids[ $i ],
704 $results['filenames'][ $image_id ],
705 $results['data'][ $image_id ],
706 $results['imagify_data'][ $image_id ],
707 $results['statuses'][ $image_id ]
708 );
709 }
710
711 // Number of thumbnails per attachment = Number of thumbnails / Number of attachments.
712 $intermediate_images_per_image = $partial_total_intermediate_images / $partial_total_images;
713 /**
714 * Note: Number of attachments ($partial_total_images) === Number of full sizes.
715 * Average image size = Size of the images / ( Number of full sizes + Number of thumbnails ).
716 * Average image size = Size of the images / Number of images.
717 */
718 $average_size_images = $partial_size_images / ( $partial_total_images + $partial_total_intermediate_images );
719 /**
720 * Note: Total number of attachments ($total_images) === Total number of full sizes.
721 * Total images size = Average image size * ( Total number of full sizes + ( Number of thumbnails per attachment * Total number of attachments ) ).
722 * Total images size = Average image size * ( Total number of full sizes + Total number of thumbnails ).
723 */
724 $total_size_images = $average_size_images * ( $total_images + ( $intermediate_images_per_image * $total_images ) );
725
726 return $total_size_images;
727 }
728
729 /**
730 * Get all generic stats to be used in the bulk optimization page.
731 *
732 * @since 1.7.1
733 * @author Grégory Viguier
734 *
735 * @param array $types The folder types. If a folder type is "library", the context should be suffixed after a pipe character. They are passed as array keys.
736 * @param array $args {
737 * Optional. An array of arguments.
738 *
739 * @type bool $fullset True to return the full set of data. False to return only the main data.
740 * @type bool $formatting Some of the data is returned formatted.
741 * }
742 * @return array
743 */
744 function imagify_get_bulk_stats( $types, $args = [] ) {
745 $types = $types && is_array( $types ) ? $types : [];
746 $args = array_merge(
747 [
748 'fullset' => false,
749 'formatting' => true,
750 ],
751 (array) $args
752 );
753
754 $data = [
755 // Global chart.
756 'total_attachments' => 0,
757 'unoptimized_attachments' => 0,
758 'optimized_attachments' => 0,
759 'errors_attachments' => 0,
760 // Stats block.
761 'already_optimized_attachments' => 0,
762 'original_human' => 0,
763 'optimized_human' => 0,
764 ];
765
766 if ( isset( $types['library|wp'] ) ) {
767 /**
768 * Library.
769 */
770 $saving_data = imagify_count_saving_data();
771
772 // Global chart.
773 $data['total_attachments'] += imagify_count_attachments();
774 $data['unoptimized_attachments'] += imagify_count_unoptimized_attachments();
775 $data['optimized_attachments'] += imagify_count_optimized_attachments();
776 $data['errors_attachments'] += imagify_count_error_attachments();
777 // Stats block.
778 $data['already_optimized_attachments'] += $saving_data['count'];
779 $data['original_human'] += $saving_data['original_size'];
780 $data['optimized_human'] += $saving_data['optimized_size'];
781 }
782
783 if ( isset( $types['custom-folders|custom-folders'] ) ) {
784 /**
785 * Custom folders.
786 */
787 // Global chart.
788 $data['total_attachments'] += Imagify_Files_Stats::count_all_files();
789 $data['unoptimized_attachments'] += Imagify_Files_Stats::count_no_status_files();
790 $data['optimized_attachments'] += Imagify_Files_Stats::count_optimized_files();
791 $data['errors_attachments'] += Imagify_Files_Stats::count_error_files();
792 // Stats block.
793 $data['already_optimized_attachments'] += Imagify_Files_Stats::count_success_files();
794 $data['original_human'] += Imagify_Files_Stats::get_original_size();
795 $data['optimized_human'] += Imagify_Files_Stats::get_optimized_size();
796 }
797
798 /**
799 * Full set of data.
800 */
801 if ( $args['fullset'] ) {
802 // User account.
803 $views = Imagify_Views::get_instance();
804
805 $data['unconsumed_quota'] = $views->get_quota_percent();
806 $data['quota_class'] = $views->get_quota_class();
807 $data['quota_icon'] = $views->get_quota_icon();
808 }
809
810 /**
811 * Filter the generic stats used in the bulk optimization page.
812 *
813 * @since 1.7.1
814 * @author Grégory Viguier
815 *
816 * @param array $data The data.
817 * @param array $types The folder types. They are passed as array keys.
818 * @param array $args {
819 * Optional. An array of arguments.
820 *
821 * @type bool $fullset True to return the full set of data. False to return only the main data.
822 * @type bool $formatting Some of the data is returned formatted.
823 * }
824 */
825 $data = apply_filters( 'imagify_bulk_stats', $data, $types, $args );
826
827 /**
828 * Percentages.
829 */
830 if ( $data['total_attachments'] && $data['optimized_attachments'] ) {
831 $data['optimized_attachments_percent'] = round( 100 * $data['optimized_attachments'] / $data['total_attachments'] );
832 } else {
833 $data['optimized_attachments_percent'] = 0;
834 }
835
836 if ( $data['original_human'] && $data['optimized_human'] ) {
837 $data['optimized_percent'] = ceil( 100 - ( 100 * $data['optimized_human'] / $data['original_human'] ) );
838 } else {
839 $data['optimized_percent'] = 0;
840 }
841
842 /**
843 * Formating.
844 */
845 if ( $args['formatting'] ) {
846 $data['already_optimized_attachments'] = number_format_i18n( $data['already_optimized_attachments'] );
847 $data['original_human'] = imagify_size_format( $data['original_human'], 1 );
848 $data['optimized_human'] = imagify_size_format( $data['optimized_human'], 1 );
849 }
850
851 return $data;
852 }
853