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 | inc/3rd-party/nextgen-gallery/classes/Bulk/NGG.php +130 -80 1.10 → trunk View file →
@@ -1,26 +1,22 @@
1 1 <?php
2 2 namespace Imagify\ThirdParty\NGG\Bulk;
3 3
4 -use \Imagify\ThirdParty\NGG\DB;
4 +use C_Gallery_Storage;
5 +use Imagify\Bulk\AbstractBulk;
6 +use Imagify\ThirdParty\NGG\DB;
5 7
6 -defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
7 -
8 8 /**
9 9 * Class to use for bulk for NextGen Gallery.
10 10 *
11 - * @since 1.9
12 - * @author Grégory Viguier
11 + * @since 1.9
13 12 */
14 -class NGG extends \Imagify\Bulk\AbstractBulk {
15 -
13 +class NGG extends AbstractBulk {
16 14 /**
17 15 * Context "short name".
18 16 *
19 - * @var string
20 - * @since 1.9
21 - * @access protected
22 - * @author Grégory Viguier
17 + * @var string
18 + * @since 1.9
23 19 */
24 20 protected $context = 'ngg';
25 21
26 22 /**
@@ -25,36 +21,43 @@
25 21
26 22 /**
27 23 * Get all unoptimized media ids.
28 24 *
29 - * @since 1.9
30 - * @access public
31 - * @author Grégory Viguier
25 + * @since 1.9
32 26 *
33 27 * @param int $optimization_level The optimization level.
34 - * @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.
28 + * @return array A list of unoptimized media IDs.
35 29 */
36 30 public function get_unoptimized_media_ids( $optimization_level ) {
31 + // @codeCoverageIgnoreStart — requires live NGG POPE classes and DB; not available in unit tests.
32 + if ( ! imagify_ngg_has_pope_storage() || ! DB::get_instance()->can_operate() ) {
33 + return [];
34 + }
35 + // @codeCoverageIgnoreEnd
36 +
37 37 global $wpdb;
38 38
39 - @set_time_limit( 0 );
39 + $this->set_no_time_limit();
40 40
41 - $storage = \C_Gallery_Storage::get_instance();
41 + $storage = C_Gallery_Storage::get_instance();
42 42 $ngg_table = $wpdb->prefix . 'ngg_pictures';
43 43 $data = [];
44 - $images = $wpdb->get_results( $wpdb->prepare( // WPCS: unprepared SQL ok.
45 - "
46 - SELECT DISTINCT picture.pid as id, picture.filename, idata.optimization_level, idata.status, idata.data
47 - FROM $ngg_table as picture
48 - LEFT JOIN $wpdb->ngg_imagify_data as idata
49 - ON picture.pid = idata.pid
50 - WHERE idata.pid IS NULL
51 - OR idata.optimization_level != %d
52 - OR idata.status = 'error'
53 - LIMIT %d",
54 - $optimization_level,
55 - imagify_get_unoptimized_attachment_limit()
56 - ), ARRAY_A );
44 + $images = $wpdb->get_results(
45 + $wpdb->prepare( // WPCS: unprepared SQL ok.
46 + "
47 + SELECT DISTINCT picture.pid as id, picture.filename, idata.optimization_level, idata.status, idata.data
48 + FROM $ngg_table as picture
49 + LEFT JOIN $wpdb->ngg_imagify_data as idata
50 + ON picture.pid = idata.pid
51 + WHERE idata.pid IS NULL
52 + OR idata.optimization_level != %d
53 + OR idata.status = 'error'
54 + LIMIT %d",
55 + $optimization_level,
56 + imagify_get_unoptimized_attachment_limit()
57 + ),
58 + ARRAY_A
59 + );
57 60
58 61 if ( ! $images ) {
59 62 return [];
60 63 }
@@ -98,22 +101,32 @@
98 101 if ( 'error' === $attachment_status && empty( $attachment_error ) ) {
99 102 continue;
100 103 }
101 104
102 - $data[ '_' . $id ] = esc_url( $storage->get_image_url( $id ) );
103 - } // End foreach().
105 + $data[] = $id;
106 + }
104 107
105 108 return $data;
106 109 }
107 110
108 111 /**
109 - * Get ids of all optimized media without WebP versions.
112 + * Get all optimized media ids that can be restored.
110 113 *
111 - * @since 1.9
112 - * @since 1.9.5 The method doesn't return the IDs directly anymore.
113 - * @access public
114 - * @author Grégory Viguier
114 + * @since 2.3
115 115 *
116 + * @return array A list of optimized media IDs with backup files available.
117 + */
118 + public function get_optimized_media_ids(): array {
119 + return [];
120 + }
121 +
122 + /**
123 + * Get ids of all optimized media without next-gen versions.
124 + *
125 + * @since 2.2
126 + *
127 + * @param string $format Format we are looking for. (webp|avif).
128 + *
116 129 * @return array {
117 130 * @type array $ids A list of media IDs.
118 131 * @type array $errors {
119 132 * @type array $no_file_path A list of media IDs.
@@ -120,32 +133,61 @@
120 133 * @type array $no_backup A list of media IDs.
121 134 * }
122 135 * }
123 136 */
124 - public function get_optimized_media_ids_without_webp() {
137 + public function get_optimized_media_ids_without_format( $format ) {
138 + // @codeCoverageIgnoreStart — requires live NGG POPE classes and DB; not available in unit tests.
139 + if ( ! imagify_ngg_has_pope_storage() || ! DB::get_instance()->can_operate() ) {
140 + return [
141 + 'ids' => [],
142 + 'errors' => [
143 + 'no_file_path' => [],
144 + 'no_backup' => [],
145 + ],
146 + ];
147 + }
148 + // @codeCoverageIgnoreEnd
149 +
125 150 global $wpdb;
126 151
127 - @set_time_limit( 0 );
152 + $this->set_no_time_limit();
128 153
129 - $storage = \C_Gallery_Storage::get_instance();
130 - $ngg_table = $wpdb->prefix . 'ngg_pictures';
131 - $data_table = DB::get_instance()->get_table_name();
132 - $webp_suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::WEBP_SUFFIX' );
133 - $files = $wpdb->get_col( $wpdb->prepare( // WPCS: unprepared SQL ok.
134 - "
135 - SELECT ngg.pid
136 - FROM $ngg_table as ngg
137 - INNER JOIN $data_table AS data
138 - ON ( ngg.pid = data.pid )
139 - WHERE
140 - ( data.status = 'success' OR data.status = 'already_optimized' )
141 - AND data.data NOT LIKE %s
142 - ORDER BY ngg.pid DESC",
143 - '%' . $wpdb->esc_like( $webp_suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
144 - ) );
154 + $storage = C_Gallery_Storage::get_instance();
155 + $ngg_table = $wpdb->prefix . 'ngg_pictures';
156 + $data_table = DB::get_instance()->get_table_name();
157 + $suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::WEBP_SUFFIX' );
145 158
159 + if ( 'avif' === get_imagify_option( 'optimization_format' ) ) {
160 + $suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::AVIF_SUFFIX' );
161 + }
162 +
163 + $files = $wpdb->get_col(
164 + $wpdb->prepare( // WPCS: unprepared SQL ok.
165 + "
166 + SELECT ngg.pid
167 + FROM $ngg_table as ngg
168 + INNER JOIN $data_table AS data
169 + ON ( ngg.pid = data.pid )
170 + WHERE
171 + ( data.status = 'success' OR data.status = 'already_optimized' )
172 + AND data.data NOT LIKE %s
173 + AND data.data NOT LIKE %s
174 + ORDER BY ngg.pid DESC",
175 + '%' . $wpdb->esc_like( $suffix . '";a:4:{s:7:"success";b:1;' ) . '%',
176 + /**
177 + * Second predicate: skip images the API permanently refused to convert (the next-gen file
178 + * would be heavier than the original, or the file is already compressed). Those are stored
179 + * as `<size><suffix>";a:3:{s:15:"permanent_error";b:1;s:7:"success";b:0;s:5:"error";…`.
180 + * Transient failures serialize as a 2-element array without the `permanent_error` key, so
181 + * they keep being retried. Matching serialized data with LIKE is fragile: the key order
182 + * written in Imagify\NGG\Optimization\Data\NGG must not change.
183 + */
184 + '%' . $wpdb->esc_like( $suffix . '";a:3:{s:15:"permanent_error";b:1;' ) . '%'
185 + )
186 + );
187 +
146 188 $wpdb->flush();
147 - unset( $ngg_table, $data_table, $webp_suffix );
189 + unset( $ngg_table, $data_table, $suffix );
148 190
149 191 $data = [
150 192 'ids' => [],
151 193 'errors' => [
@@ -170,54 +212,62 @@
170 212
171 213 $backup_path = get_imagify_ngg_attachment_backup_path( $file_path );
172 214
173 215 if ( ! $this->filesystem->exists( $backup_path ) ) {
174 - // No backup, no WebP.
216 + // No backup, no next-gen.
175 217 $data['errors']['no_backup'][] = $file_id;
176 218 continue;
177 219 }
178 220
179 221 $data['ids'][] = $file_id;
180 - } // End foreach().
222 + }
181 223
182 224 return $data;
183 225 }
184 226
185 227 /**
186 - * Tell if there are optimized media without WebP versions.
228 + * Tell if there are optimized media without next-gen versions.
187 229 *
188 - * @since 1.9
189 - * @access public
190 - * @author Grégory Viguier
230 + * @since 2.2
191 231 *
192 232 * @return int The number of media.
193 233 */
194 - public function has_optimized_media_without_webp() {
234 + public function has_optimized_media_without_nextgen() {
235 + // @codeCoverageIgnoreStart — requires live NGG DB table; not available in unit tests.
236 + if ( ! DB::get_instance()->can_operate() ) {
237 + return 0;
238 + }
239 + // @codeCoverageIgnoreEnd
240 +
195 241 global $wpdb;
196 242
197 - $ngg_table = $wpdb->prefix . 'ngg_pictures';
198 - $data_table = DB::get_instance()->get_table_name();
199 - $webp_suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::WEBP_SUFFIX' );
243 + $ngg_table = $wpdb->prefix . 'ngg_pictures';
244 + $data_table = DB::get_instance()->get_table_name();
245 + $suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::WEBP_SUFFIX' );
200 246
201 - return (int) $wpdb->get_var( $wpdb->prepare( // WPCS: unprepared SQL ok.
202 - "
203 - SELECT COUNT(ngg.pid)
204 - FROM $ngg_table as ngg
205 - INNER JOIN $data_table AS data
206 - ON ( ngg.pid = data.pid )
207 - WHERE
208 - ( data.status = 'success' OR data.status = 'already_optimized' )
209 - AND data.data NOT LIKE %s",
210 - '%' . $wpdb->esc_like( $webp_suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
211 - ) );
247 + if ( 'avif' === get_imagify_option( 'optimization_format' ) ) {
248 + $suffix = constant( imagify_get_optimization_process_class_name( 'ngg' ) . '::AVIF_SUFFIX' );
249 + }
250 +
251 + return (int) $wpdb->get_var(
252 + $wpdb->prepare( // WPCS: unprepared SQL ok.
253 + "
254 + SELECT COUNT(ngg.pid)
255 + FROM $ngg_table as ngg
256 + INNER JOIN $data_table AS data
257 + ON ( ngg.pid = data.pid )
258 + WHERE
259 + ( data.status = 'success' OR data.status = 'already_optimized' )
260 + AND data.data NOT LIKE %s",
261 + '%' . $wpdb->esc_like( $suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
262 + )
263 + );
212 264 }
213 265
214 266 /**
215 267 * Get the context data.
216 268 *
217 - * @since 1.9
218 - * @access public
219 - * @author Grégory Viguier
269 + * @since 1.9
220 270 *
221 271 * @return array {
222 272 * The formated data.
223 273 *