← 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 | * |