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

498 lines 17.2 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 $is_webp_conversion_enabled = $options['webp_conversion'] ? 'true' : 'false';
216 WP_Optimize()->log("WebP conversion is enabled? $is_webp_conversion_enabled");
217 $options['webp_converters'] = false;
218
219 $success = $this->task_manager->update_smush_options($options);
220
221 if (!$success) {
222 return new WP_Error('update_failed', __('Options could not be updated', 'wp-optimize'));
223 }
224
225 do_action('wpo_save_images_settings');
226
227 $response = array();
228 $response['status'] = true;
229 $response['saved'] = $success;
230 $response['summary'] = __('Options updated successfully', 'wp-optimize');
231
232 return $response;
233 }
234
235 /**
236 * Clears any smush related stats
237 *
238 * @return WP_Error|array - information about the operation or WP_Error object on failure
239 */
240 public function clear_smush_stats() {
241
242 $success = $this->task_manager->clear_smush_stats();
243
244 if (!$success) {
245 return new WP_Error('update_failed', __('Stats could not be cleared', 'wp-optimize'));
246 }
247
248 $response = array();
249 $response['status'] = true;
250 $response['summary'] = __('Stats cleared successfully', 'wp-optimize');
251
252 return $response;
253 }
254
255 /**
256 * Checks if the selected server is online
257 *
258 * @param mixed $data - Sent in via AJAX
259 */
260 public function check_server_status($data) {
261 $server = sanitize_text_field($data['server']);
262 $response = array();
263 $response['status'] = true;
264 $response['online'] = $this->task_manager->check_server_online($server);
265
266 if (!$response['online']) {
267 $response['error'] = get_option($this->task_manager->get_associated_task($server));
268 }
269
270 return $response;
271 }
272
273 /**
274 * Completes any pending tasks
275 */
276 public function process_pending_images() {
277 $this->process_bulk_smush();
278 }
279
280 /**
281 * Deletes and removes any pending tasks from queue
282 *
283 * @return WP_Error|array - information about the operation or WP_Error object on failure
284 */
285 public function clear_pending_images() {
286
287 $success = $this->task_manager->clear_pending_images();
288
289 if (!$success) {
290 return new WP_Error('error_deleting_tasks', __('Pending tasks could not be cleared', 'wp-optimize'));
291 }
292
293 $response = array();
294 $response['status'] = true;
295 $response['summary'] = __('Pending tasks cleared successfully', 'wp-optimize');
296
297 return $response;
298 }
299
300 /**
301 * Mark selected images as already compressed.
302 *
303 * @param array $data
304 * @return array
305 */
306 public function mark_as_compressed($data) {
307 $response = array();
308 $selected_images = array();
309
310 $unmark = isset($data['unmark']) && $data['unmark'];
311
312 foreach ($data['selected_images'] as $image) {
313 if (!array_key_exists($image['blog_id'], $selected_images)) $selected_images[$image['blog_id']] = array();
314
315 $selected_images[$image['blog_id']][] = $image['attachment_id'];
316 }
317
318 $info = __('This image is marked as already compressed by another tool.', 'wp-optimize');
319
320 foreach (array_keys($selected_images) as $blog_id) {
321 if (is_multisite()) switch_to_blog($blog_id);
322
323 foreach ($selected_images[$blog_id] as $attachment_id) {
324 if ($unmark) {
325 delete_post_meta($attachment_id, 'smush-complete');
326 delete_post_meta($attachment_id, 'smush-marked');
327 delete_post_meta($attachment_id, 'smush-info');
328 } else {
329 update_post_meta($attachment_id, 'smush-complete', true);
330 update_post_meta($attachment_id, 'smush-marked', true);
331 update_post_meta($attachment_id, 'smush-info', $info);
332 }
333 }
334
335 if (is_multisite()) restore_current_blog();
336 }
337
338 $response['status'] = true;
339
340 if ($unmark) {
341 $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');
342 } else {
343 $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');
344 }
345
346 $response['info'] = $info;
347
348 return $response;
349 }
350
351 /**
352 * Mark all images as uncompressed and if posted restore_backup argument
353 * then try to restore images form backup.
354 *
355 * @param array $data
356 * @return array
357 */
358 public function mark_all_as_uncompressed($data) {
359
360 $restore_backup = isset($data['restore_backup']) && $data['restore_backup'];
361 $images_per_request = apply_filters('mark_all_as_uncompressed_images_per_request', 100);
362 $delete_only_backups_meta = isset($data['delete_only_backups_meta']) && $data['delete_only_backups_meta'];
363
364 if (is_multisite()) {
365 // option where we store last completed blog id
366 $option_name = 'mark_as_uncompressed_last_blog_id';
367 // set default value for response
368 $response = array(
369 'completed' => true,
370 'message' => __('All the compressed images were successfully restored.', 'wp-optimize'),
371 );
372
373 // get all blogs ids
374 $blogs = WP_Optimize()->get_sites();
375 $blogs_ids = wp_list_pluck($blogs, 'blog_id');
376 sort($blogs_ids);
377
378 // select the blog for processing
379 $last_completed_blog_id = $this->task_manager->options->get_option($option_name, false);
380 $index = $last_completed_blog_id ? array_search($last_completed_blog_id, $blogs_ids) + 1 : 0;
381
382 if ($index < count($blogs_ids)) {
383 $blog_id = $blogs_ids[$index];
384 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, $blog_id, $images_per_request, $delete_only_backups_meta);
385
386 // if we get completed the current blog then update last completed blog option value
387 // and if we have other blogs for processing then set complete to false as we have not
388 // processed all blogs
389 if ($response['completed']) {
390 if ($index + 1 < count($blogs_ids)) {
391 $response['completed'] = false;
392 } else {
393 if ($delete_only_backups_meta) {
394 $response['message'] = __('All the compressed images were successfully restored.', 'wp-optimize');
395 } else {
396 $response['message'] = __('All the compressed images were successfully marked as uncompressed.', 'wp-optimize');
397 }
398 }
399 $this->task_manager->options->update_option($option_name, $blog_id);
400 }
401 }
402
403 // if we get an error or completed the work then delete option with last completed blog id.
404 if ($response['completed'] || isset($response['error'])) {
405 $this->task_manager->options->delete_option($option_name);
406 }
407 } else {
408 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, 0, $images_per_request, $delete_only_backups_meta);
409 }
410
411 return $response;
412 }
413
414 /**
415 * Returns the log file
416 *
417 * @return WP_Error|file - logfile or WP_Error object on failure
418 */
419 public function get_smush_logs() {
420
421 $logfile = $this->task_manager->get_logfile_path();
422
423 if (!file_exists($logfile)) {
424 $this->task_manager->write_log_header();
425 }
426
427 if (is_file($logfile)) {
428 header('Content-Description: File Transfer');
429 header('Content-Type: application/octet-stream');
430 header('Content-Disposition: attachment; filename="'.basename($logfile).'"');
431 header('Expires: 0');
432 header('Cache-Control: must-revalidate');
433 header('Pragma: public');
434 header('Content-Length: ' . filesize($logfile));
435 readfile($logfile);
436 exit;
437 } else {
438 return new WP_Error('log_file_error', __('Log file does not exist or could not be read', 'wp-optimize'));
439 }
440 }
441
442 /**
443 * Clean all backup images command.
444 *
445 * @return array
446 */
447 public function clean_all_backup_images() {
448 $upload_dir = wp_upload_dir(null, false);
449 $base_dir = $upload_dir['basedir'];
450
451 $this->task_manager->clear_backup_images_directory($base_dir, 0);
452
453 return array(
454 'status' => true,
455 );
456 }
457
458 /**
459 * Close browser connection so that it can resume AJAX polling
460 *
461 * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
462 * @return void
463 */
464 public function close_browser_connection($txt = '') {
465 header('Content-Length: '.((!empty($txt)) ? 4+strlen($txt) : '0'));
466 header('Content-Type: application/json');
467 header('Connection: close');
468 header('Content-Encoding: none');
469 if (session_id()) session_write_close();
470 echo "\r\n\r\n";
471 echo $txt;
472
473 $levels = ob_get_level();
474
475 for ($i = 0; $i < $levels; $i++) {
476 ob_end_flush();
477 }
478
479 flush();
480
481 if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
482 }
483
484 /**
485 * Resets webp serving method
486 *
487 * @return array
488 */
489 public function reset_webp_serving_method() {
490 $success = $this->task_manager->reset_webp_serving_method();
491 return array(
492 'success' => $success,
493 );
494 }
495 }
496
497 endif;
498