PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.7
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.7
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 3.2.7, at includes/class-updraft-smush-manager-commands.php

496 lines 17.0 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 * The commands constructor
16 *
17 * @param mixed $task_manager - A task manager instance
18 */
19 public function __construct($task_manager) {
20 parent::__construct($task_manager);
21 }
22
23 /**
24 * Returns a list of commands available for smush related operations
25 */
26 public static function get_allowed_ajax_commands() {
27
28 $commands = apply_filters('updraft_task_manager_allowed_ajax_commands', array());
29
30 $smush_commands = array(
31 'compress_single_image',
32 'restore_single_image',
33 'process_bulk_smush',
34 'update_smush_options',
35 'get_ui_update',
36 'process_pending_images',
37 'clear_pending_images',
38 'clear_smush_stats',
39 'check_server_status',
40 'get_smush_logs',
41 'mark_as_compressed',
42 'mark_all_as_uncompressed',
43 'clean_all_backup_images',
44 'reset_webp_serving_method',
45 );
46
47 return array_merge($commands, $smush_commands);
48 }
49
50 /**
51 * Process the compression of a single image
52 *
53 * @param mixed $data - sent in via AJAX
54 * @return WP_Error|array - information about the operation or WP_Error object on failure
55 */
56 public function compress_single_image($data) {
57
58 $options = !empty($data['smush_options']) ? $data['smush_options'] : $this->task_manager->get_smush_options();
59 $image = isset($data['selected_image']) ? filter_var($data['selected_image']['attachment_id'], FILTER_SANITIZE_NUMBER_INT) : false;
60 $blog = isset($data['selected_image']) ? filter_var($data['selected_image']['blog_id'], FILTER_SANITIZE_NUMBER_INT) : false;
61
62 // A subsite administrator can only compress their own image. If the blog ID isn't theirs, return an error.
63 if ($blog && is_multisite() && get_current_blog_id() != $blog && !current_user_can('manage_network_options')) {
64 return new WP_Error('compression_not_permitted', __('The blog ID provided does not match the current blog.', 'wp-optimize'));
65 }
66
67 $server = sanitize_text_field($options['compression_server']);
68
69 $lossy = filter_var($options['lossy_compression'], FILTER_VALIDATE_BOOLEAN) ? true : false;
70 $backup = filter_var($options['back_up_original'], FILTER_VALIDATE_BOOLEAN) ? true : false;
71 $exif = filter_var($options['preserve_exif'], FILTER_VALIDATE_BOOLEAN) ? true : false;
72 $quality = filter_var($options['image_quality'], FILTER_SANITIZE_NUMBER_INT);
73
74 $options = array(
75 'attachment_id' => $image,
76 'blog_id' => $blog,
77 'image_quality' => $quality,
78 'keep_original' => $backup,
79 'lossy_compression' => $lossy,
80 'preserve_exif' => $exif
81 );
82
83 if (filesize(get_attached_file($image)) > 5242880) {
84 $options['request_timeout'] = 180;
85 }
86
87 $success = $this->task_manager->compress_single_image($image, $options, $server);
88
89 if (!$success) {
90 return new WP_Error('compress_failed', get_post_meta($image, 'smush-info', true));
91 }
92
93 $response = array();
94 $response['status'] = true;
95 $response['operation'] = 'compress';
96 $response['options'] = $options;
97 $response['server'] = $server;
98 $response['success'] = $success;
99 $response['restore_possible'] = $backup;
100 $response['summary'] = get_post_meta($image, 'smush-info', true);
101
102 $smush_stats = get_post_meta($image, 'smush-stats', true);
103 if (isset($smush_stats['sizes-info'])) {
104 $response['sizes-info'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info']));
105 }
106
107 return $response;
108 }
109
110 /**
111 * Restores a single image, if backup is available
112 *
113 * @param mixed $data - Sent in via AJAX
114 * @return WP_Error|array - information about the operation or a WP_Error object on failure
115 */
116 public function restore_single_image($data) {
117
118 $blog_id = isset($data['blog_id']) ? $data['blog_id'] : false;
119 $image_id = isset($data['selected_image']) ? $data['selected_image'] : false;
120
121 $success = $this->task_manager->restore_single_image($image_id, $blog_id);
122
123 if (is_wp_error($success)) {
124 return $success;
125 }
126
127 $response = array();
128 $response['status'] = true;
129 $response['operation'] = 'restore';
130 $response['blog_id'] = $blog_id;
131 $response['image'] = $image_id;
132 $response['success'] = $success;
133 $response['summary'] = __('The image was restored successfully', 'wp-optimize');
134
135 return $response;
136 }
137
138 /**
139 * Process the compression of multiple images
140 *
141 * @param mixed $data - Sent in via AJAX
142 */
143 public function process_bulk_smush($data = array()) {
144 $images = isset($data['selected_images']) ? $data['selected_images'] : array();
145
146 $ui_update = $this->get_ui_update($images);
147 $this->close_browser_connection(json_encode($ui_update));
148 $this->task_manager->process_bulk_smush($images);
149 // Since we already sent back data and closed the browser connection, we must not return (that would result in further sending back of JSON).
150 die();
151 }
152
153 /**
154 * Returns useful information for the UI and closes the connection
155 *
156 * @param mixed $data - Sent in via AJAX
157 *
158 * @return mixed - Information for the UI
159 */
160 public function get_ui_update($data) {
161 $ui_update = array();
162 $ui_update['status'] = true;
163 $ui_update['is_multisite'] = is_multisite() ? 1 : 0;
164 $pending_tasks = $this->task_manager->get_pending_tasks();
165
166 $ui_update['pending_tasks'] = is_array($pending_tasks) ? count($this->task_manager->get_pending_tasks()) : 0;
167 $ui_update['unsmushed_images'] = $this->task_manager->get_uncompressed_images();
168 $ui_update['admin_urls'] = $this->task_manager->get_admin_urls();
169 $ui_update['completed_task_count'] = $this->task_manager->options->get_option('completed_task_count', 0);
170 $ui_update['bytes_saved'] = WP_Optimize()->format_size($this->task_manager->options->get_option('total_bytes_saved', 0));
171 $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%';
172 $ui_update['failed_task_count'] = $this->task_manager->get_failed_task_count();
173
174 $ui_update['summary'] = sprintf(__("Since your compression statistics were last reset, a total of %d image(s) were compressed on this site, saving approximately %s of space at an average of %02d percent per image.", 'wp-optimize'), $ui_update['completed_task_count'], $ui_update['bytes_saved'], $ui_update['percent_saved']);
175 $ui_update['failed'] = sprintf(__("%d image(s) could not be compressed. Please see the logs for more information, or try again later.", 'wp-optimize'), $ui_update['failed_task_count']);
176 $ui_update['pending'] = sprintf(__("%d image(s) images were selected for compressing previously, but were not all processed. You can either complete them now or cancel and retry later.", 'wp-optimize'), $ui_update['pending_tasks']);
177 $ui_update['smush_complete'] = $this->task_manager->is_queue_processed();
178
179 if (isset($data['image_list'])) {
180 $images = $data['image_list'];
181 $stats = $this->task_manager->get_session_stats($images);
182 $ui_update['session_stats'] = "";
183
184 if (!empty($stats['success'])) {
185 $ui_update['session_stats'] .= sprintf(__("A total of %d image(s) were successfully compressed in this iteration. ", 'wp-optimize'), $stats['success']);
186 }
187
188 if (!empty($stats['fail'])) {
189 $ui_update['session_stats'] .= sprintf(__("%d selected image(s) could not be compressed. Please see the logs for more information, you may try again later.", 'wp-optimize'), $stats['fail']);
190 }
191 }
192
193 return $ui_update;
194
195 }
196
197 /**
198 * Updates smush related options
199 *
200 * @param mixed $data - Sent in via AJAX
201 * @return WP_Error|array - information about the operation or WP_Error object on failure
202 */
203 public function update_smush_options($data) {
204 $options = array();
205 $options['compression_server'] = sanitize_text_field($data['compression_server']);
206 $options['lossy_compression'] = filter_var($data['lossy_compression'], FILTER_VALIDATE_BOOLEAN) ? true : false;
207 $options['back_up_original'] = filter_var($data['back_up_original'], FILTER_VALIDATE_BOOLEAN) ? true : false;
208 $options['back_up_delete_after'] = filter_var($data['back_up_delete_after'], FILTER_VALIDATE_BOOLEAN) ? true : false;
209 $options['back_up_delete_after_days'] = filter_var($data['back_up_delete_after_days'], FILTER_SANITIZE_NUMBER_INT);
210 $options['preserve_exif'] = filter_var($data['preserve_exif'], FILTER_VALIDATE_BOOLEAN) ? true : false;
211 $options['autosmush'] = filter_var($data['autosmush'], FILTER_VALIDATE_BOOLEAN) ? true : false;
212 $options['image_quality'] = filter_var($data['image_quality'], FILTER_SANITIZE_NUMBER_INT);
213 $options['show_smush_metabox'] = filter_var($data['show_smush_metabox'], FILTER_VALIDATE_BOOLEAN) ? 'show' : 'hide';
214 $options['webp_conversion'] = filter_var($data['webp_conversion'], FILTER_VALIDATE_BOOLEAN) ? true : false;
215 $options['webp_converters'] = false;
216
217 $success = $this->task_manager->update_smush_options($options);
218
219 if (!$success) {
220 return new WP_Error('update_failed', __('Options could not be updated', 'wp-optimize'));
221 }
222
223 do_action('wpo_save_images_settings');
224
225 $response = array();
226 $response['status'] = true;
227 $response['saved'] = $success;
228 $response['summary'] = __('Options updated successfully', 'wp-optimize');
229
230 return $response;
231 }
232
233 /**
234 * Clears any smush related stats
235 *
236 * @return WP_Error|array - information about the operation or WP_Error object on failure
237 */
238 public function clear_smush_stats() {
239
240 $success = $this->task_manager->clear_smush_stats();
241
242 if (!$success) {
243 return new WP_Error('update_failed', __('Stats could not be cleared', 'wp-optimize'));
244 }
245
246 $response = array();
247 $response['status'] = true;
248 $response['summary'] = __('Stats cleared successfully', 'wp-optimize');
249
250 return $response;
251 }
252
253 /**
254 * Checks if the selected server is online
255 *
256 * @param mixed $data - Sent in via AJAX
257 */
258 public function check_server_status($data) {
259 $server = sanitize_text_field($data['server']);
260 $response = array();
261 $response['status'] = true;
262 $response['online'] = $this->task_manager->check_server_online($server);
263
264 if (!$response['online']) {
265 $response['error'] = get_option($this->task_manager->get_associated_task($server));
266 }
267
268 return $response;
269 }
270
271 /**
272 * Completes any pending tasks
273 */
274 public function process_pending_images() {
275 $this->process_bulk_smush();
276 }
277
278 /**
279 * Deletes and removes any pending tasks from queue
280 *
281 * @return WP_Error|array - information about the operation or WP_Error object on failure
282 */
283 public function clear_pending_images() {
284
285 $success = $this->task_manager->clear_pending_images();
286
287 if (!$success) {
288 return new WP_Error('error_deleting_tasks', __('Pending tasks could not be cleared', 'wp-optimize'));
289 }
290
291 $response = array();
292 $response['status'] = true;
293 $response['summary'] = __('Pending tasks cleared successfully', 'wp-optimize');
294
295 return $response;
296 }
297
298 /**
299 * Mark selected images as already compressed.
300 *
301 * @param array $data
302 * @return array
303 */
304 public function mark_as_compressed($data) {
305 $response = array();
306 $selected_images = array();
307
308 $unmark = isset($data['unmark']) && $data['unmark'];
309
310 foreach ($data['selected_images'] as $image) {
311 if (!array_key_exists($image['blog_id'], $selected_images)) $selected_images[$image['blog_id']] = array();
312
313 $selected_images[$image['blog_id']][] = $image['attachment_id'];
314 }
315
316 $info = __('This image is marked as already compressed by another tool.', 'wp-optimize');
317
318 foreach (array_keys($selected_images) as $blog_id) {
319 if (is_multisite()) switch_to_blog($blog_id);
320
321 foreach ($selected_images[$blog_id] as $attachment_id) {
322 if ($unmark) {
323 delete_post_meta($attachment_id, 'smush-complete');
324 delete_post_meta($attachment_id, 'smush-marked');
325 delete_post_meta($attachment_id, 'smush-info');
326 } else {
327 update_post_meta($attachment_id, 'smush-complete', true);
328 update_post_meta($attachment_id, 'smush-marked', true);
329 update_post_meta($attachment_id, 'smush-info', $info);
330 }
331 }
332
333 if (is_multisite()) restore_current_blog();
334 }
335
336 $response['status'] = true;
337
338 if ($unmark) {
339 $response['summary'] = _n('The selected image was successfully marked as uncompressed', 'The selected images were successfully marked as uncompressed', count($data['selected_images']), 'wp-optimize');
340 } else {
341 $response['summary'] = _n('The selected image was successfully marked as compressed', 'The selected images were successfully marked as compressed', count($data['selected_images']), 'wp-optimize');
342 }
343
344 $response['info'] = $info;
345
346 return $response;
347 }
348
349 /**
350 * Mark all images as uncompressed and if posted restore_backup argument
351 * then try to restore images form backup.
352 *
353 * @param array $data
354 * @return array
355 */
356 public function mark_all_as_uncompressed($data) {
357
358 $restore_backup = isset($data['restore_backup']) && $data['restore_backup'];
359 $images_per_request = apply_filters('mark_all_as_uncompressed_images_per_request', 100);
360 $delete_only_backups_meta = isset($data['delete_only_backups_meta']) && $data['delete_only_backups_meta'];
361
362 if (is_multisite()) {
363 // option where we store last completed blog id
364 $option_name = 'mark_as_uncompressed_last_blog_id';
365 // set default value for response
366 $response = array(
367 'completed' => true,
368 'message' => __('All the compressed images were successfully restored.', 'wp-optimize'),
369 );
370
371 // get all blogs ids
372 $blogs = WP_Optimize()->get_sites();
373 $blogs_ids = wp_list_pluck($blogs, 'blog_id');
374 sort($blogs_ids);
375
376 // select the blog for processing
377 $last_completed_blog_id = $this->task_manager->options->get_option($option_name, false);
378 $index = $last_completed_blog_id ? array_search($last_completed_blog_id, $blogs_ids) + 1 : 0;
379
380 if ($index < count($blogs_ids)) {
381 $blog_id = $blogs_ids[$index];
382 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, $blog_id, $images_per_request, $delete_only_backups_meta);
383
384 // if we get completed the current blog then update last completed blog option value
385 // and if we have other blogs for processing then set complete to false as we have not
386 // processed all blogs
387 if ($response['completed']) {
388 if ($index + 1 < count($blogs_ids)) {
389 $response['completed'] = false;
390 } else {
391 if ($delete_only_backups_meta) {
392 $response['message'] = __('All the compressed images were successfully restored.', 'wp-optimize');
393 } else {
394 $response['message'] = __('All the compressed images were successfully marked as uncompressed.', 'wp-optimize');
395 }
396 }
397 $this->task_manager->options->update_option($option_name, $blog_id);
398 }
399 }
400
401 // if we get an error or completed the work then delete option with last completed blog id.
402 if ($response['completed'] || isset($response['error'])) {
403 $this->task_manager->options->delete_option($option_name);
404 }
405 } else {
406 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, 0, $images_per_request, $delete_only_backups_meta);
407 }
408
409 return $response;
410 }
411
412 /**
413 * Returns the log file
414 *
415 * @return WP_Error|file - logfile or WP_Error object on failure
416 */
417 public function get_smush_logs() {
418
419 $logfile = $this->task_manager->get_logfile_path();
420
421 if (!file_exists($logfile)) {
422 $this->task_manager->write_log_header();
423 }
424
425 if (is_file($logfile)) {
426 header('Content-Description: File Transfer');
427 header('Content-Type: application/octet-stream');
428 header('Content-Disposition: attachment; filename="'.basename($logfile).'"');
429 header('Expires: 0');
430 header('Cache-Control: must-revalidate');
431 header('Pragma: public');
432 header('Content-Length: ' . filesize($logfile));
433 readfile($logfile);
434 exit;
435 } else {
436 return new WP_Error('log_file_error', __('Log file does not exist or could not be read', 'wp-optimize'));
437 }
438 }
439
440 /**
441 * Clean all backup images command.
442 *
443 * @return array
444 */
445 public function clean_all_backup_images() {
446 $upload_dir = wp_upload_dir(null, false);
447 $base_dir = $upload_dir['basedir'];
448
449 $this->task_manager->clear_backup_images_directory($base_dir, 0);
450
451 return array(
452 'status' => true,
453 );
454 }
455
456 /**
457 * Close browser connection so that it can resume AJAX polling
458 *
459 * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
460 * @return void
461 */
462 public function close_browser_connection($txt = '') {
463 header('Content-Length: '.((!empty($txt)) ? 4+strlen($txt) : '0'));
464 header('Content-Type: application/json');
465 header('Connection: close');
466 header('Content-Encoding: none');
467 if (session_id()) session_write_close();
468 echo "\r\n\r\n";
469 echo $txt;
470
471 $levels = ob_get_level();
472
473 for ($i = 0; $i < $levels; $i++) {
474 ob_end_flush();
475 }
476
477 flush();
478
479 if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
480 }
481
482 /**
483 * Resets webp serving method
484 *
485 * @return array
486 */
487 public function reset_webp_serving_method() {
488 $success = $this->task_manager->reset_webp_serving_method();
489 return array(
490 'success' => $success,
491 );
492 }
493 }
494
495 endif;
496