PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.3.1
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.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 / Bulk / WP.php

WP.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 2.3.1, at classes/Bulk/WP.php

428 lines 11.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Imagify\Bulk;
3
4 use Imagify_DB;
5
6 /**
7 * Class to use for bulk for WP attachments.
8 *
9 * @since 1.9
10 */
11 class WP extends AbstractBulk {
12 /**
13 * Context "short name".
14 *
15 * @var string
16 * @since 1.9
17 */
18 protected $context = 'wp';
19
20 /**
21 * Get all unoptimized media ids.
22 *
23 * @since 1.9
24 *
25 * @param int $optimization_level The optimization level.
26 *
27 * @return array A list of unoptimized media IDs.
28 */
29 public function get_unoptimized_media_ids( $optimization_level ) {
30 global $wpdb;
31
32 $this->set_no_time_limit();
33
34 $mime_types = Imagify_DB::get_mime_types();
35 $statuses = Imagify_DB::get_post_statuses();
36 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
37 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause(
38 [
39 'prepared' => true,
40 ]
41 );
42 $ids = $wpdb->get_col(
43 $wpdb->prepare( // WPCS: unprepared SQL ok.
44 "
45 SELECT DISTINCT p.ID
46 FROM $wpdb->posts AS p
47 $nodata_join
48 LEFT JOIN $wpdb->postmeta AS mt1
49 ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
50 LEFT JOIN $wpdb->postmeta AS mt2
51 ON ( p.ID = mt2.post_id AND mt2.meta_key = '_imagify_optimization_level' )
52 WHERE
53 p.post_mime_type IN ( $mime_types )
54 AND (
55 mt1.meta_value = 'error'
56 OR
57 mt2.meta_value != %d
58 OR
59 mt2.post_id IS NULL
60 )
61 AND p.post_type = 'attachment'
62 AND p.post_status IN ( $statuses )
63 $nodata_where
64 ORDER BY
65 CASE mt1.meta_value
66 WHEN 'already_optimized' THEN 2
67 ELSE 1
68 END ASC,
69 p.ID DESC
70 LIMIT 0, %d",
71 $optimization_level,
72 imagify_get_unoptimized_attachment_limit()
73 )
74 );
75
76 $wpdb->flush();
77 unset( $mime_types );
78 $ids = array_filter( array_map( 'absint', $ids ) );
79
80 if ( ! $ids ) {
81 return [];
82 }
83
84 $metas = Imagify_DB::get_metas(
85 [
86 // Get attachments filename.
87 'filenames' => '_wp_attached_file',
88 // Get attachments data.
89 'data' => '_imagify_data',
90 // Get attachments optimization level.
91 'optimization_levels' => '_imagify_optimization_level',
92 // Get attachments status.
93 'statuses' => '_imagify_status',
94 ],
95 $ids
96 );
97
98 // First run.
99 foreach ( $ids as $i => $id ) {
100 $attachment_status = isset( $metas['statuses'][ $id ] ) ? $metas['statuses'][ $id ] : false;
101 $attachment_optimization_level = isset( $metas['optimization_levels'][ $id ] ) ? $metas['optimization_levels'][ $id ] : false;
102 $attachment_error = '';
103
104 if ( isset( $metas['data'][ $id ]['sizes']['full']['error'] ) ) {
105 $attachment_error = $metas['data'][ $id ]['sizes']['full']['error'];
106 }
107
108 // Don't try to re-optimize if the optimization level is still the same.
109 if ( $optimization_level === $attachment_optimization_level && is_string( $attachment_error ) ) {
110 unset( $ids[ $i ] );
111 continue;
112 }
113
114 // Don't try to re-optimize images already compressed.
115 if ( 'already_optimized' === $attachment_status && $attachment_optimization_level >= $optimization_level ) {
116 unset( $ids[ $i ] );
117 continue;
118 }
119
120 $attachment_error = trim( $attachment_error );
121
122 // Don't try to re-optimize images with an empty error message.
123 if ( 'error' === $attachment_status && empty( $attachment_error ) ) {
124 unset( $ids[ $i ] );
125 }
126 }
127
128 if ( ! $ids ) {
129 return [];
130 }
131
132 $ids = array_values( $ids );
133
134 /**
135 * Fires before testing for file existence.
136 *
137 * @since 1.6.7
138 *
139 * @param array $ids An array of attachment IDs.
140 * @param array $metas An array of the data fetched from the database.
141 * @param int $optimization_level The optimization level that will be used for the optimization.
142 */
143 do_action( 'imagify_bulk_optimize_before_file_existence_tests', $ids, $metas, $optimization_level );
144
145 $data = [];
146
147 foreach ( $ids as $i => $id ) {
148 if ( empty( $metas['filenames'][ $id ] ) ) {
149 // Problem.
150 continue;
151 }
152
153 $file_path = get_imagify_attached_file( $metas['filenames'][ $id ] );
154
155 if ( ! $file_path || ! $this->filesystem->exists( $file_path ) ) {
156 continue;
157 }
158
159 $attachment_backup_path = get_imagify_attachment_backup_path( $file_path );
160 $attachment_status = isset( $metas['statuses'][ $id ] ) ? $metas['statuses'][ $id ] : false;
161 $attachment_optimization_level = isset( $metas['optimization_levels'][ $id ] ) ? $metas['optimization_levels'][ $id ] : false;
162
163 // Don't try to re-optimize if there is no backup file.
164 if ( 'success' === $attachment_status && $optimization_level !== $attachment_optimization_level && ! $this->filesystem->exists( $attachment_backup_path ) ) {
165 continue;
166 }
167
168 $data[] = $id;
169 }
170
171 return $data;
172 }
173
174 /**
175 * Get all optimized media IDs that have a backup file available for restore.
176 *
177 * @return array A list of media IDs.
178 */
179 public function get_optimized_media_ids(): array {
180 global $wpdb;
181
182 $this->set_no_time_limit();
183
184 $mime_types = Imagify_DB::get_mime_types();
185 $statuses = Imagify_DB::get_post_statuses();
186 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
187 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause(
188 [
189 'prepared' => true,
190 ]
191 );
192 $ids = $wpdb->get_col(
193 $wpdb->prepare( // WPCS: unprepared SQL ok.
194 "
195 SELECT DISTINCT p.ID
196 FROM $wpdb->posts AS p
197 $nodata_join
198 INNER JOIN $wpdb->postmeta AS mt1
199 ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
200 WHERE
201 p.post_mime_type IN ( $mime_types )
202 AND mt1.meta_value IN ( 'success', 'already_optimized' )
203 AND p.post_type = 'attachment'
204 AND p.post_status IN ( $statuses )
205 $nodata_where
206 ORDER BY p.ID DESC
207 LIMIT 0, %d",
208 imagify_get_unoptimized_attachment_limit()
209 )
210 );
211
212 $wpdb->flush();
213 unset( $mime_types, $statuses );
214 $ids = array_filter( array_map( 'absint', $ids ) );
215
216 if ( ! $ids ) {
217 return [];
218 }
219
220 $metas = Imagify_DB::get_metas(
221 [
222 // Get attachments filename.
223 'filenames' => '_wp_attached_file',
224 ],
225 $ids
226 );
227
228 $data = [];
229
230 foreach ( $ids as $id ) {
231 if ( empty( $metas['filenames'][ $id ] ) ) {
232 // Problem.
233 continue;
234 }
235
236 $file_path = get_imagify_attached_file( $metas['filenames'][ $id ] );
237
238 if ( ! $file_path ) {
239 continue;
240 }
241
242 $attachment_backup_path = get_imagify_attachment_backup_path( $file_path );
243
244 if ( ! $this->filesystem->exists( $attachment_backup_path ) ) {
245 // No backup, cannot restore.
246 continue;
247 }
248
249 $data[] = $id;
250 }
251
252 return $data;
253 }
254
255 /**
256 * Get ids of all optimized media without Next gen versions.
257 *
258 * @since 2.2
259 *
260 * @param string $format Format we are looking for. (webp|avif).
261 *
262 * @return array {
263 * @type array $ids A list of media IDs.
264 * @type array $errors {
265 * @type array $no_file_path A list of media IDs.
266 * @type array $no_backup A list of media IDs.
267 * }
268 * }
269 */
270 public function get_optimized_media_ids_without_format( $format ) {
271 global $wpdb;
272
273 $this->set_no_time_limit();
274
275 $mime_types = Imagify_DB::get_mime_types( 'image' );
276
277 // Remove single quotes and explode string into array.
278 $mime_types_array = explode( ',', str_replace( "'", '', $mime_types ) );
279
280 // Iterate over array and check if string contains input.
281 foreach ( $mime_types_array as $item ) {
282 if ( strpos( $item, $format ) !== false ) {
283 $mime = $item;
284 break;
285 }
286 }
287 if ( ! isset( $mime ) && empty( $mime ) ) {
288 $mime = 'image/webp';
289 }
290 $mime = trim( $mime );
291 $mime_types = str_replace( [ ", '" . $mime . "'", ",'" . $mime . "'" ], '', $mime_types );
292 $statuses = Imagify_DB::get_post_statuses();
293 $nodata_join = '';
294 $nodata_where = '';
295 if ( ! imagify_has_attachments_without_required_metadata() ) {
296 $nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
297 $nodata_where = Imagify_DB::get_required_wp_metadata_where_clause(
298 [
299 'prepared' => true,
300 ]
301 );
302 }
303
304 $nextgen_suffix = constant( imagify_get_optimization_process_class_name( 'wp' ) . '::' . strtoupper( $format ) . '_SUFFIX' );
305
306 $ids = $wpdb->get_col(
307 $wpdb->prepare( // WPCS: unprepared SQL ok.
308 "
309 SELECT p.ID
310 FROM $wpdb->posts AS p
311 $nodata_join
312 LEFT JOIN $wpdb->postmeta AS mt1
313 ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
314 LEFT JOIN $wpdb->postmeta AS mt2
315 ON ( p.ID = mt2.post_id AND mt2.meta_key = '_imagify_data' )
316 WHERE
317 p.post_mime_type IN ( $mime_types )
318 AND ( mt1.meta_value = 'success' OR mt1.meta_value = 'already_optimized' )
319 AND mt2.meta_value NOT LIKE %s
320 AND p.post_type = 'attachment'
321 AND p.post_status IN ( $statuses )
322 $nodata_where
323 ORDER BY p.ID DESC
324 LIMIT 0, %d",
325 '%' . $wpdb->esc_like( $nextgen_suffix . '";a:4:{s:7:"success";b:1;' ) . '%',
326 imagify_get_unoptimized_attachment_limit()
327 )
328 );
329
330 $wpdb->flush();
331 unset( $mime_types, $statuses, $nextgen_suffix, $mime );
332
333 $ids = array_filter( array_map( 'absint', $ids ) );
334
335 $data = [
336 'ids' => [],
337 'errors' => [
338 'no_file_path' => [],
339 'no_backup' => [],
340 ],
341 ];
342
343 if ( ! $ids ) {
344 return $data;
345 }
346
347 $metas = Imagify_DB::get_metas(
348 [
349 // Get attachments filename.
350 'filenames' => '_wp_attached_file',
351 ],
352 $ids
353 );
354
355 /**
356 * Fires before testing for file existence.
357 *
358 * @since 1.9
359 *
360 * @param array $ids An array of attachment IDs.
361 * @param array $metas An array of the data fetched from the database.
362 * @param string $context The context.
363 */
364 do_action( 'imagify_bulk_generate_nextgen_before_file_existence_tests', $ids, $metas, 'wp' );
365
366 foreach ( $ids as $i => $id ) {
367 if ( empty( $metas['filenames'][ $id ] ) ) {
368 // Problem. Should not happen, thanks to the wpdb query.
369 $data['errors']['no_file_path'][] = $id;
370 continue;
371 }
372
373 $file_path = get_imagify_attached_file( $metas['filenames'][ $id ] );
374
375 if ( ! $file_path ) {
376 // Main file not found.
377 $data['errors']['no_file_path'][] = $id;
378 continue;
379 }
380
381 // Skip files whose extension already matches the target format
382 // (e.g. a .webp file stored with incorrect post_mime_type).
383 if ( strtolower( pathinfo( $file_path, PATHINFO_EXTENSION ) ) === $format ) {
384 continue;
385 }
386
387 $backup_path = get_imagify_attachment_backup_path( $file_path );
388
389 if ( ! $this->filesystem->exists( $backup_path ) ) {
390 // No backup, no WebP.
391 $data['errors']['no_backup'][] = $id;
392 continue;
393 }
394
395 $data['ids'][] = $id;
396 }
397
398 return $data;
399 }
400
401 /**
402 * Get the context data.
403 *
404 * @since 1.9
405 *
406 * @return array {
407 * The formated data.
408 *
409 * @type string $count-optimized Number of media optimized.
410 * @type string $count-errors Number of media having an optimization error, with a link to the page listing the optimization errors.
411 * @type string $optimized-size Optimized filesize.
412 * @type string $original-size Original filesize.
413 * }
414 */
415 public function get_context_data() {
416 $total_saving_data = imagify_count_saving_data();
417 $data = [
418 'count-optimized' => imagify_count_optimized_attachments(),
419 'count-errors' => imagify_count_error_attachments(),
420 'optimized-size' => $total_saving_data['optimized_size'],
421 'original-size' => $total_saving_data['original_size'],
422 'errors_url' => get_imagify_admin_url( 'folder-errors', $this->context ),
423 ];
424
425 return $this->format_context_data( $data );
426 }
427 }
428