PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.7.7
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.7.7
1.7.7 1.7.6 1.7.5 1.7.4 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.3.0 1.4.0 1.4.1 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
image-optimization / modules / optimization / components / bulk-optimization.php

bulk-optimization.php in Image Optimizer – Compress Images and Convert to WebP or AVIF 1.7.7, at modules/optimization/components/bulk-optimization.php

307 lines 7.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImageOptimization\Modules\Optimization\Components;
4
5 use ImageOptimization\Classes\Async_Operation\{
6 Async_Operation,
7 Async_Operation_Hook,
8 Async_Operation_Queue,
9 };
10
11 use ImageOptimization\Classes\Image\{
12 Image_Meta,
13 Image_Status
14 };
15
16 use ImageOptimization\Modules\Optimization\{
17 Classes\Exceptions\Bulk_Token_Expired_Error,
18 Classes\Optimize_Image,
19 Classes\Bulk_Optimization\Bulk_Optimization_Queue,
20 Classes\Bulk_Optimization\Bulk_Optimization_Queue_Status,
21 Classes\Bulk_Optimization\Bulk_Optimization_Queue_Type,
22 Classes\Bulk_Optimization\Bulk_Optimization_Token_Manager,
23 };
24
25 use ImageOptimization\Classes\Logger;
26 use ImageOptimization\Classes\Utils;
27 use ImageOptimization\Classes\Exceptions\Quota_Exceeded_Error;
28 use Throwable;
29
30 // @codeCoverageIgnoreStart
31 if ( ! defined( 'ABSPATH' ) ) {
32 exit; // Exit if accessed directly.
33 }
34 // @codeCoverageIgnoreEnd
35
36 class Bulk_Optimization {
37 /** @async */
38 public function optimize_bulk() {
39 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::OPTIMIZATION );
40
41 if ( ! $queue->exists() ) {
42 Logger::debug( 'Bulk optimization queue did not found' );
43
44 return;
45 }
46
47 if ( ! $queue->has_more_images() ) {
48 Logger::debug( 'No more pending images, deleting queue' );
49 $queue->delete();
50
51 return;
52 }
53
54 if ( $queue->should_refresh_token() ) {
55 Logger::debug( 'Refreshing bulk token' );
56
57 try {
58 $token_data = Bulk_Optimization_Token_Manager::obtain_token(
59 $queue->get_stats()[ Bulk_Optimization_Queue_Status::PENDING ],
60 $queue->get_max_batch_size()
61 );
62
63 $queue
64 ->set_bulk_token(
65 $token_data['token'],
66 time() + HOUR_IN_SECONDS,
67 $token_data['batch_size']
68 )
69 ->save();
70 } catch ( Throwable $t ) {
71 Logger::info( 'Failed to obtain a bulk token: ' . $t->getMessage() );
72
73 foreach ( $queue->get_images_by_status( Bulk_Optimization_Queue_Status::PENDING ) as $image ) {
74 ( new Image_Meta( $image['id'] ) )
75 ->set_status( Image_Status::NOT_OPTIMIZED )
76 ->save();
77 }
78
79 $queue->delete();
80
81 return;
82 }
83 }
84
85 $image_id = $queue->get_next_image();
86
87 Logger::debug( 'Processing image: ' . $image_id );
88
89 if ( ! $image_id ) {
90 Logger::debug( 'No image to process, deleting queue' );
91 $queue->delete();
92
93 return;
94 }
95
96 $queue
97 ->set_current_image_id( $image_id )
98 ->save();
99
100 try {
101 $oi = new Optimize_Image(
102 $image_id,
103 'bulk',
104 $queue->get_bulk_token()
105 );
106
107 $oi->optimize();
108
109 $queue
110 ->mark_image_completed( $image_id )
111 ->increment_optimized_counter()
112 ->save();
113
114 } catch ( Bulk_Token_Expired_Error $btee ) {
115 $queue->mark_image_failed( $image_id )->save();
116
117 Logger::info( "Token expired while optimizing image {$image_id}" );
118 } catch ( Quota_Exceeded_Error $qee ) {
119 $queue->mark_image_failed( $image_id )->save();
120
121 Logger::info( "Quota exceeded while optimizing image {$image_id}" );
122 } catch ( Throwable $e ) {
123 $queue->mark_image_failed( $image_id )->save();
124
125 Logger::info( "Failed to optimize image {$image_id}: " . $e->getMessage() );
126 }
127
128 $queue
129 ->set_current_image_id( null )
130 ->save();
131
132 try {
133 if ( $queue->has_more_images() ) {
134 Async_Operation::create(
135 Async_Operation_Hook::OPTIMIZE_BULK,
136 [ 'operation_id' => $queue->get_operation_id() ],
137 Async_Operation_Queue::OPTIMIZE
138 );
139
140 Logger::debug( 'Async operation created' );
141 } else {
142 Logger::debug( 'All images were optimized, deleting queue' );
143
144 $queue->delete();
145 }
146 } catch ( Throwable $t ) {
147 Logger::error( 'Failed to create next async operation or delete queue: ' . $t->getMessage() );
148 }
149 }
150
151 /** @async */
152 public function reoptimize_bulk() {
153 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::REOPTIMIZATION );
154
155 if ( ! $queue->exists() ) {
156 return;
157 }
158
159 if ( ! $queue->has_more_images() ) {
160 $queue->delete();
161
162 return;
163 }
164
165 if ( $queue->should_refresh_token() ) {
166 try {
167 $token_data = Bulk_Optimization_Token_Manager::obtain_token(
168 $queue->get_stats()[ Bulk_Optimization_Queue_Status::PENDING ],
169 $queue->get_max_batch_size()
170 );
171
172 $queue
173 ->set_bulk_token(
174 $token_data['token'],
175 time() + HOUR_IN_SECONDS,
176 $token_data['batch_size']
177 )
178 ->save();
179 } catch ( Throwable $t ) {
180 Logger::info( 'Failed to obtain bulk token: ' . $t->getMessage() );
181
182 foreach ( $queue->get_images_by_status( Bulk_Optimization_Queue_Status::PENDING ) as $image ) {
183 ( new Image_Meta( $image['id'] ) )
184 ->set_status( Image_Status::OPTIMIZATION_FAILED )
185 ->save();
186 }
187
188 $queue->delete();
189
190 return;
191 }
192 }
193
194 $image_id = $queue->get_next_image();
195
196 if ( ! $image_id ) {
197 $queue
198 ->set_status( Bulk_Optimization_Queue_Status::COMPLETED )
199 ->save();
200
201 return;
202 }
203
204 $queue
205 ->set_current_image_id( $image_id )
206 ->save();
207
208 try {
209 $oi = new Optimize_Image(
210 $image_id,
211 'bulk-reoptimize',
212 $queue->get_bulk_token(),
213 true
214 );
215
216 $oi->optimize();
217
218 $queue
219 ->mark_image_completed( $image_id )
220 ->increment_optimized_counter()
221 ->save();
222
223 } catch ( Bulk_Token_Expired_Error $btee ) {
224 $queue->mark_image_failed( $image_id )->save();
225
226 Logger::info( "Token expired while reoptimizing image {$image_id}" );
227 } catch ( Quota_Exceeded_Error $qee ) {
228 $queue->mark_image_failed( $image_id )->save();
229
230 foreach ( $queue->get_images_by_status( Bulk_Optimization_Queue_Status::PENDING ) as $image ) {
231 ( new Image_Meta( $image['id'] ) )
232 ->set_status( Image_Status::OPTIMIZATION_FAILED )
233 ->save();
234 }
235
236 $queue->delete();
237
238 Logger::info( "Quota exceeded while reoptimizing image {$image_id}" );
239
240 return;
241 } catch ( Throwable $e ) {
242 $queue->mark_image_failed( $image_id )->save();
243
244 Logger::info( "Failed to reoptimize image {$image_id}: " . $e->getMessage() );
245 }
246
247 $queue
248 ->set_current_image_id( null )
249 ->save();
250
251 try {
252 if ( $queue->has_more_images() ) {
253 Async_Operation::create(
254 Async_Operation_Hook::REOPTIMIZE_BULK,
255 [ 'operation_id' => $queue->get_operation_id() ],
256 Async_Operation_Queue::OPTIMIZE
257 );
258 } else {
259 $queue->delete();
260 }
261 } catch ( Throwable $t ) {
262 Logger::error( 'Failed to create next async operation or delete queue: ' . $t->getMessage() );
263 }
264 }
265
266 /**
267 * Renders the bulk optimization notice
268 *
269 * @return void
270 */
271 public function render_bulk_optimization_notice() {
272 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::OPTIMIZATION );
273 $is_in_progress = $queue->exists();
274 ?>
275 <div class="notice notice-info notice image-optimizer__notice image-optimizer__notice--info image-optimizer__notice--bulk-tip"
276 style="display: <?php echo $is_in_progress ? 'block' : 'none'; ?>">
277 <p>
278 <b>
279 <?php esc_html_e(
280 'Heads up!',
281 'image-optimization'
282 ); ?>
283 </b>
284
285 <span>
286 <?php esc_html_e(
287 'Bulk optimizing may take a lot of processing and server time, depending on the number of images. Your site will still work smoothly until the processing is all done, without any downtime.',
288 'image-optimization'
289 ); ?>
290 </span>
291 </p>
292 </div>
293 <?php
294 }
295
296 public function __construct() {
297 add_action( Async_Operation_Hook::OPTIMIZE_BULK, [ $this, 'optimize_bulk' ] );
298 add_action( Async_Operation_Hook::REOPTIMIZE_BULK, [ $this, 'reoptimize_bulk' ] );
299
300 add_action( 'current_screen', function () {
301 if ( Utils::is_bulk_optimization_page() ) {
302 add_filter( 'admin_footer_text', [ $this, 'render_bulk_optimization_notice' ] );
303 }
304 } );
305 }
306 }
307