PluginProbe
Image Optimizer – Compress Images and Convert to WebP or AVIF / 1.7.4
Image Optimizer – Compress Images and Convert to WebP or AVIF v1.7.4
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 / classes / bulk-optimization / bulk-optimization-controller.php

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

279 lines 7.7 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\Classes\Bulk_Optimization;
4
5 use ImageOptimization\Classes\Async_Operation\{
6 Async_Operation,
7 Async_Operation_Hook,
8 Async_Operation_Queue,
9 Exceptions\Async_Operation_Exception,
10 Queries\Image_Optimization_Operation_Query
11 };
12 use ImageOptimization\Classes\Image\{
13 Exceptions\Invalid_Image_Exception,
14 Image,
15 Image_Meta,
16 Image_Optimization_Error_Type,
17 Image_Query_Builder,
18 Image_Status
19 };
20 use ImageOptimization\Classes\Exceptions\Quota_Exceeded_Error;
21 use ImageOptimization\Classes\Logger;
22 use ImageOptimization\Modules\Stats\Classes\Optimization_Stats;
23 use Throwable;
24
25 // @codeCoverageIgnoreStart
26 if ( ! defined( 'ABSPATH' ) ) {
27 exit; // Exit if accessed directly.
28 }
29 // @codeCoverageIgnoreEnd
30
31 final class Bulk_Optimization_Controller {
32 /**
33 * Cancels pending bulk optimization operations.
34 *
35 * @return void
36 * @throws Async_Operation_Exception
37 */
38 public static function delete_bulk_optimization(): void {
39 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::OPTIMIZATION );
40
41 if ( $queue->exists() ) {
42 foreach ( $queue->get_image_ids() as $image_id ) {
43 $meta = new Image_Meta( $image_id );
44 $status = $meta->get_status();
45
46 if ( Image_Status::OPTIMIZATION_IN_PROGRESS === $status ) {
47 $meta->delete();
48 }
49 }
50
51 $queue->delete();
52 }
53
54 $query = ( new Image_Optimization_Operation_Query() )
55 ->set_hook( Async_Operation_Hook::OPTIMIZE_BULK )
56 ->set_status( [ Async_Operation::OPERATION_STATUS_PENDING, Async_Operation::OPERATION_STATUS_RUNNING ] )
57 ->set_limit( 1 );
58
59 $operation = Async_Operation::get( $query );
60
61 if ( ! empty( $operation ) ) {
62 Async_Operation::remove( [ $operation[0]->get_id() ] );
63 }
64 }
65
66 /**
67 * Creates a queue for bulk optimization and schedules the processor.
68 *
69 * @return void
70 * @throws Quota_Exceeded_Error|Invalid_Image_Exception|Async_Operation_Exception
71 */
72 public static function create_optimization_queue(): void {
73 $images = Bulk_Optimization_Image_Query::find_images(
74 ( new Image_Query_Builder() )
75 ->return_not_optimized_images(),
76 true
77 );
78
79 Logger::debug( 'Non-optimized images found: ' . $images['total_images_count'] );
80
81 if ( ! $images['total_images_count'] ) {
82 $not_fully_optimized_images = Bulk_Optimization_Image_Query::find_images(
83 Bulk_Optimization_Image_Query::query_not_fully_optimized_images(),
84 true
85 );
86
87 Logger::debug( 'Non fully optimized images found: ' . $images['total_images_count'] );
88
89 if ( ! $not_fully_optimized_images['total_images_count'] ) {
90 Logger::debug( 'Bulk optimization not started' );
91
92 return;
93 }
94
95 $images = $not_fully_optimized_images;
96 }
97
98 $token_data = Bulk_Optimization_Token_Manager::obtain_token( $images['total_images_count'] );
99 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::OPTIMIZATION );
100
101 Logger::debug( "Bulk token obtained for {$token_data['batch_size']} images" );
102
103 $queue
104 ->set_bulk_token(
105 $token_data['token'],
106 time() + HOUR_IN_SECONDS,
107 $token_data['batch_size']
108 )
109 ->set_status( Bulk_Optimization_Queue_Status::PROCESSING )
110 ->add_images( $images['attachments_in_quota'] )
111 ->save();
112
113 Logger::info( "New queue {$queue->get_operation_id()} created" );
114
115 Async_Operation::create(
116 Async_Operation_Hook::OPTIMIZE_BULK,
117 [ 'operation_id' => $queue->get_operation_id() ],
118 Async_Operation_Queue::OPTIMIZE
119 );
120
121 Logger::debug( 'Async operation created' );
122
123 foreach ( $images['attachments_in_quota'] as $image_id ) {
124 ( new Image_Meta( $image_id ) )
125 ->set_status( Image_Status::OPTIMIZATION_IN_PROGRESS )
126 ->set_retry_count( 0 )
127 ->set_error_type( null )
128 ->save();
129 }
130 }
131
132 /**
133 * Creates a queue for bulk reoptimization and schedules the processor.
134 *
135 * @return void
136 * @throws Quota_Exceeded_Error|Invalid_Image_Exception|Async_Operation_Exception
137 */
138 public static function create_reoptimization_queue(): void {
139 $images = Bulk_Optimization_Image_Query::find_images(
140 ( new Image_Query_Builder() )
141 ->return_optimized_images()
142 );
143
144 if ( ! $images['total_images_count'] ) {
145 return;
146 }
147
148 $token_data = Bulk_Optimization_Token_Manager::obtain_token( $images['total_images_count'] );
149 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::REOPTIMIZATION );
150
151 $queue
152 ->set_bulk_token(
153 $token_data['token'],
154 time() + HOUR_IN_SECONDS,
155 $token_data['batch_size']
156 )
157 ->set_status( Bulk_Optimization_Queue_Status::PROCESSING )
158 ->add_images( $images['attachments_in_quota'] )
159 ->save();
160
161 Async_Operation::create(
162 Async_Operation_Hook::REOPTIMIZE_BULK,
163 [ 'operation_id' => $queue->get_operation_id() ],
164 Async_Operation_Queue::OPTIMIZE
165 );
166
167 foreach ( $images['attachments_in_quota'] as $image_id ) {
168 ( new Image_Meta( $image_id ) )
169 ->set_status( Image_Status::REOPTIMIZING_IN_PROGRESS )
170 ->set_retry_count( 0 )
171 ->set_error_type( null )
172 ->save();
173 }
174
175 // Handle images out of quota
176 foreach ( $images['attachments_out_of_quota'] as $image_id ) {
177 ( new Image_Meta( $image_id ) )
178 ->set_status( Image_Status::REOPTIMIZING_FAILED )
179 ->set_error_type( Image_Optimization_Error_Type::QUOTA_EXCEEDED )
180 ->save();
181 }
182 }
183
184 /**
185 * Checks if there is a bulk optimization operation in progress.
186 * If there is at least a single active bulk optimization operation it returns true, otherwise false.
187 *
188 * @return bool
189 */
190 public static function is_optimization_in_progress(): bool {
191 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::OPTIMIZATION );
192
193 return $queue->exists() && Bulk_Optimization_Queue_Status::PROCESSING === $queue->get_status();
194 }
195
196 /**
197 * Checks if there is a bulk re-optimization operation in progress.
198 * If there is at least a single active bulk re-optimization operation it returns true, otherwise false.
199 *
200 * @return bool
201 */
202 public static function is_reoptimization_in_progress(): bool {
203 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::REOPTIMIZATION );
204
205 return $queue->exists() && Bulk_Optimization_Queue_Status::PROCESSING === $queue->get_status();
206 }
207
208 /**
209 * Retrieves the bulk optimization process status.
210 *
211 * @return array{status: string, stats: array}
212 */
213 public static function get_status(): array {
214 $stats = Optimization_Stats::get_image_stats();
215
216 $percentage = 0;
217 if ( $stats['total_image_count'] > 0 ) {
218 $percentage = round( $stats['optimized_image_count'] / $stats['total_image_count'] * 100 );
219 }
220
221 $output = [
222 'status' => 'not-started',
223 'percentage' => $percentage,
224 ];
225
226 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::OPTIMIZATION );
227
228 if ( ! $queue->exists() ) {
229 return $output;
230 }
231
232 $output['status'] = 'in-progress';
233
234 return $output;
235 }
236
237 /**
238 * Returns latest operations for the bulk optimization screen.
239 *
240 * @return array
241 */
242 public static function get_processed_images(): array {
243 $output = [];
244 $queue = new Bulk_Optimization_Queue( Bulk_Optimization_Queue_Type::OPTIMIZATION );
245
246 if ( ! $queue->exists() ) {
247 return $output;
248 }
249
250 $images = $queue->get_images();
251 $images = array_slice( $images, 0, 50 );
252
253 foreach ( $images as $queue_image ) {
254 $image_id = $queue_image['id'];
255
256 try {
257 $image = new Image( $image_id );
258 $stats = Optimization_Stats::get_image_stats( $image_id );
259 } catch ( Throwable $t ) {
260 continue;
261 }
262
263 $meta = new Image_Meta( $image_id );
264
265 $output[] = [
266 'id' => $image_id,
267 'status' => $meta->get_status(),
268 'image_name' => $image->get_attachment_object()->post_title,
269 'image_id' => $image_id,
270 'thumbnail_url' => $image->get_url( 'thumbnail' ),
271 'original_file_size' => $stats['initial_image_size'],
272 'current_file_size' => $stats['current_image_size'],
273 ];
274 }
275
276 return $output;
277 }
278 }
279