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
← All changes | classes/Bulk/CustomFolders.php +146 -85 1.10 → trunk View file →
@@ -1,24 +1,25 @@
1 1 <?php
2 2 namespace Imagify\Bulk;
3 3
4 -defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
4 +use Imagify_Custom_Folders;
5 +use Imagify_Files_Scan;
6 +use Imagify_Files_DB;
7 +use Imagify_Folders_DB;
8 +use Imagify_DB;
9 +use Imagify_Files_Stats;
5 10
6 11 /**
7 12 * Class to use for bulk for custom folders.
8 13 *
9 - * @since 1.9
10 - * @author Grégory Viguier
14 + * @since 1.9
11 15 */
12 16 class CustomFolders extends AbstractBulk {
13 -
14 17 /**
15 18 * Context "short name".
16 19 *
17 - * @var string
18 - * @since 1.9
19 - * @access protected
20 - * @author Grégory Viguier
20 + * @var string
21 + * @since 1.9
21 22 */
22 23 protected $context = 'custom-folders';
23 24
24 25 /**
@@ -23,24 +24,25 @@
23 24
24 25 /**
25 26 * Get all unoptimized media ids.
26 27 *
27 - * @since 1.9
28 - * @access public
29 - * @author Grégory Viguier
28 + * @since 1.9
30 29 *
31 30 * @param int $optimization_level The optimization level.
32 - * @return array A list of unoptimized media. Array keys are media IDs prefixed with an underscore character, array values are the main file’s URL.
31 + *
32 + * @return array A list of unoptimized media IDs.
33 33 */
34 34 public function get_unoptimized_media_ids( $optimization_level ) {
35 - @set_time_limit( 0 );
35 + $this->set_no_time_limit();
36 36
37 37 /**
38 38 * Get the folders from DB.
39 39 */
40 - $folders = \Imagify_Custom_Folders::get_folders( array(
41 - 'active' => true,
42 - ) );
40 + $folders = Imagify_Custom_Folders::get_folders(
41 + [
42 + 'active' => true,
43 + ]
44 + );
43 45
44 46 if ( ! $folders ) {
45 47 return [];
46 48 }
@@ -45,12 +47,11 @@
45 47 return [];
46 48 }
47 49
48 50 /**
49 - * Triggered before getting file IDs.
51 + * Fires before getting file IDs.
50 52 *
51 - * @since 1.7
52 - * @author Grégory Viguier
53 + * @since 1.7
53 54 *
54 55 * @param array $folders An array of folders data.
55 56 * @param int $optimization_level The optimization level that will be used for the optimization.
56 57 */
@@ -58,19 +59,21 @@
58 59
59 60 /**
60 61 * Get the files from DB, and from the folders.
61 62 */
62 - $files = \Imagify_Custom_Folders::get_files_from_folders( $folders, [
63 - 'optimization_level' => $optimization_level,
64 - ] );
63 + $files = Imagify_Custom_Folders::get_files_from_folders(
64 + $folders,
65 + [
66 + 'optimization_level' => $optimization_level,
67 + ]
68 + );
65 69
66 70 if ( ! $files ) {
67 71 return [];
68 72 }
69 73
70 - // We need to output file URLs.
71 74 foreach ( $files as $k => $file ) {
72 - $files[ $k ] = esc_url( \Imagify_Files_Scan::remove_placeholder( $file['path'], 'url' ) );
75 + $files[ $k ] = $file['file_id'];
73 76 }
74 77
75 78 return $files;
76 79 }
@@ -75,15 +78,72 @@
75 78 return $files;
76 79 }
77 80
78 81 /**
79 - * Get ids of all optimized media without WebP versions.
82 + * Get all optimized file IDs that have a backup file available for restore.
80 83 *
81 - * @since 1.9
82 - * @since 1.9.5 The method doesn't return the IDs directly anymore.
83 - * @access public
84 - * @author Grégory Viguier
84 + * @return array A list of file IDs.
85 + */
86 + public function get_optimized_media_ids(): array {
87 + global $wpdb;
88 +
89 + $this->set_no_time_limit();
90 +
91 + $files_table = Imagify_Files_DB::get_instance()->get_table_name();
92 + $folders_table = Imagify_Folders_DB::get_instance()->get_table_name();
93 + $files = $wpdb->get_results(
94 + $wpdb->prepare( // WPCS: unprepared SQL ok.
95 + "
96 + SELECT fi.file_id, fi.path
97 + FROM $files_table AS fi
98 + INNER JOIN $folders_table AS fo
99 + ON ( fi.folder_id = fo.folder_id )
100 + WHERE
101 + fi.status IN ( 'success', 'already_optimized' )
102 + ORDER BY fi.file_id DESC
103 + LIMIT 0, %d",
104 + imagify_get_unoptimized_attachment_limit()
105 + )
106 + );
107 +
108 + $wpdb->flush();
109 + unset( $files_table, $folders_table );
110 +
111 + if ( ! $files ) {
112 + return [];
113 + }
114 +
115 + $data = [];
116 +
117 + foreach ( $files as $file ) {
118 + $file_id = absint( $file->file_id );
119 +
120 + if ( empty( $file->path ) ) {
121 + // Problem.
122 + continue;
123 + }
124 +
125 + $file_path = Imagify_Files_Scan::remove_placeholder( $file->path );
126 + $backup_path = Imagify_Custom_Folders::get_file_backup_path( $file_path );
127 +
128 + if ( ! $this->filesystem->exists( $backup_path ) ) {
129 + // No backup, cannot restore.
130 + continue;
131 + }
132 +
133 + $data[] = $file_id;
134 + }
135 +
136 + return $data;
137 + }
138 +
139 + /**
140 + * Get ids of all optimized media without Next gen versions.
85 141 *
142 + * @since 2.2
143 + *
144 + * @param string $format Format we are looking for. (webp|avif).
145 + *
86 146 * @return array {
87 147 * @type array $ids A list of media IDs.
88 148 * @type array $errors {
89 149 * @type array $no_file_path A list of media IDs.
@@ -90,33 +150,60 @@
90 150 * @type array $no_backup A list of media IDs.
91 151 * }
92 152 * }
93 153 */
94 - public function get_optimized_media_ids_without_webp() {
154 + public function get_optimized_media_ids_without_format( $format ) {
95 155 global $wpdb;
96 156
97 - @set_time_limit( 0 );
157 + $this->set_no_time_limit();
98 158
99 - $files_table = \Imagify_Files_DB::get_instance()->get_table_name();
100 - $folders_table = \Imagify_Folders_DB::get_instance()->get_table_name();
101 - $mime_types = \Imagify_DB::get_mime_types( 'image' );
102 - $webp_suffix = constant( imagify_get_optimization_process_class_name( 'custom-folders' ) . '::WEBP_SUFFIX' );
103 - $files = $wpdb->get_results( $wpdb->prepare( // WPCS: unprepared SQL ok.
104 - "
159 + $files_table = Imagify_Files_DB::get_instance()->get_table_name();
160 + $folders_table = Imagify_Folders_DB::get_instance()->get_table_name();
161 + $mime_types = Imagify_DB::get_mime_types( 'image' );
162 + // Remove single quotes and explode string into array.
163 + $mime_types_array = explode( ',', str_replace( "'", '', $mime_types ) );
164 +
165 + // Iterate over array and check if string contains input.
166 + foreach ( $mime_types_array as $item ) {
167 + if ( strpos( $item, $format ) !== false ) {
168 + $mime = $item;
169 + break;
170 + }
171 + }
172 + if ( ! isset( $mime ) && empty( $mime ) ) {
173 + $mime = 'image/webp';
174 + }
175 + $mime = trim( $mime );
176 + $mime_types = str_replace( [ ", '" . $mime . "'", ",'" . $mime . "'" ], '', $mime_types );
177 + $nextgen_suffix = constant( imagify_get_optimization_process_class_name( 'custom-folders' ) . '::' . strtoupper( $format ) . '_SUFFIX' );
178 + $files = $wpdb->get_results(
179 + $wpdb->prepare( // WPCS: unprepared SQL ok.
180 + "
105 181 SELECT fi.file_id, fi.path
106 182 FROM $files_table as fi
107 183 INNER JOIN $folders_table AS fo
108 - ON ( fi.folder_id = fo.folder_id )
184 + ON ( fi.folder_id = fo.folder_id AND fo.active = 1 )
109 185 WHERE
110 186 fi.mime_type IN ( $mime_types )
111 187 AND ( fi.status = 'success' OR fi.status = 'already_optimized' )
112 - AND ( fi.data NOT LIKE %s OR fi.data IS NULL )
188 + AND fi.data NOT LIKE %s
189 + AND fi.data NOT LIKE %s
113 190 ORDER BY fi.file_id DESC",
114 - '%' . $wpdb->esc_like( $webp_suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
115 - ) );
191 + '%' . $wpdb->esc_like( $nextgen_suffix . '";a:4:{s:7:"success";b:1;' ) . '%',
192 + /**
193 + * Second predicate: skip files the API permanently refused to convert (the next-gen file
194 + * would be heavier than the original, or the file is already compressed). Those are stored
195 + * as `<size><suffix>";a:3:{s:15:"permanent_error";b:1;s:7:"success";b:0;s:5:"error";…`.
196 + * Transient failures serialize as a 2-element array without the `permanent_error` key, so
197 + * they keep being retried. Matching serialized data with LIKE is fragile: the key order
198 + * written in Optimization\Data\CustomFolders must not change.
199 + */
200 + '%' . $wpdb->esc_like( $nextgen_suffix . '";a:3:{s:15:"permanent_error";b:1;' ) . '%'
201 + )
202 + );
116 203
117 204 $wpdb->flush();
118 - unset( $mime_types, $files_table, $folders_table, $webp_suffix );
205 + unset( $mime_types, $files_table, $folders_table, $nextgen_suffix, $mime );
119 206
120 207 $data = [
121 208 'ids' => [],
122 209 'errors' => [
@@ -137,11 +224,18 @@
137 224 $data['errors']['no_file_path'][] = $file_id;
138 225 continue;
139 226 }
140 227
141 - $file_path = \Imagify_Files_Scan::remove_placeholder( $file->path );
142 - $backup_path = \Imagify_Custom_Folders::get_file_backup_path( $file_path );
228 + $file_path = Imagify_Files_Scan::remove_placeholder( $file->path );
143 229
230 + // Skip files whose extension already matches the target format
231 + // (e.g. a .webp file stored with incorrect post_mime_type).
232 + if ( strtolower( pathinfo( $file_path, PATHINFO_EXTENSION ) ) === $format ) {
233 + continue;
234 + }
235 +
236 + $backup_path = Imagify_Custom_Folders::get_file_backup_path( $file_path );
237 +
144 238 if ( ! $this->filesystem->exists( $backup_path ) ) {
145 239 // No backup, no WebP.
146 240 $data['errors']['no_backup'][] = $file_id;
147 241 continue;
@@ -147,50 +241,17 @@
147 241 continue;
148 242 }
149 243
150 244 $data['ids'][] = $file_id;
151 - } // End foreach().
245 + }
152 246
153 247 return $data;
154 248 }
155 249
156 250 /**
157 - * Tell if there are optimized media without WebP versions.
158 - *
159 - * @since 1.9
160 - * @access public
161 - * @author Grégory Viguier
162 - *
163 - * @return int The number of media.
164 - */
165 - public function has_optimized_media_without_webp() {
166 - global $wpdb;
167 -
168 - $files_table = \Imagify_Files_DB::get_instance()->get_table_name();
169 - $folders_table = \Imagify_Folders_DB::get_instance()->get_table_name();
170 - $mime_types = \Imagify_DB::get_mime_types( 'image' );
171 - $webp_suffix = constant( imagify_get_optimization_process_class_name( 'custom-folders' ) . '::WEBP_SUFFIX' );
172 -
173 - return (int) $wpdb->get_var( $wpdb->prepare( // WPCS: unprepared SQL ok.
174 - "
175 - SELECT COUNT(fi.file_id)
176 - FROM $files_table as fi
177 - INNER JOIN $folders_table AS fo
178 - ON ( fi.folder_id = fo.folder_id )
179 - WHERE
180 - fi.mime_type IN ( $mime_types )
181 - AND ( fi.status = 'success' OR fi.status = 'already_optimized' )
182 - AND ( fi.data NOT LIKE %s OR fi.data IS NULL )",
183 - '%' . $wpdb->esc_like( $webp_suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
184 - ) );
185 - }
186 -
187 - /**
188 251 * Get the context data.
189 252 *
190 - * @since 1.9
191 - * @access public
192 - * @author Grégory Viguier
253 + * @since 1.9
193 254 *
194 255 * @return array {
195 256 * The formated data.
196 257 *
@@ -200,15 +261,15 @@
200 261 * @type string $original-size Original filesize.
201 262 * }
202 263 */
203 264 public function get_context_data() {
204 - $data = array(
205 - 'count-optimized' => \Imagify_Files_Stats::count_optimized_files(),
206 - 'count-errors' => \Imagify_Files_Stats::count_error_files(),
207 - 'optimized-size' => \Imagify_Files_Stats::get_optimized_size(),
208 - 'original-size' => \Imagify_Files_Stats::get_original_size(),
265 + $data = [
266 + 'count-optimized' => Imagify_Files_Stats::count_optimized_files(),
267 + 'count-errors' => Imagify_Files_Stats::count_error_files(),
268 + 'optimized-size' => Imagify_Files_Stats::get_optimized_size(),
269 + 'original-size' => Imagify_Files_Stats::get_original_size(),
209 270 'errors_url' => get_imagify_admin_url( 'folder-errors', $this->context ),
210 - );
271 + ];
211 272
212 273 return $this->format_context_data( $data );
213 274 }
214 275 }