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

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