PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
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
← All changes | includes/class-updraft-smush-manager-commands.php +322 -108 3.2.9 → 4.7.0 View file →
@@ -11,8 +11,36 @@
11 11
12 12 class Updraft_Smush_Manager_Commands extends Updraft_Task_Manager_Commands_1_0 {
13 13
14 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 + /**
15 43 * The commands constructor
16 44 *
17 45 * @param mixed $task_manager - A task manager instance
18 46 */
@@ -21,12 +49,14 @@
21 49 }
22 50
23 51 /**
24 52 * Returns a list of commands available for smush related operations
53 + *
54 + * @return array
25 55 */
26 56 public static function get_allowed_ajax_commands() {
27 57
28 - $commands = apply_filters('updraft_task_manager_allowed_ajax_commands', array());
58 + $commands = parent::get_allowed_ajax_commands();
29 59
30 60 $smush_commands = array(
31 61 'compress_single_image',
32 62 'restore_single_image',
@@ -41,8 +71,12 @@
41 71 'mark_as_compressed',
42 72 'mark_all_as_uncompressed',
43 73 'clean_all_backup_images',
44 74 'reset_webp_serving_method',
75 + 'convert_to_webp_format',
76 + 'update_webp_options',
77 + 'get_smush_details',
78 + 'get_smush_settings_form',
45 79 );
46 80
47 81 return array_merge($commands, $smush_commands);
48 82 }
@@ -49,28 +83,36 @@
49 83
50 84 /**
51 85 * Process the compression of a single image
52 86 *
53 - * @param mixed $data - sent in via AJAX
87 + * @param array $data - sent in via AJAX
54 88 * @return WP_Error|array - information about the operation or WP_Error object on failure
55 89 */
56 90 public function compress_single_image($data) {
57 91
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;
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;
61 95
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')) {
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 && !WP_Optimize()->current_user_can('manage_network_options')) {
64 106 return new WP_Error('compression_not_permitted', __('The blog ID provided does not match the current blog.', 'wp-optimize'));
65 107 }
66 108
67 - $server = sanitize_text_field($options['compression_server']);
109 + $server = isset($options['compression_server']) ? sanitize_text_field($options['compression_server']) : $this->task_manager->get_default_webservice();
68 110
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);
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;
73 115
74 116 $options = array(
75 117 'attachment_id' => $image,
76 118 'blog_id' => $blog,
@@ -86,9 +128,9 @@
86 128
87 129 $success = $this->task_manager->compress_single_image($image, $options, $server);
88 130
89 131 if (!$success) {
90 - return new WP_Error('compress_failed', get_post_meta($image, 'smush-info', true));
132 + return new WP_Error('compress_failed', get_post_meta($image, '_wpo-smush-info', true));
91 133 }
92 134
93 135 $response = array();
94 136 $response['status'] = true;
@@ -96,15 +138,17 @@
96 138 $response['options'] = $options;
97 139 $response['server'] = $server;
98 140 $response['success'] = $success;
99 141 $response['restore_possible'] = $backup;
100 - $response['summary'] = get_post_meta($image, 'smush-info', true);
142 + $response['summary'] = get_post_meta($image, '_wpo-smush-info', true);
101 143
102 - $smush_stats = get_post_meta($image, 'smush-stats', true);
144 + $smush_stats = get_post_meta($image, '_wpo-smush-stats', true);
103 145 if (isset($smush_stats['sizes-info'])) {
104 146 $response['sizes-info'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info']));
105 147 }
106 148
149 + $response['media_column_html'] = $this->get_smush_media_column_content($blog, $image);
150 +
107 151 return $response;
108 152 }
109 153
110 154 /**
@@ -109,15 +153,15 @@
109 153
110 154 /**
111 155 * Restores a single image, if backup is available
112 156 *
113 - * @param mixed $data - Sent in via AJAX
157 + * @param array $data - Sent in via AJAX
114 158 * @return WP_Error|array - information about the operation or a WP_Error object on failure
115 159 */
116 160 public function restore_single_image($data) {
117 161
118 - $blog_id = isset($data['blog_id']) ? $data['blog_id'] : false;
119 - $image_id = isset($data['selected_image']) ? $data['selected_image'] : false;
162 + $blog_id = isset($data['blog_id']) ? absint($data['blog_id']) : 0;
163 + $image_id = isset($data['selected_image']) ? absint($data['selected_image']) : 0;
120 164
121 165 $success = $this->task_manager->restore_single_image($image_id, $blog_id);
122 166
123 167 if (is_wp_error($success)) {
@@ -130,8 +174,10 @@
130 174 $response['blog_id'] = $blog_id;
131 175 $response['image'] = $image_id;
132 176 $response['success'] = $success;
133 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);
134 180
135 181 return $response;
136 182 }
137 183
@@ -137,28 +183,48 @@
137 183
138 184 /**
139 185 * Process the compression of multiple images
140 186 *
141 - * @param mixed $data - Sent in via AJAX
187 + * @param array $data - Sent in via AJAX
188 + * @return array
142 189 */
143 190 public function process_bulk_smush($data = array()) {
144 - $images = isset($data['selected_images']) ? $data['selected_images'] : array();
191 + $images = isset($data['selected_images']) && is_array($data['selected_images']) ? $this->sanitize_images($data['selected_images']) : array();
192 +
193 + $this->images = $images;
145 194
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();
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;
151 202 }
152 203
153 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 + /**
154 217 * Returns useful information for the UI and closes the connection
155 218 *
156 - * @param mixed $data - Sent in via AJAX
219 + * @param array $data - Sent in via AJAX
157 220 *
158 - * @return mixed - Information for the UI
221 + * @return array - Information for the UI
159 222 */
160 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 +
161 227 $ui_update = array();
162 228 $ui_update['status'] = true;
163 229 $ui_update['is_multisite'] = is_multisite() ? 1 : 0;
164 230 $pending_tasks = $this->task_manager->get_pending_tasks();
@@ -163,9 +229,9 @@
163 229 $ui_update['is_multisite'] = is_multisite() ? 1 : 0;
164 230 $pending_tasks = $this->task_manager->get_pending_tasks();
165 231
166 232 $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();
233 + $ui_update['unsmushed_images'] = $this->task_manager->get_uncompressed_images($use_cache);
168 234 $ui_update['admin_urls'] = $this->task_manager->get_admin_urls();
169 235 $ui_update['completed_task_count'] = $this->task_manager->options->get_option('completed_task_count', 0);
170 236 $ui_update['bytes_saved'] = WP_Optimize()->format_size($this->task_manager->options->get_option('total_bytes_saved', 0));
171 237 $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%';
@@ -170,24 +236,33 @@
170 236 $ui_update['bytes_saved'] = WP_Optimize()->format_size($this->task_manager->options->get_option('total_bytes_saved', 0));
171 237 $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%';
172 238 $ui_update['failed_task_count'] = $this->task_manager->get_failed_task_count();
173 239
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']);
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');
177 251 $ui_update['smush_complete'] = $this->task_manager->is_queue_processed();
178 252
179 - if (isset($data['image_list'])) {
180 - $images = $data['image_list'];
181 - $stats = $this->task_manager->get_session_stats($images);
253 + if ($image_list) {
254 + $stats = $this->task_manager->get_session_stats($image_list);
182 255 $ui_update['session_stats'] = "";
183 256
184 257 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']);
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']);
186 260 }
187 261
188 262 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']);
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');
190 265 }
191 266 }
192 267
193 268 return $ui_update;
@@ -194,32 +269,48 @@
194 269
195 270 }
196 271
197 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 + /**
198 294 * Updates smush related options
199 295 *
200 - * @param mixed $data - Sent in via AJAX
296 + * @param array $data - Sent in via AJAX
201 297 * @return WP_Error|array - information about the operation or WP_Error object on failure
202 298 */
203 299 public function update_smush_options($data) {
204 300 $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;
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';
215 310
216 311 $success = $this->task_manager->update_smush_options($options);
217 312
218 - if (!$this->is_webp_enabled($options['webp_conversion'])) {
219 - $this->remove_webp_redirect_rules();
220 - }
221 -
222 313 if (!$success) {
223 314 return new WP_Error('update_failed', __('Smush options could not be updated', 'wp-optimize'));
224 315 }
225 316
@@ -255,12 +346,14 @@
255 346
256 347 /**
257 348 * Checks if the selected server is online
258 349 *
259 - * @param mixed $data - Sent in via AJAX
350 + * @param array $data - Sent in via AJAX
351 + *
352 + * @return array
260 353 */
261 354 public function check_server_status($data) {
262 - $server = sanitize_text_field($data['server']);
355 + $server = isset($data['server']) ? sanitize_text_field($data['server']) : $this->task_manager->get_default_webservice();
263 356 $response = array();
264 357 $response['status'] = true;
265 358 $response['online'] = $this->task_manager->check_server_online($server);
266 359
@@ -272,20 +365,30 @@
272 365 }
273 366
274 367 /**
275 368 * Completes any pending tasks
369 + *
370 + * @return array
276 371 */
277 372 public function process_pending_images() {
278 - $this->process_bulk_smush();
373 + return $this->process_bulk_smush();
279 374 }
280 375
281 376 /**
282 377 * Deletes and removes any pending tasks from queue
283 378 *
379 + * @param array $data - in 'restore_images' index passed an array with ids of images to restore
284 380 * @return WP_Error|array - information about the operation or WP_Error object on failure
285 381 */
286 - public function clear_pending_images() {
382 + public function clear_pending_images($data) {
287 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 +
288 391 $success = $this->task_manager->clear_pending_images();
289 392
290 393 if (!$success) {
291 394 return new WP_Error('error_deleting_tasks', __('Pending tasks could not be cleared', 'wp-optimize'));
@@ -308,10 +411,11 @@
308 411 $response = array();
309 412 $selected_images = array();
310 413
311 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();
312 416
313 - foreach ($data['selected_images'] as $image) {
417 + foreach ($image_list as $image) {
314 418 if (!array_key_exists($image['blog_id'], $selected_images)) $selected_images[$image['blog_id']] = array();
315 419
316 420 $selected_images[$image['blog_id']][] = $image['attachment_id'];
317 421 }
@@ -322,15 +426,15 @@
322 426 if (is_multisite()) switch_to_blog($blog_id);
323 427
324 428 foreach ($selected_images[$blog_id] as $attachment_id) {
325 429 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');
430 + delete_post_meta($attachment_id, '_wpo-smush-complete');
431 + delete_post_meta($attachment_id, '_wpo-smush-marked');
432 + delete_post_meta($attachment_id, '_wpo-smush-info');
329 433 } 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);
434 + update_post_meta($attachment_id, '_wpo-smush-complete', true);
435 + update_post_meta($attachment_id, '_wpo-smush-marked', true);
436 + update_post_meta($attachment_id, '_wpo-smush-info', $info);
333 437 }
334 438 }
335 439
336 440 if (is_multisite()) restore_current_blog();
@@ -338,15 +442,20 @@
338 442
339 443 $response['status'] = true;
340 444
341 445 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');
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');
343 447 } 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');
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');
345 449 }
346 450
347 451 $response['info'] = $info;
348 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 +
349 458 return $response;
350 459 }
351 460
352 461 /**
@@ -364,8 +473,9 @@
364 473
365 474 if (is_multisite()) {
366 475 // option where we store last completed blog id
367 476 $option_name = 'mark_as_uncompressed_last_blog_id';
477 + $smushed_images_total_option_name = 'smushed_images_total';
368 478 // set default value for response
369 479 $response = array(
370 480 'completed' => true,
371 481 'message' => __('All the compressed images were successfully restored.', 'wp-optimize'),
@@ -382,9 +492,9 @@
382 492
383 493 if ($index < count($blogs_ids)) {
384 494 $blog_id = $blogs_ids[$index];
385 495 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, $blog_id, $images_per_request, $delete_only_backups_meta);
386 -
496 + $smushed_images_total = $this->task_manager->options->get_option($smushed_images_total_option_name, 0) + $response['smushed_images_count'];
387 497 // if we get completed the current blog then update last completed blog option value
388 498 // and if we have other blogs for processing then set complete to false as we have not
389 499 // processed all blogs
390 500 if ($response['completed']) {
@@ -389,16 +499,23 @@
389 499 // processed all blogs
390 500 if ($response['completed']) {
391 501 if ($index + 1 < count($blogs_ids)) {
392 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);
393 505 } else {
394 506 if ($delete_only_backups_meta) {
395 - $response['message'] = __('All the compressed images were successfully restored.', 'wp-optimize');
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 + }
396 514 } else {
397 515 $response['message'] = __('All the compressed images were successfully marked as uncompressed.', 'wp-optimize');
398 516 }
399 517 }
400 - $this->task_manager->options->update_option($option_name, $blog_id);
401 518 }
402 519 }
403 520
404 521 // if we get an error or completed the work then delete option with last completed blog id.
@@ -403,8 +520,9 @@
403 520
404 521 // if we get an error or completed the work then delete option with last completed blog id.
405 522 if ($response['completed'] || isset($response['error'])) {
406 523 $this->task_manager->options->delete_option($option_name);
524 + $this->task_manager->options->delete_option($smushed_images_total_option_name);
407 525 }
408 526 } else {
409 527 $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, 0, $images_per_request, $delete_only_backups_meta);
410 528 }
@@ -414,9 +532,9 @@
414 532
415 533 /**
416 534 * Returns the log file
417 535 *
418 - * @return WP_Error|file - logfile or WP_Error object on failure
536 + * @return void|WP_Error - logfile or WP_Error object on failure
419 537 */
420 538 public function get_smush_logs() {
421 539
422 540 $logfile = $this->task_manager->get_logfile_path();
@@ -425,17 +543,23 @@
425 543 $this->task_manager->write_log_header();
426 544 }
427 545
428 546 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;
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 + }
438 562 } else {
439 563 return new WP_Error('log_file_error', __('Log file does not exist or could not be read', 'wp-optimize'));
440 564 }
441 565 }
@@ -456,63 +580,153 @@
456 580 );
457 581 }
458 582
459 583 /**
460 - * Close browser connection so that it can resume AJAX polling
584 + * Resets webp serving method
461 585 *
462 - * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
463 - * @return void
586 + * @return array|WP_Error
464 587 */
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;
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 + }
473 596
474 - $levels = ob_get_level();
475 -
476 - for ($i = 0; $i < $levels; $i++) {
477 - ob_end_flush();
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 + }
478 621 }
479 622
480 - flush();
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, '_wpo-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);
481 667
482 - if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
668 + if (is_multisite()) restore_current_blog();
669 +
670 + return $content;
483 671 }
484 672
485 673 /**
486 - * Resets webp serving method
674 + * Returns image not found response
487 675 *
488 676 * @return array
489 677 */
490 - public function reset_webp_serving_method() {
491 - $success = WP_Optimize()->get_webp_instance()->reset_webp_serving_method();
678 + private function image_not_found_response() {
492 679 return array(
493 - 'success' => $success,
680 + 'error' => __('Image not found', 'wp-optimize'),
494 681 );
495 682 }
496 -
683 +
497 684 /**
498 - * Decides whether to use webp images option is enabled or not
685 + * Get smush details of given image IDs
499 686 *
500 - * @param bool $webp_option
687 + * @param array $data
501 688 *
502 - * @return bool
689 + * @return array
503 690 */
504 - private function is_webp_enabled($webp_option) {
505 - return true === $webp_option;
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 + );
506 702 }
507 703
508 704 /**
509 - * Removes webp redirect rules in .htaccess file
705 + * Sanitize array of images ensuring proper integer values for attachment_id and blog_id
510 706 *
511 - * @return void
707 + * @param array $images Array of image data to sanitize
708 + * @return array
512 709 */
513 - private function remove_webp_redirect_rules() {
514 - WP_Optimize()->get_webp_instance()->empty_htaccess_file();
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;
515 729 }
516 730 }
517 731
518 732 endif;