PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.5.4
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.5.4
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / includes / class-updraft-smush-manager-commands.php

class-updraft-smush-manager-commands.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.5.4, at includes/class-updraft-smush-manager-commands.php

733 lines 25.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * A Smush Task manager class
4 */
5
6 if (!defined('ABSPATH')) die('Access denied.');
7
8 if (!class_exists('Updraft_Task_Manager_Commands_1_0')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager-commands.php');
9
10 if (!class_exists('Updraft_Smush_Manager_Commands')) :
11
12 class Updraft_Smush_Manager_Commands extends Updraft_Task_Manager_Commands_1_0 {
13
14 /**
15 * Stores the bulk of images to be processed
16 *
17 * @var array
18 */
19 private $images = array();
20
21 /**
22 * Flag to return a valid envelope on AJAX calls
23 *
24 * @var bool
25 */
26 public $background_command = false;
27
28 /**
29 * Flag to return a valid envelope on heartbeat AJAX calls
30 *
31 * @var bool
32 */
33 public $heartbeat_command = false;
34
35 /**
36 * Store the response to be sent at shutdown
37 *
38 * @var array
39 */
40 public $final_response = array();
41
42 /**
43 * The commands constructor
44 *
45 * @param mixed $task_manager - A task manager instance
46 */
47 public function __construct($task_manager) {
48 parent::__construct($task_manager);
49 }
50
51 /**
52 * Returns a list of commands available for smush related operations
53 *
54 * @return array
55 */
56 public static function get_allowed_ajax_commands() {
57
58 $commands = parent::get_allowed_ajax_commands();
59
60 $smush_commands = array(
61 'compress_single_image',
62 'restore_single_image',
63 'process_bulk_smush',
64 'update_smush_options',
65 'get_ui_update',
66 'process_pending_images',
67 'clear_pending_images',
68 'clear_smush_stats',
69 'check_server_status',
70 'get_smush_logs',
71 'mark_as_compressed',
72 'mark_all_as_uncompressed',
73 'clean_all_backup_images',
74 'reset_webp_serving_method',
75 'convert_to_webp_format',
76 'update_webp_options',
77 'get_smush_details',
78 'get_smush_settings_form',
79 );
80
81 return array_merge($commands, $smush_commands);
82 }
83
84 /**
85 * Process the compression of a single image
86 *
87 * @param array $data - sent in via AJAX
88 * @return WP_Error|array - information about the operation or WP_Error object on failure
89 */
90 public function compress_single_image($data) {
91
92 $options = empty($data['smush_options']) ? $this->task_manager->get_smush_options() : $data['smush_options'];
93 $image = isset($data['selected_image']['attachment_id']) ? absint($data['selected_image']['attachment_id']) : 0;
94 $blog = isset($data['selected_image']['blog_id']) ? absint($data['selected_image']['blog_id']) : 0;
95
96 if (0 === $image) {
97 return new WP_Error('invalid_image', __('Image ID is invalid', 'wp-optimize'));
98 }
99
100 if (0 === $blog && is_multisite()) {
101 return new WP_Error('invalid_blog', __('Blog ID is invalid', 'wp-optimize'));
102 }
103
104 // A sub site administrator can only compress their own image. If the blog ID isn't theirs, return an error.
105 if ($blog && is_multisite() && get_current_blog_id() !== $blog && !current_user_can('manage_network_options')) {
106 return new WP_Error('compression_not_permitted', __('The blog ID provided does not match the current blog.', 'wp-optimize'));
107 }
108
109 $server = isset($options['compression_server']) ? sanitize_text_field($options['compression_server']) : $this->task_manager->get_default_webservice();
110
111 $lossy = isset($options['lossy_compression']) ? filter_var($options['lossy_compression'], FILTER_VALIDATE_BOOLEAN) : false;
112 $backup = isset($options['back_up_original']) ? filter_var($options['back_up_original'], FILTER_VALIDATE_BOOLEAN) : true;
113 $exif = isset($options['preserve_exif']) ? filter_var($options['preserve_exif'], FILTER_VALIDATE_BOOLEAN) : false;
114 $quality = isset($options['image_quality']) ? absint($options['image_quality']) : 92;
115
116 $options = array(
117 'attachment_id' => $image,
118 'blog_id' => $blog,
119 'image_quality' => $quality,
120 'keep_original' => $backup,
121 'lossy_compression' => $lossy,
122 'preserve_exif' => $exif
123 );
124
125 if (filesize(get_attached_file($image)) > 5242880) {
126 $options['request_timeout'] = 180;
127 }
128
129 $success = $this->task_manager->compress_single_image($image, $options, $server);
130
131 if (!$success) {
132 return new WP_Error('compress_failed', get_post_meta($image, 'smush-info', true));
133 }
134
135 $response = array();
136 $response['status'] = true;
137 $response['operation'] = 'compress';
138 $response['options'] = $options;
139 $response['server'] = $server;
140 $response['success'] = $success;
141 $response['restore_possible'] = $backup;
142 $response['summary'] = get_post_meta($image, 'smush-info', true);
143
144 $smush_stats = get_post_meta($image, 'smush-stats', true);
145 if (isset($smush_stats['sizes-info'])) {
146 $response['sizes-info'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info']));
147 }
148
149 $response['media_column_html'] = $this->get_smush_media_column_content($blog, $image);
150
151 return $response;
152 }
153
154 /**
155 * Restores a single image, if backup is available
156 *
157 * @param array $data - Sent in via AJAX
158 * @return WP_Error|array - information about the operation or a WP_Error object on failure
159 */
160 public function restore_single_image($data) {
161
162 $blog_id = isset($data['blog_id']) ? absint($data['blog_id']) : 0;
163 $image_id = isset($data['selected_image']) ? absint($data['selected_image']) : 0;
164
165 $success = $this->task_manager->restore_single_image($image_id, $blog_id);
166
167 if (is_wp_error($success)) {
168 return $success;
169 }
170
171 $response = array();
172 $response['status'] = true;
173 $response['operation'] = 'restore';
174 $response['blog_id'] = $blog_id;
175 $response['image'] = $image_id;
176 $response['success'] = $success;
177 $response['summary'] = __('The image was restored successfully', 'wp-optimize');
178
179 $response['media_column_html'] = $this->get_smush_media_column_content($blog_id, $image_id);
180
181 return $response;
182 }
183
184 /**
185 * Process the compression of multiple images
186 *
187 * @param array $data - Sent in via AJAX
188 * @return array
189 */
190 public function process_bulk_smush($data = array()) {
191 $images = isset($data['selected_images']) && is_array($data['selected_images']) ? $this->sanitize_images($data['selected_images']) : array();
192
193 $this->images = $images;
194
195 $this->background_command = true;
196
197 $this->final_response = $this->get_ui_update($this->images);
198
199 add_action('shutdown', array($this, 'process_bulk_smush_shutdown'));
200
201 return $this->final_response;
202 }
203
204 /**
205 * Close request connection at the `shutdown` hook and start processing the bulk
206 *
207 * @return void
208 */
209 public function process_bulk_smush_shutdown() {
210 WP_Optimize()->close_browser_connection(wp_json_encode($this->final_response));
211
212 $this->task_manager->process_bulk_smush($this->images);
213 exit;
214 }
215
216 /**
217 * Returns useful information for the UI and closes the connection
218 *
219 * @param array $data - Sent in via AJAX
220 *
221 * @return array - Information for the UI
222 */
223 public function get_ui_update($data) {
224 $use_cache = isset($data['use_cache']) ? sanitize_text_field($data['use_cache']) : 'true';
225 $image_list = isset($data['image_list']) && is_array($data['image_list']) ? $this->sanitize_images($data['image_list']) : false;
226
227 $ui_update = array();
228 $ui_update['status'] = true;
229 $ui_update['is_multisite'] = is_multisite() ? 1 : 0;
230 $pending_tasks = $this->task_manager->get_pending_tasks();
231
232 $ui_update['pending_tasks'] = is_array($pending_tasks) ? count($this->task_manager->get_pending_tasks()) : 0;
233 $ui_update['unsmushed_images'] = $this->task_manager->get_uncompressed_images($use_cache);
234 $ui_update['admin_urls'] = $this->task_manager->get_admin_urls();
235 $ui_update['completed_task_count'] = $this->task_manager->options->get_option('completed_task_count', 0);
236 $ui_update['bytes_saved'] = WP_Optimize()->format_size($this->task_manager->options->get_option('total_bytes_saved', 0));
237 $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%';
238 $ui_update['failed_task_count'] = $this->task_manager->get_failed_task_count();
239
240 if (is_multisite()) {
241 // translators: %d: number of images compressed, %2$s: size of saved space, %3$02d: average percent saved
242 $ui_update['summary'] = sprintf(__('Since the last reset of compression statistics on this multisite, a total of %d image(s) were compressed across the network.', 'wp-optimize').' '.__('This saved approximately %2$s of space at an average of %3$02d percent per image.', 'wp-optimize'), $ui_update['completed_task_count'], $ui_update['bytes_saved'], $ui_update['percent_saved']);
243 } else {
244 // translators: %d: number of images compressed, %2$s: size of saved space, %3$02d: average percent saved
245 $ui_update['summary'] = sprintf(__('Since your compression statistics were last reset, a total of %d image(s) were compressed on this site.', 'wp-optimize').' '.__('This saved approximately %2$s of space at an average of %3$02d percent per image.', 'wp-optimize'), $ui_update['completed_task_count'], $ui_update['bytes_saved'], $ui_update['percent_saved']);
246 }
247 // translators: %d: number of images that could not be compressed
248 $ui_update['failed'] = sprintf(__("%d image(s) could not be compressed.", 'wp-optimize'), $ui_update['failed_task_count']) . ' ' . __('Please see the logs for more information, or try again later.', 'wp-optimize');
249 // translators: %d: number of images that were selected for compression, and pending processing
250 $ui_update['pending'] = sprintf(__("%d image(s) images were selected for compressing previously, but were not all processed.", 'wp-optimize'), $ui_update['pending_tasks']) . ' ' . __('You can either complete them now or cancel and retry later.', 'wp-optimize');
251 $ui_update['smush_complete'] = $this->task_manager->is_queue_processed();
252
253 if ($image_list) {
254 $stats = $this->task_manager->get_session_stats($image_list);
255 $ui_update['session_stats'] = "";
256
257 if (!empty($stats['success'])) {
258 // translators: %d: number of images compressed
259 $ui_update['session_stats'] .= sprintf(__("A total of %d image(s) were successfully compressed in this iteration.", 'wp-optimize'), $stats['success']);
260 }
261
262 if (!empty($stats['fail'])) {
263 // translators: %d: number of images that could not be compressed
264 $ui_update['session_stats'] .= sprintf(__("%d selected image(s) could not be compressed.", 'wp-optimize'), $stats['fail']) . ' ' . __('Please see the logs for more information, you may try again later.', 'wp-optimize');
265 }
266 }
267
268 return $ui_update;
269
270 }
271
272 /**
273 * Updates webp related options
274 *
275 * @param array $data - Sent in via AJAX
276 * @return WP_Error|array - information about the operation or WP_Error object on failure
277 */
278 public function update_webp_options($data) {
279 $webp_instance = WP_Optimize()->get_webp_instance();
280 $result = $webp_instance->save_webp_settings($data);
281 if (is_wp_error($result)) {
282 return $result;
283 }
284
285 $response = array();
286 $response['status'] = true;
287 $response['saved'] = $result;
288 $response['summary'] = __('WebP options updated successfully.', 'wp-optimize');
289
290 return $response;
291 }
292
293 /**
294 * Updates smush related options
295 *
296 * @param array $data - Sent in via AJAX
297 * @return WP_Error|array - information about the operation or WP_Error object on failure
298 */
299 public function update_smush_options($data) {
300 $options = array();
301 $options['compression_server'] = isset($data['compression_server']) ? sanitize_text_field($data['compression_server']) : $this->task_manager->get_default_webservice();
302 $options['lossy_compression'] = isset($data['lossy_compression']) ? filter_var($data['lossy_compression'], FILTER_VALIDATE_BOOLEAN) : false;
303 $options['back_up_original'] = isset($data['back_up_original']) ? filter_var($data['back_up_original'], FILTER_VALIDATE_BOOLEAN) : true;
304 $options['back_up_delete_after'] = isset($data['back_up_delete_after']) ? filter_var($data['back_up_delete_after'], FILTER_VALIDATE_BOOLEAN) : true;
305 $options['back_up_delete_after_days'] = isset($data['back_up_delete_after_days']) ? absint($data['back_up_delete_after_days']) : 50;
306 $options['preserve_exif'] = isset($data['preserve_exif']) ? filter_var($data['preserve_exif'], FILTER_VALIDATE_BOOLEAN) : false;
307 $options['autosmush'] = isset($data['autosmush']) ? filter_var($data['autosmush'], FILTER_VALIDATE_BOOLEAN) : false;
308 $options['image_quality'] = isset($data['image_quality']) ? absint($data['image_quality']) : 92;
309 $options['show_smush_metabox'] = isset($data['show_smush_metabox']) && filter_var($data['show_smush_metabox'], FILTER_VALIDATE_BOOLEAN) ? 'show' : 'hide';
310
311 $success = $this->task_manager->update_smush_options($options);
312
313 if (!$success) {
314 return new WP_Error('update_failed', __('Smush options could not be updated', 'wp-optimize'));
315 }
316
317 do_action('wpo_save_images_settings');
318
319 $response = array();
320 $response['status'] = true;
321 $response['saved'] = $success;
322 $response['summary'] = __('Options updated successfully', 'wp-optimize');
323
324 return $response;
325 }
326
327 /**
328 * Clears any smush related stats
329 *
330 * @return WP_Error|array - information about the operation or WP_Error object on failure
331 */
332 public function clear_smush_stats() {
333
334 $success = $this->task_manager->clear_smush_stats();
335
336 if (!$success) {
337 return new WP_Error('update_failed', __('Stats could not be cleared', 'wp-optimize'));
338 }
339
340 $response = array();
341 $response['status'] = true;
342 $response['summary'] = __('Stats cleared successfully', 'wp-optimize');
343
344 return $response;
345 }
346
347 /**
348 * Checks if the selected server is online
349 *
350 * @param array $data - Sent in via AJAX
351 *
352 * @return array
353 */
354 public function check_server_status($data) {
355 $server = isset($data['server']) ? sanitize_text_field($data['server']) : $this->task_manager->get_default_webservice();
356 $response = array();
357 $response['status'] = true;
358 $response['online'] = $this->task_manager->check_server_online($server);
359
360 if (!$response['online']) {
361 $response['error'] = get_option($this->task_manager->get_associated_task($server));
362 }
363
364 return $response;
365 }
366
367 /**
368 * Completes any pending tasks
369 *
370 * @return array
371 */
372 public function process_pending_images() {
373 return $this->process_bulk_smush();
374 }
375
376 /**
377 * Deletes and removes any pending tasks from queue
378 *
379 * @param array $data - in 'restore_images' index passed an array with ids of images to restore
380 * @return WP_Error|array - information about the operation or WP_Error object on failure
381 */
382 public function clear_pending_images($data) {
383
384 if (!empty($data['restore_images']) && is_array($data['restore_images'])) {
385 $restore_images = $this->sanitize_images($data['restore_images']);
386 foreach ($restore_images as $image) {
387 $this->task_manager->restore_single_image($image['attachment_id'], $image['blog_id']);
388 }
389 }
390
391 $success = $this->task_manager->clear_pending_images();
392
393 if (!$success) {
394 return new WP_Error('error_deleting_tasks', __('Pending tasks could not be cleared', 'wp-optimize'));
395 }
396
397 $response = array();
398 $response['status'] = true;
399 $response['summary'] = __('Pending tasks cleared successfully', 'wp-optimize');
400
401 return $response;
402 }
403
404 /**
405 * Mark selected images as already compressed.
406 *
407 * @param array $data
408 * @return array
409 */
410 public function mark_as_compressed($data) {
411 $response = array();
412 $selected_images = array();
413
414 $unmark = isset($data['unmark']) && $data['unmark'];
415 $image_list = isset($data['selected_images']) && is_array($data['selected_images']) ? $this->sanitize_images($data['selected_images']) : array();
416
417 foreach ($image_list as $image) {
418 if (!array_key_exists($image['blog_id'], $selected_images)) $selected_images[$image['blog_id']] = array();
419
420 $selected_images[$image['blog_id']][] = $image['attachment_id'];
421 }
422
423 $info = __('This image is marked as already compressed by another tool.', 'wp-optimize');
424
425 foreach (array_keys($selected_images) as $blog_id) {
426 if (is_multisite()) switch_to_blog($blog_id);
427
428 foreach ($selected_images[$blog_id] as $attachment_id) {
429 if ($unmark) {
430 delete_post_meta($attachment_id, 'smush-complete');
431 delete_post_meta($attachment_id, 'smush-marked');
432 delete_post_meta($attachment_id, 'smush-info');
433 } else {
434 update_post_meta($attachment_id, 'smush-complete', true);
435 update_post_meta($attachment_id, 'smush-marked', true);
436 update_post_meta($attachment_id, 'smush-info', $info);
437 }
438 }
439
440 if (is_multisite()) restore_current_blog();
441 }
442
443 $response['status'] = true;
444
445 if ($unmark) {
446 $response['summary'] = _n('The selected image was successfully marked as uncompressed', 'The selected images were successfully marked as uncompressed', count($image_list), 'wp-optimize');
447 } else {
448 $response['summary'] = _n('The selected image was successfully marked as compressed', 'The selected images were successfully marked as compressed', count($image_list), 'wp-optimize');
449 }
450
451 $response['info'] = $info;
452
453 if (1 === count($image_list)) {
454 $selected_image = reset($image_list);
455 $response['media_column_html'] = $this->get_smush_media_column_content($selected_image['blog_id'], $selected_image['attachment_id']);
456 }
457
458 return $response;
459 }
460
461 /**
462 * Mark all images as uncompressed and if posted restore_backup argument
463 * then try to restore images form backup.
464 *
465 * @param array $data
466 * @return array
467 */
468 public function mark_all_as_uncompressed($data) {
469
470 $restore_backup = isset($data['restore_backup']) && $data['restore_backup'];
471 $images_per_request = apply_filters('mark_all_as_uncompressed_images_per_request', 100);
472 $delete_only_backups_meta = isset($data['delete_only_backups_meta']) && $data['delete_only_backups_meta'];
473
474 if (is_multisite()) {
475 // option where we store last completed blog id
476 $option_name = 'mark_as_uncompressed_last_blog_id';
477 $smushed_images_total_option_name = 'smushed_images_total';
478 // set default value for response
479 $response = array(
480 'completed' => true,
481 'message' => __('All the compressed images were successfully restored.', 'wp-optimize'),
482 );
483
484 // get all blogs ids
485 $blogs = WP_Optimize()->get_sites();
486 $blogs_ids = wp_list_pluck($blogs, 'blog_id');
487 sort($blogs_ids);
488
489 // select the blog for processing
490 $last_completed_blog_id = $this->task_manager->options->get_option($option_name, false);
491 $index = $last_completed_blog_id ? array_search($last_completed_blog_id, $blogs_ids) + 1 : 0;
492
493 if ($index < count($blogs_ids)) {
494 $blog_id = $blogs_ids[$index];
495 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, $blog_id, $images_per_request, $delete_only_backups_meta);
496 $smushed_images_total = $this->task_manager->options->get_option($smushed_images_total_option_name, 0) + $response['smushed_images_count'];
497 // if we get completed the current blog then update last completed blog option value
498 // and if we have other blogs for processing then set complete to false as we have not
499 // processed all blogs
500 if ($response['completed']) {
501 if ($index + 1 < count($blogs_ids)) {
502 $response['completed'] = false;
503 $this->task_manager->options->update_option($option_name, $blog_id);
504 $this->task_manager->options->update_option($smushed_images_total_option_name, $smushed_images_total);
505 } else {
506 if ($delete_only_backups_meta) {
507 if ($smushed_images_total > 0) {
508 $response['message'] = __('All the compressed images with backup copies of their original files were successfully restored.', 'wp-optimize');
509 // translators: %s - number of smushed images
510 $response['message'] .= ' '.sprintf(_n('Unable to restore %s image without backup files.', 'Unable to restore %s images without backup files.', $smushed_images_total, 'wp-optimize'), $smushed_images_total);
511 } else {
512 $response['message'] = __('All the compressed images were successfully restored.', 'wp-optimize');
513 }
514 } else {
515 $response['message'] = __('All the compressed images were successfully marked as uncompressed.', 'wp-optimize');
516 }
517 }
518 }
519 }
520
521 // if we get an error or completed the work then delete option with last completed blog id.
522 if ($response['completed'] || isset($response['error'])) {
523 $this->task_manager->options->delete_option($option_name);
524 $this->task_manager->options->delete_option($smushed_images_total_option_name);
525 }
526 } else {
527 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, 0, $images_per_request, $delete_only_backups_meta);
528 }
529
530 return $response;
531 }
532
533 /**
534 * Returns the log file
535 *
536 * @return void|WP_Error - logfile or WP_Error object on failure
537 */
538 public function get_smush_logs() {
539
540 $logfile = $this->task_manager->get_logfile_path();
541
542 if (!file_exists($logfile)) {
543 $this->task_manager->write_log_header();
544 }
545
546 if (is_file($logfile)) {
547 if ($this->heartbeat_command) {
548 // The response will be inside the heartbeat response envelope, as each response of a heartbeat goes in its own unique ID key
549 readfile($logfile); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Using WP_Filesystem and get contents will result in `echo` and unescaped error
550 } else {
551 // Headers are needed for the `Download logs` link, which will run this command and just prompt a file download
552 header('Content-Description: File Transfer');
553 header('Content-Type: application/octet-stream');
554 header('Content-Disposition: attachment; filename="'.basename($logfile).'"');
555 header('Expires: 0');
556 header('Cache-Control: must-revalidate');
557 header('Pragma: public');
558 header('Content-Length: ' . filesize($logfile));
559 readfile($logfile); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Using WP_Filesystem and get contents will result in `echo` and unescaped error
560 exit;
561 }
562 } else {
563 return new WP_Error('log_file_error', __('Log file does not exist or could not be read', 'wp-optimize'));
564 }
565 }
566
567 /**
568 * Clean all backup images command.
569 *
570 * @return array
571 */
572 public function clean_all_backup_images() {
573 $upload_dir = wp_upload_dir(null, false);
574 $base_dir = $upload_dir['basedir'];
575
576 $this->task_manager->clear_backup_images_directory($base_dir, 0);
577
578 return array(
579 'status' => true,
580 );
581 }
582
583 /**
584 * Resets webp serving method
585 *
586 * @return array|WP_Error
587 */
588 public function reset_webp_serving_method() {
589 $webp_instance = WP_Optimize()->get_webp_instance();
590 //Run checks before calling reset_webp_serving_method
591 if (!$webp_instance->is_webp_conversion_enabled()) {
592 $webp_instance->disable_webp_conversion();
593 $webp_instance->log("The WebP serving method cannot be reset because WebP conversion is currently disabled");
594 return new WP_Error('reset_failed_webp_conversion_disabled', __('The WebP serving method cannot be reset because WebP conversion is currently disabled', 'wp-optimize'));
595 }
596
597 $webp_instance->reset_webp_serving_method();
598 return array(
599 'success' => true,
600 );
601 }
602
603 /**
604 * Convert the image to webp format
605 *
606 * @param array $data
607 * @return array
608 */
609 public function convert_to_webp_format($data) {
610 $attachment_id = isset($data['attachment_id']) ? absint($data['attachment_id']) : 0;
611 if (0 === $attachment_id) return $this->image_not_found_response();
612
613 $images = WPO_Image_Utils::get_attachment_files($attachment_id);
614 if (empty($images)) return $this->image_not_found_response();
615
616 $images['original'] = get_attached_file($attachment_id);
617 foreach ($images as $image) {
618 if (!is_file($image.'.webp')) {
619 WPO_WebP_Utils::do_webp_conversion($image);
620 }
621 }
622
623 return array(
624 'success' => __('Image is converted to WebP format.', 'wp-optimize'),
625 );
626 }
627
628 /**
629 * Get Smush settings form
630 *
631 * @param array $data
632 * @return array
633 */
634 public function get_smush_settings_form($data) {
635 $attachment_id = isset($data['attachment_id']) ? absint($data['attachment_id']) : 0;
636 if (0 === $attachment_id) return $this->image_not_found_response();
637
638 $compressed = (bool) get_post_meta($attachment_id, 'smush-complete', true);
639
640 $smush_options = Updraft_Smush_Manager()->get_smush_options();
641
642 $extract = array(
643 'post_id' => $attachment_id,
644 'smush_options' => $smush_options,
645 'custom' => 90 >= $smush_options['image_quality'] && 65 <= $smush_options['image_quality'],
646 'smush_display' => $compressed ? "display:none;" : "display:block;",
647 );
648
649 return array(
650 'success' => true,
651 'html' => WP_Optimize()->include_template('admin-metabox-smush-settings.php', true, $extract),
652 );
653 }
654
655 /**
656 * Get content for Media Library column content
657 *
658 * @param int $blog_id
659 * @param int $attachment_id
660 *
661 * @return string
662 */
663 private function get_smush_media_column_content($blog_id, $attachment_id) {
664 if (is_multisite()) switch_to_blog($blog_id);
665
666 $content = Updraft_Smush_Manager()->get_smush_details($attachment_id);
667
668 if (is_multisite()) restore_current_blog();
669
670 return $content;
671 }
672
673 /**
674 * Returns image not found response
675 *
676 * @return array
677 */
678 private function image_not_found_response() {
679 return array(
680 'error' => __('Image not found', 'wp-optimize'),
681 );
682 }
683
684 /**
685 * Get smush details of given image IDs
686 *
687 * @param array $data
688 *
689 * @return array
690 */
691 public function get_smush_details($data) {
692 $selected_images = isset( $data['selected_images'] ) && is_array( $data['selected_images'] ) ? array_map( 'absint', $data['selected_images'] ) : array();
693 $smush_details = array();
694 foreach ($selected_images as $attachment_id) {
695 $smush_details[$attachment_id] = $this->task_manager->get_smush_details($attachment_id);
696 }
697
698 return array(
699 'success' => true,
700 'smush_details' => $smush_details,
701 );
702 }
703
704 /**
705 * Sanitize array of images ensuring proper integer values for attachment_id and blog_id
706 *
707 * @param array $images Array of image data to sanitize
708 * @return array
709 */
710 private function sanitize_images($images) {
711 $result = array();
712
713 foreach ($images as $image) {
714 $attachment_id = isset($image['attachment_id']) ? absint($image['attachment_id']) : 0;
715 $blog_id = isset($image['blog_id']) ? absint($image['blog_id']) : 0;
716
717 // Skip entries where either value is zero
718 if (0 === $attachment_id || 0 === $blog_id) {
719 continue;
720 }
721
722 $result[] = array(
723 'attachment_id' => $attachment_id,
724 'blog_id' => $blog_id,
725 );
726 }
727
728 return $result;
729 }
730 }
731
732 endif;
733