← All changes
|
includes/class-updraft-smush-manager-commands.php
+292
-113
3.2.22
→
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,8 +49,10 @@ | ||
| 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 | 58 | $commands = parent::get_allowed_ajax_commands(); |
| @@ -42,8 +72,11 @@ | ||
| 42 | 72 | 'mark_all_as_uncompressed', |
| 43 | 73 | 'clean_all_backup_images', |
| 44 | 74 | 'reset_webp_serving_method', |
| 45 | 75 | 'convert_to_webp_format', |
| 76 | + 'update_webp_options', | |
| 77 | + 'get_smush_details', | |
| 78 | + 'get_smush_settings_form', | |
| 46 | 79 | ); |
| 47 | 80 | |
| 48 | 81 | return array_merge($commands, $smush_commands); |
| 49 | 82 | } |
| @@ -50,28 +83,36 @@ | ||
| 50 | 83 | |
| 51 | 84 | /** |
| 52 | 85 | * Process the compression of a single image |
| 53 | 86 | * |
| 54 | - * @param mixed $data - sent in via AJAX | |
| 87 | + * @param array $data - sent in via AJAX | |
| 55 | 88 | * @return WP_Error|array - information about the operation or WP_Error object on failure |
| 56 | 89 | */ |
| 57 | 90 | public function compress_single_image($data) { |
| 58 | 91 | |
| 59 | - $options = !empty($data['smush_options']) ? $data['smush_options'] : $this->task_manager->get_smush_options(); | |
| 60 | - $image = isset($data['selected_image']) ? filter_var($data['selected_image']['attachment_id'], FILTER_SANITIZE_NUMBER_INT) : false; | |
| 61 | - $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; | |
| 62 | 95 | |
| 63 | - // A subsite administrator can only compress their own image. If the blog ID isn't theirs, return an error. | |
| 64 | - 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')) { | |
| 65 | 106 | return new WP_Error('compression_not_permitted', __('The blog ID provided does not match the current blog.', 'wp-optimize')); |
| 66 | 107 | } |
| 67 | 108 | |
| 68 | - $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(); | |
| 69 | 110 | |
| 70 | - $lossy = filter_var($options['lossy_compression'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 71 | - $backup = filter_var($options['back_up_original'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 72 | - $exif = filter_var($options['preserve_exif'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 73 | - $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; | |
| 74 | 115 | |
| 75 | 116 | $options = array( |
| 76 | 117 | 'attachment_id' => $image, |
| 77 | 118 | 'blog_id' => $blog, |
| @@ -87,9 +128,9 @@ | ||
| 87 | 128 | |
| 88 | 129 | $success = $this->task_manager->compress_single_image($image, $options, $server); |
| 89 | 130 | |
| 90 | 131 | if (!$success) { |
| 91 | - 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)); | |
| 92 | 133 | } |
| 93 | 134 | |
| 94 | 135 | $response = array(); |
| 95 | 136 | $response['status'] = true; |
| @@ -97,15 +138,17 @@ | ||
| 97 | 138 | $response['options'] = $options; |
| 98 | 139 | $response['server'] = $server; |
| 99 | 140 | $response['success'] = $success; |
| 100 | 141 | $response['restore_possible'] = $backup; |
| 101 | - $response['summary'] = get_post_meta($image, 'smush-info', true); | |
| 142 | + $response['summary'] = get_post_meta($image, '_wpo-smush-info', true); | |
| 102 | 143 | |
| 103 | - $smush_stats = get_post_meta($image, 'smush-stats', true); | |
| 144 | + $smush_stats = get_post_meta($image, '_wpo-smush-stats', true); | |
| 104 | 145 | if (isset($smush_stats['sizes-info'])) { |
| 105 | 146 | $response['sizes-info'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info'])); |
| 106 | 147 | } |
| 107 | 148 | |
| 149 | + $response['media_column_html'] = $this->get_smush_media_column_content($blog, $image); | |
| 150 | + | |
| 108 | 151 | return $response; |
| 109 | 152 | } |
| 110 | 153 | |
| 111 | 154 | /** |
| @@ -110,15 +153,15 @@ | ||
| 110 | 153 | |
| 111 | 154 | /** |
| 112 | 155 | * Restores a single image, if backup is available |
| 113 | 156 | * |
| 114 | - * @param mixed $data - Sent in via AJAX | |
| 157 | + * @param array $data - Sent in via AJAX | |
| 115 | 158 | * @return WP_Error|array - information about the operation or a WP_Error object on failure |
| 116 | 159 | */ |
| 117 | 160 | public function restore_single_image($data) { |
| 118 | 161 | |
| 119 | - $blog_id = isset($data['blog_id']) ? $data['blog_id'] : false; | |
| 120 | - $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; | |
| 121 | 164 | |
| 122 | 165 | $success = $this->task_manager->restore_single_image($image_id, $blog_id); |
| 123 | 166 | |
| 124 | 167 | if (is_wp_error($success)) { |
| @@ -131,8 +174,10 @@ | ||
| 131 | 174 | $response['blog_id'] = $blog_id; |
| 132 | 175 | $response['image'] = $image_id; |
| 133 | 176 | $response['success'] = $success; |
| 134 | 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); | |
| 135 | 180 | |
| 136 | 181 | return $response; |
| 137 | 182 | } |
| 138 | 183 | |
| @@ -138,28 +183,48 @@ | ||
| 138 | 183 | |
| 139 | 184 | /** |
| 140 | 185 | * Process the compression of multiple images |
| 141 | 186 | * |
| 142 | - * @param mixed $data - Sent in via AJAX | |
| 187 | + * @param array $data - Sent in via AJAX | |
| 188 | + * @return array | |
| 143 | 189 | */ |
| 144 | 190 | public function process_bulk_smush($data = array()) { |
| 145 | - $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; | |
| 146 | 194 | |
| 147 | - $ui_update = $this->get_ui_update($images); | |
| 148 | - $this->close_browser_connection(json_encode($ui_update)); | |
| 149 | - $this->task_manager->process_bulk_smush($images); | |
| 150 | - // Since we already sent back data and closed the browser connection, we must not return (that would result in further sending back of JSON). | |
| 151 | - 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; | |
| 152 | 202 | } |
| 153 | 203 | |
| 154 | 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 | + /** | |
| 155 | 217 | * Returns useful information for the UI and closes the connection |
| 156 | 218 | * |
| 157 | - * @param mixed $data - Sent in via AJAX | |
| 219 | + * @param array $data - Sent in via AJAX | |
| 158 | 220 | * |
| 159 | - * @return mixed - Information for the UI | |
| 221 | + * @return array - Information for the UI | |
| 160 | 222 | */ |
| 161 | 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 | + | |
| 162 | 227 | $ui_update = array(); |
| 163 | 228 | $ui_update['status'] = true; |
| 164 | 229 | $ui_update['is_multisite'] = is_multisite() ? 1 : 0; |
| 165 | 230 | $pending_tasks = $this->task_manager->get_pending_tasks(); |
| @@ -164,9 +229,9 @@ | ||
| 164 | 229 | $ui_update['is_multisite'] = is_multisite() ? 1 : 0; |
| 165 | 230 | $pending_tasks = $this->task_manager->get_pending_tasks(); |
| 166 | 231 | |
| 167 | 232 | $ui_update['pending_tasks'] = is_array($pending_tasks) ? count($this->task_manager->get_pending_tasks()) : 0; |
| 168 | - $ui_update['unsmushed_images'] = $this->task_manager->get_uncompressed_images(); | |
| 233 | + $ui_update['unsmushed_images'] = $this->task_manager->get_uncompressed_images($use_cache); | |
| 169 | 234 | $ui_update['admin_urls'] = $this->task_manager->get_admin_urls(); |
| 170 | 235 | $ui_update['completed_task_count'] = $this->task_manager->options->get_option('completed_task_count', 0); |
| 171 | 236 | $ui_update['bytes_saved'] = WP_Optimize()->format_size($this->task_manager->options->get_option('total_bytes_saved', 0)); |
| 172 | 237 | $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%'; |
| @@ -171,23 +236,32 @@ | ||
| 171 | 236 | $ui_update['bytes_saved'] = WP_Optimize()->format_size($this->task_manager->options->get_option('total_bytes_saved', 0)); |
| 172 | 237 | $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%'; |
| 173 | 238 | $ui_update['failed_task_count'] = $this->task_manager->get_failed_task_count(); |
| 174 | 239 | |
| 175 | - $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 %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']); | |
| 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 | |
| 176 | 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 | |
| 177 | 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'); |
| 178 | 251 | $ui_update['smush_complete'] = $this->task_manager->is_queue_processed(); |
| 179 | 252 | |
| 180 | - if (isset($data['image_list'])) { | |
| 181 | - $images = $data['image_list']; | |
| 182 | - $stats = $this->task_manager->get_session_stats($images); | |
| 253 | + if ($image_list) { | |
| 254 | + $stats = $this->task_manager->get_session_stats($image_list); | |
| 183 | 255 | $ui_update['session_stats'] = ""; |
| 184 | 256 | |
| 185 | 257 | if (!empty($stats['success'])) { |
| 186 | - $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']); | |
| 187 | 260 | } |
| 188 | 261 | |
| 189 | 262 | if (!empty($stats['fail'])) { |
| 263 | + // translators: %d: number of images that could not be compressed | |
| 190 | 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'); |
| 191 | 265 | } |
| 192 | 266 | } |
| 193 | 267 | |
| @@ -195,32 +269,48 @@ | ||
| 195 | 269 | |
| 196 | 270 | } |
| 197 | 271 | |
| 198 | 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 | + /** | |
| 199 | 294 | * Updates smush related options |
| 200 | 295 | * |
| 201 | - * @param mixed $data - Sent in via AJAX | |
| 296 | + * @param array $data - Sent in via AJAX | |
| 202 | 297 | * @return WP_Error|array - information about the operation or WP_Error object on failure |
| 203 | 298 | */ |
| 204 | 299 | public function update_smush_options($data) { |
| 205 | 300 | $options = array(); |
| 206 | - $options['compression_server'] = sanitize_text_field($data['compression_server']); | |
| 207 | - $options['lossy_compression'] = filter_var($data['lossy_compression'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 208 | - $options['back_up_original'] = filter_var($data['back_up_original'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 209 | - $options['back_up_delete_after'] = filter_var($data['back_up_delete_after'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 210 | - $options['back_up_delete_after_days'] = filter_var($data['back_up_delete_after_days'], FILTER_SANITIZE_NUMBER_INT); | |
| 211 | - $options['preserve_exif'] = filter_var($data['preserve_exif'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 212 | - $options['autosmush'] = filter_var($data['autosmush'], FILTER_VALIDATE_BOOLEAN) ? true : false; | |
| 213 | - $options['image_quality'] = filter_var($data['image_quality'], FILTER_SANITIZE_NUMBER_INT); | |
| 214 | - $options['show_smush_metabox'] = filter_var($data['show_smush_metabox'], FILTER_VALIDATE_BOOLEAN) ? 'show' : 'hide'; | |
| 215 | - $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'; | |
| 216 | 310 | |
| 217 | 311 | $success = $this->task_manager->update_smush_options($options); |
| 218 | 312 | |
| 219 | - if (!$this->is_webp_enabled($options['webp_conversion'])) { | |
| 220 | - $this->remove_webp_redirect_rules(); | |
| 221 | - } | |
| 222 | - | |
| 223 | 313 | if (!$success) { |
| 224 | 314 | return new WP_Error('update_failed', __('Smush options could not be updated', 'wp-optimize')); |
| 225 | 315 | } |
| 226 | 316 | |
| @@ -256,12 +346,14 @@ | ||
| 256 | 346 | |
| 257 | 347 | /** |
| 258 | 348 | * Checks if the selected server is online |
| 259 | 349 | * |
| 260 | - * @param mixed $data - Sent in via AJAX | |
| 350 | + * @param array $data - Sent in via AJAX | |
| 351 | + * | |
| 352 | + * @return array | |
| 261 | 353 | */ |
| 262 | 354 | public function check_server_status($data) { |
| 263 | - $server = sanitize_text_field($data['server']); | |
| 355 | + $server = isset($data['server']) ? sanitize_text_field($data['server']) : $this->task_manager->get_default_webservice(); | |
| 264 | 356 | $response = array(); |
| 265 | 357 | $response['status'] = true; |
| 266 | 358 | $response['online'] = $this->task_manager->check_server_online($server); |
| 267 | 359 | |
| @@ -273,20 +365,30 @@ | ||
| 273 | 365 | } |
| 274 | 366 | |
| 275 | 367 | /** |
| 276 | 368 | * Completes any pending tasks |
| 369 | + * | |
| 370 | + * @return array | |
| 277 | 371 | */ |
| 278 | 372 | public function process_pending_images() { |
| 279 | - $this->process_bulk_smush(); | |
| 373 | + return $this->process_bulk_smush(); | |
| 280 | 374 | } |
| 281 | 375 | |
| 282 | 376 | /** |
| 283 | 377 | * Deletes and removes any pending tasks from queue |
| 284 | 378 | * |
| 379 | + * @param array $data - in 'restore_images' index passed an array with ids of images to restore | |
| 285 | 380 | * @return WP_Error|array - information about the operation or WP_Error object on failure |
| 286 | 381 | */ |
| 287 | - public function clear_pending_images() { | |
| 382 | + public function clear_pending_images($data) { | |
| 288 | 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 | + | |
| 289 | 391 | $success = $this->task_manager->clear_pending_images(); |
| 290 | 392 | |
| 291 | 393 | if (!$success) { |
| 292 | 394 | return new WP_Error('error_deleting_tasks', __('Pending tasks could not be cleared', 'wp-optimize')); |
| @@ -309,10 +411,11 @@ | ||
| 309 | 411 | $response = array(); |
| 310 | 412 | $selected_images = array(); |
| 311 | 413 | |
| 312 | 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(); | |
| 313 | 416 | |
| 314 | - foreach ($data['selected_images'] as $image) { | |
| 417 | + foreach ($image_list as $image) { | |
| 315 | 418 | if (!array_key_exists($image['blog_id'], $selected_images)) $selected_images[$image['blog_id']] = array(); |
| 316 | 419 | |
| 317 | 420 | $selected_images[$image['blog_id']][] = $image['attachment_id']; |
| 318 | 421 | } |
| @@ -323,15 +426,15 @@ | ||
| 323 | 426 | if (is_multisite()) switch_to_blog($blog_id); |
| 324 | 427 | |
| 325 | 428 | foreach ($selected_images[$blog_id] as $attachment_id) { |
| 326 | 429 | if ($unmark) { |
| 327 | - delete_post_meta($attachment_id, 'smush-complete'); | |
| 328 | - delete_post_meta($attachment_id, 'smush-marked'); | |
| 329 | - 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'); | |
| 330 | 433 | } else { |
| 331 | - update_post_meta($attachment_id, 'smush-complete', true); | |
| 332 | - update_post_meta($attachment_id, 'smush-marked', true); | |
| 333 | - 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); | |
| 334 | 437 | } |
| 335 | 438 | } |
| 336 | 439 | |
| 337 | 440 | if (is_multisite()) restore_current_blog(); |
| @@ -339,15 +442,20 @@ | ||
| 339 | 442 | |
| 340 | 443 | $response['status'] = true; |
| 341 | 444 | |
| 342 | 445 | if ($unmark) { |
| 343 | - $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'); | |
| 344 | 447 | } else { |
| 345 | - $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'); | |
| 346 | 449 | } |
| 347 | 450 | |
| 348 | 451 | $response['info'] = $info; |
| 349 | 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 | + | |
| 350 | 458 | return $response; |
| 351 | 459 | } |
| 352 | 460 | |
| 353 | 461 | /** |
| @@ -365,8 +473,9 @@ | ||
| 365 | 473 | |
| 366 | 474 | if (is_multisite()) { |
| 367 | 475 | // option where we store last completed blog id |
| 368 | 476 | $option_name = 'mark_as_uncompressed_last_blog_id'; |
| 477 | + $smushed_images_total_option_name = 'smushed_images_total'; | |
| 369 | 478 | // set default value for response |
| 370 | 479 | $response = array( |
| 371 | 480 | 'completed' => true, |
| 372 | 481 | 'message' => __('All the compressed images were successfully restored.', 'wp-optimize'), |
| @@ -383,9 +492,9 @@ | ||
| 383 | 492 | |
| 384 | 493 | if ($index < count($blogs_ids)) { |
| 385 | 494 | $blog_id = $blogs_ids[$index]; |
| 386 | 495 | $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, $blog_id, $images_per_request, $delete_only_backups_meta); |
| 387 | - | |
| 496 | + $smushed_images_total = $this->task_manager->options->get_option($smushed_images_total_option_name, 0) + $response['smushed_images_count']; | |
| 388 | 497 | // if we get completed the current blog then update last completed blog option value |
| 389 | 498 | // and if we have other blogs for processing then set complete to false as we have not |
| 390 | 499 | // processed all blogs |
| 391 | 500 | if ($response['completed']) { |
| @@ -390,16 +499,23 @@ | ||
| 390 | 499 | // processed all blogs |
| 391 | 500 | if ($response['completed']) { |
| 392 | 501 | if ($index + 1 < count($blogs_ids)) { |
| 393 | 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); | |
| 394 | 505 | } else { |
| 395 | 506 | if ($delete_only_backups_meta) { |
| 396 | - $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 | + } | |
| 397 | 514 | } else { |
| 398 | 515 | $response['message'] = __('All the compressed images were successfully marked as uncompressed.', 'wp-optimize'); |
| 399 | 516 | } |
| 400 | 517 | } |
| 401 | - $this->task_manager->options->update_option($option_name, $blog_id); | |
| 402 | 518 | } |
| 403 | 519 | } |
| 404 | 520 | |
| 405 | 521 | // if we get an error or completed the work then delete option with last completed blog id. |
| @@ -404,8 +520,9 @@ | ||
| 404 | 520 | |
| 405 | 521 | // if we get an error or completed the work then delete option with last completed blog id. |
| 406 | 522 | if ($response['completed'] || isset($response['error'])) { |
| 407 | 523 | $this->task_manager->options->delete_option($option_name); |
| 524 | + $this->task_manager->options->delete_option($smushed_images_total_option_name); | |
| 408 | 525 | } |
| 409 | 526 | } else { |
| 410 | 527 | $response = $this->task_manager->bulk_restore_compressed_images($restore_backup, 0, $images_per_request, $delete_only_backups_meta); |
| 411 | 528 | } |
| @@ -415,9 +532,9 @@ | ||
| 415 | 532 | |
| 416 | 533 | /** |
| 417 | 534 | * Returns the log file |
| 418 | 535 | * |
| 419 | - * @return WP_Error|file - logfile or WP_Error object on failure | |
| 536 | + * @return void|WP_Error - logfile or WP_Error object on failure | |
| 420 | 537 | */ |
| 421 | 538 | public function get_smush_logs() { |
| 422 | 539 | |
| 423 | 540 | $logfile = $this->task_manager->get_logfile_path(); |
| @@ -426,17 +543,23 @@ | ||
| 426 | 543 | $this->task_manager->write_log_header(); |
| 427 | 544 | } |
| 428 | 545 | |
| 429 | 546 | if (is_file($logfile)) { |
| 430 | - header('Content-Description: File Transfer'); | |
| 431 | - header('Content-Type: application/octet-stream'); | |
| 432 | - header('Content-Disposition: attachment; filename="'.basename($logfile).'"'); | |
| 433 | - header('Expires: 0'); | |
| 434 | - header('Cache-Control: must-revalidate'); | |
| 435 | - header('Pragma: public'); | |
| 436 | - header('Content-Length: ' . filesize($logfile)); | |
| 437 | - readfile($logfile); | |
| 438 | - 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 | + } | |
| 439 | 562 | } else { |
| 440 | 563 | return new WP_Error('log_file_error', __('Log file does not exist or could not be read', 'wp-optimize')); |
| 441 | 564 | } |
| 442 | 565 | } |
| @@ -457,40 +580,22 @@ | ||
| 457 | 580 | ); |
| 458 | 581 | } |
| 459 | 582 | |
| 460 | 583 | /** |
| 461 | - * Close browser connection so that it can resume AJAX polling | |
| 584 | + * Resets webp serving method | |
| 462 | 585 | * |
| 463 | - * @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below) | |
| 464 | - * @return void | |
| 586 | + * @return array|WP_Error | |
| 465 | 587 | */ |
| 466 | - public function close_browser_connection($txt = '') { | |
| 467 | - header('Content-Length: '.((!empty($txt)) ? 4+strlen($txt) : '0')); | |
| 468 | - header('Content-Type: application/json'); | |
| 469 | - header('Connection: close'); | |
| 470 | - header('Content-Encoding: none'); | |
| 471 | - if (session_id()) session_write_close(); | |
| 472 | - echo "\r\n\r\n"; | |
| 473 | - echo $txt; | |
| 474 | - | |
| 475 | - $levels = ob_get_level(); | |
| 476 | - | |
| 477 | - for ($i = 0; $i < $levels; $i++) { | |
| 478 | - ob_end_flush(); | |
| 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')); | |
| 479 | 595 | } |
| 480 | 596 | |
| 481 | - flush(); | |
| 482 | - | |
| 483 | - if (function_exists('fastcgi_finish_request')) fastcgi_finish_request(); | |
| 484 | - } | |
| 485 | - | |
| 486 | - /** | |
| 487 | - * Resets webp serving method | |
| 488 | - * | |
| 489 | - * @return array | |
| 490 | - */ | |
| 491 | - public function reset_webp_serving_method() { | |
| 492 | - WP_Optimize()->get_webp_instance()->reset_webp_serving_method(); | |
| 597 | + $webp_instance->reset_webp_serving_method(); | |
| 493 | 598 | return array( |
| 494 | 599 | 'success' => true, |
| 495 | 600 | ); |
| 496 | 601 | } |
| @@ -501,9 +606,9 @@ | ||
| 501 | 606 | * @param array $data |
| 502 | 607 | * @return array |
| 503 | 608 | */ |
| 504 | 609 | public function convert_to_webp_format($data) { |
| 505 | - $attachment_id = isset($data['attachment_id']) ? $data['attachment_id'] : 0; | |
| 610 | + $attachment_id = isset($data['attachment_id']) ? absint($data['attachment_id']) : 0; | |
| 506 | 611 | if (0 === $attachment_id) return $this->image_not_found_response(); |
| 507 | 612 | |
| 508 | 613 | $images = WPO_Image_Utils::get_attachment_files($attachment_id); |
| 509 | 614 | if (empty($images)) return $this->image_not_found_response(); |
| @@ -509,9 +614,11 @@ | ||
| 509 | 614 | if (empty($images)) return $this->image_not_found_response(); |
| 510 | 615 | |
| 511 | 616 | $images['original'] = get_attached_file($attachment_id); |
| 512 | 617 | foreach ($images as $image) { |
| 513 | - WPO_WebP_Utils::do_webp_conversion($image); | |
| 618 | + if (!is_file($image.'.webp')) { | |
| 619 | + WPO_WebP_Utils::do_webp_conversion($image); | |
| 620 | + } | |
| 514 | 621 | } |
| 515 | 622 | |
| 516 | 623 | return array( |
| 517 | 624 | 'success' => __('Image is converted to WebP format.', 'wp-optimize'), |
| @@ -518,8 +625,53 @@ | ||
| 518 | 625 | ); |
| 519 | 626 | } |
| 520 | 627 | |
| 521 | 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); | |
| 667 | + | |
| 668 | + if (is_multisite()) restore_current_blog(); | |
| 669 | + | |
| 670 | + return $content; | |
| 671 | + } | |
| 672 | + | |
| 673 | + /** | |
| 522 | 674 | * Returns image not found response |
| 523 | 675 | * |
| 524 | 676 | * @return array |
| 525 | 677 | */ |
| @@ -527,27 +679,54 @@ | ||
| 527 | 679 | return array( |
| 528 | 680 | 'error' => __('Image not found', 'wp-optimize'), |
| 529 | 681 | ); |
| 530 | 682 | } |
| 531 | - | |
| 683 | + | |
| 532 | 684 | /** |
| 533 | - * Decides whether to use webp images option is enabled or not | |
| 685 | + * Get smush details of given image IDs | |
| 534 | 686 | * |
| 535 | - * @param bool $webp_option | |
| 687 | + * @param array $data | |
| 536 | 688 | * |
| 537 | - * @return bool | |
| 689 | + * @return array | |
| 538 | 690 | */ |
| 539 | - private function is_webp_enabled($webp_option) { | |
| 540 | - 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 | + ); | |
| 541 | 702 | } |
| 542 | 703 | |
| 543 | 704 | /** |
| 544 | - * Removes webp redirect rules in .htaccess file | |
| 705 | + * Sanitize array of images ensuring proper integer values for attachment_id and blog_id | |
| 545 | 706 | * |
| 546 | - * @return void | |
| 707 | + * @param array $images Array of image data to sanitize | |
| 708 | + * @return array | |
| 547 | 709 | */ |
| 548 | - private function remove_webp_redirect_rules() { | |
| 549 | - 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; | |
| 550 | 729 | } |
| 551 | 730 | } |
| 552 | 731 | |
| 553 | 732 | endif; |