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

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