| @@ -11,9 +11,9 @@ | ||
| 11 | 11 | |
| 12 | 12 | abstract class Updraft_Smush_Task extends Updraft_Task_1_2 { |
| 13 | 13 | |
| 14 | 14 | /** |
| 15 | - * A flag indicating if the operation was succesful | |
| 15 | + * A flag indicating if the operation was successful | |
| 16 | 16 | * |
| 17 | 17 | * @var bool |
| 18 | 18 | */ |
| 19 | 19 | protected $success = false; |
| @@ -27,9 +27,9 @@ | ||
| 27 | 27 | |
| 28 | 28 | /** |
| 29 | 29 | * Initialise the task |
| 30 | 30 | * |
| 31 | - * @param Array $options - options to use | |
| 31 | + * @param array $options - options to use | |
| 32 | 32 | */ |
| 33 | 33 | public function initialise($options = array()) { |
| 34 | 34 | parent::initialise($options); |
| 35 | 35 | $this->set_current_stage('initialised'); |
| @@ -61,9 +61,9 @@ | ||
| 61 | 61 | |
| 62 | 62 | $api_endpoint = $this->get_option('api_endpoint'); |
| 63 | 63 | |
| 64 | 64 | if (false === filter_var($api_endpoint, FILTER_VALIDATE_URL)) { |
| 65 | - $this->fail('invalid_api_url', "The API endpoint supplied {$api_endpoint} is invalid"); | |
| 65 | + $this->fail('invalid_api_url', "The API endpoint supplied $api_endpoint is invalid"); | |
| 66 | 66 | return false; |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | 69 | $original_image = $file_path; |
| @@ -74,11 +74,26 @@ | ||
| 74 | 74 | |
| 75 | 75 | $this->update_option('original_filesize', filesize($file_path)); |
| 76 | 76 | |
| 77 | 77 | // build list of files for smush. |
| 78 | - $files = array_merge(array('full' => $file_path), $this->get_attachment_files($attachment_id)); | |
| 78 | + if (is_multisite()) { | |
| 79 | + switch_to_blog($this->get_option('blog_id', 1)); | |
| 80 | + $files = array_merge(array('full' => $file_path), WPO_Image_Utils::get_attachment_files($attachment_id)); | |
| 81 | + restore_current_blog(); | |
| 82 | + } else { | |
| 83 | + $files = array_merge(array('full' => $file_path), WPO_Image_Utils::get_attachment_files($attachment_id)); | |
| 84 | + } | |
| 79 | 85 | |
| 80 | 86 | $sizes_info = array(); |
| 87 | + $webp_tools_available = true; | |
| 88 | + $lossy = $this->get_option('lossy_compression'); | |
| 89 | + if ($lossy) { | |
| 90 | + $quality = $this->get_option('image_quality'); | |
| 91 | + } else { | |
| 92 | + $quality = 92; | |
| 93 | + } | |
| 94 | + $this->log($this->get_description()); | |
| 95 | + $this->log("File: " . basename($file_path) . ", Compression quality: $quality"); | |
| 81 | 96 | |
| 82 | 97 | foreach ($files as $size => $file_path) { |
| 83 | 98 | |
| 84 | 99 | if (in_array($size, $dont_smush_sizes)) continue; |
| @@ -88,15 +103,23 @@ | ||
| 88 | 103 | if ($file_size > 5242880) { |
| 89 | 104 | $this->update_option('request_timeout', 180); |
| 90 | 105 | } |
| 91 | 106 | |
| 92 | - $this->log($this->get_description()); | |
| 107 | + $ext = WPO_Image_Utils::get_extension($file_path); | |
| 108 | + $allowed_extensions = WPO_Image_Utils::get_allowed_extensions(); | |
| 109 | + $allowed_extensions = array_diff($allowed_extensions, array('gif')); | |
| 110 | + if (WPO_WebP_Utils::can_do_webp_conversion()) { | |
| 111 | + if (WPO_Image_Utils::is_supported_extension($ext, $allowed_extensions)) { | |
| 112 | + WPO_WebP_Utils::do_webp_conversion($file_path); | |
| 113 | + } | |
| 114 | + } else { | |
| 115 | + $webp_tools_available = false; | |
| 116 | + } | |
| 93 | 117 | |
| 94 | - $this->maybe_do_webp_conversion($file_path); | |
| 95 | - | |
| 118 | + | |
| 96 | 119 | /** |
| 97 | 120 | * Filters the options for a single image to compress. |
| 98 | - * Currently supports: | |
| 121 | + * Currently, supports: | |
| 99 | 122 | * - 'quality': Will use the image quality set in this filter, instead of the one defined in the settings. |
| 100 | 123 | * |
| 101 | 124 | * @param array $options - The options (default: empty array) |
| 102 | 125 | * @param integer $attachment_id - The attachment post ID |
| @@ -110,9 +133,9 @@ | ||
| 110 | 133 | $response = $this->post_to_remote_server($api_endpoint, $post_data); |
| 111 | 134 | $optimised_image = $this->process_server_response($response); |
| 112 | 135 | |
| 113 | 136 | if ($optimised_image) { |
| 114 | - $backup_image = ($original_image == $file_path) ? $backup_original_image : false; | |
| 137 | + $backup_image = ($original_image === $file_path) ? $backup_original_image : false; | |
| 115 | 138 | $this->save_optimised_image($file_path, $optimised_image, $backup_image); |
| 116 | 139 | |
| 117 | 140 | clearstatcache($file_path); |
| 118 | 141 | |
| @@ -125,32 +148,32 @@ | ||
| 125 | 148 | } |
| 126 | 149 | |
| 127 | 150 | $this->update_option('smush-sizes-info', $sizes_info); |
| 128 | 151 | |
| 129 | - return $this->success; | |
| 130 | - } | |
| 152 | + if (!$webp_tools_available) { | |
| 153 | + $this->log('There were no WebP conversion tools found on your server.'); | |
| 154 | + } | |
| 131 | 155 | |
| 132 | - /** | |
| 133 | - * Converts to WebP format, if possible | |
| 134 | - * | |
| 135 | - * @param string $source Source image file path | |
| 136 | - */ | |
| 137 | - public function maybe_do_webp_conversion($source) { | |
| 138 | - $webp_conversion = WP_Optimize()->get_options()->get_option('webp_conversion', false); | |
| 139 | - if (!empty($webp_conversion)) { | |
| 140 | - $webp_converter = new WPO_WebP_Convert(); | |
| 141 | - $webp_converter->convert($source); | |
| 142 | - } else { | |
| 143 | - $this->log('There were no WebP conversion tools found on your server.'); | |
| 156 | + $destination = WPO_WebP_Utils::get_destination_path($file_path); | |
| 157 | + if ($webp_tools_available && file_exists($destination)) { | |
| 158 | + if (is_multisite()) { | |
| 159 | + switch_to_blog($this->get_option('blog_id', 1)); | |
| 160 | + update_post_meta($attachment_id, WPO_Webp_Convert_Image_Task::WEBP_CONVERSION_META_KEY, true); | |
| 161 | + restore_current_blog(); | |
| 162 | + } else { | |
| 163 | + update_post_meta($attachment_id, WPO_Webp_Convert_Image_Task::WEBP_CONVERSION_META_KEY, true); | |
| 164 | + } | |
| 144 | 165 | } |
| 166 | + | |
| 167 | + return $this->success; | |
| 145 | 168 | } |
| 146 | 169 | |
| 147 | 170 | /** |
| 148 | 171 | * Posts the supplied data to the API url and returns a response |
| 149 | 172 | * |
| 150 | - * @param String $api_endpoint - the url to post the form to | |
| 151 | - * @param String $post_data - the post data as specified by the server | |
| 152 | - * @return mixed - the response | |
| 173 | + * @param string $api_endpoint - the url to post the form to | |
| 174 | + * @param array $post_data - the post data as specified by the server | |
| 175 | + * @return array|false|WP_Error - the response | |
| 153 | 176 | */ |
| 154 | 177 | public function post_to_remote_server($api_endpoint, $post_data) { |
| 155 | 178 | |
| 156 | 179 | $this->set_current_stage('connecting'); |
| @@ -164,9 +187,9 @@ | ||
| 164 | 187 | return $response; |
| 165 | 188 | } |
| 166 | 189 | |
| 167 | 190 | /** |
| 168 | - * Processes the response recieved from the remote server | |
| 191 | + * Processes the response received from the remote server | |
| 169 | 192 | * |
| 170 | 193 | * @param mixed $response - the response object |
| 171 | 194 | * @return mixed - the response |
| 172 | 195 | */ |
| @@ -177,9 +200,9 @@ | ||
| 177 | 200 | |
| 178 | 201 | /** |
| 179 | 202 | * Checks if a file is valid and capable of being smushed |
| 180 | 203 | * |
| 181 | - * @param String $file_path - the path of the original image | |
| 204 | + * @param string $file_path - the path of the original image | |
| 182 | 205 | * @return bool - true on success, false otherwise |
| 183 | 206 | */ |
| 184 | 207 | public function validate_file($file_path) { |
| 185 | 208 | |
| @@ -205,9 +228,9 @@ | ||
| 205 | 228 | |
| 206 | 229 | /** |
| 207 | 230 | * Creates a backup of the original image |
| 208 | 231 | * |
| 209 | - * @param String $file_path - the path of the original image | |
| 232 | + * @param string $file_path - the path of the original image | |
| 210 | 233 | * @return bool - true on success, false otherwise |
| 211 | 234 | */ |
| 212 | 235 | public function backup_original_image($file_path) { |
| 213 | 236 | |
| @@ -223,15 +246,15 @@ | ||
| 223 | 246 | |
| 224 | 247 | // Make path relative and safe for migrations |
| 225 | 248 | $back_up_relative_path = preg_replace('#^'.wp_normalize_path($uploads_dir['basedir'].'/').'#', '', $back_up); |
| 226 | 249 | |
| 227 | - update_post_meta($this->get_option('attachment_id'), 'original-file', $back_up_relative_path); | |
| 250 | + update_post_meta($this->get_option('attachment_id'), '_wpo-original-file', $back_up_relative_path); | |
| 228 | 251 | |
| 229 | 252 | if (is_multisite()) { |
| 230 | 253 | restore_current_blog(); |
| 231 | 254 | } |
| 232 | 255 | |
| 233 | - $this->log("Backing up the original image - {$back_up_relative_path}"); | |
| 256 | + $this->log("Backing up the original image - $back_up_relative_path"); | |
| 234 | 257 | |
| 235 | 258 | return copy($file_path, $back_up); |
| 236 | 259 | } |
| 237 | 260 | |
| @@ -237,10 +260,10 @@ | ||
| 237 | 260 | |
| 238 | 261 | /** |
| 239 | 262 | * Creates a backup of the original image |
| 240 | 263 | * |
| 241 | - * @param String $file_path - the path of the original image | |
| 242 | - * @param Mixes $optimised_image - the contents of the image | |
| 264 | + * @param string $file_path - the path of the original image | |
| 265 | + * @param mixed $optimised_image - the contents of the image | |
| 243 | 266 | * @param bool $backup_original - backup original image |
| 244 | 267 | * |
| 245 | 268 | * @return bool - true on success, false otherwise |
| 246 | 269 | */ |
| @@ -260,9 +283,9 @@ | ||
| 260 | 283 | return $this->success; |
| 261 | 284 | } |
| 262 | 285 | |
| 263 | 286 | /** |
| 264 | - * Fires if the task succeds, any clean up code and logging goes here | |
| 287 | + * Fires if the task succeeds, any clean up code and logging goes here | |
| 265 | 288 | */ |
| 266 | 289 | public function complete() { |
| 267 | 290 | |
| 268 | 291 | $attachment_id = $this->get_option('attachment_id'); |
| @@ -274,18 +297,20 @@ | ||
| 274 | 297 | } else { |
| 275 | 298 | $file_path = get_attached_file($attachment_id); |
| 276 | 299 | } |
| 277 | 300 | |
| 278 | - $original_size = $this->get_option('original_filesize'); | |
| 301 | + $original_size = (int) $this->get_option('original_filesize'); | |
| 279 | 302 | $this->set_current_stage('completed'); |
| 280 | 303 | |
| 281 | - clearstatcache(true, $file_path); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.clearstatcache_clear_realpath_cacheFound,PHPCompatibility.FunctionUse.NewFunctionParameters.clearstatcache_filenameFound | |
| 282 | - if (0 == $original_size) { | |
| 304 | + clearstatcache(true, $file_path); | |
| 305 | + if (0 === $original_size) { | |
| 283 | 306 | $saved = ''; |
| 307 | + // translators: %s is a file size | |
| 284 | 308 | $info = sprintf(__("The file was compressed to %s using WP-Optimize", 'wp-optimize'), WP_Optimize()->format_size(filesize($file_path))); |
| 285 | 309 | } else { |
| 286 | 310 | $saved = round((($original_size - filesize($file_path)) / $original_size * 100), 2); |
| 287 | - $info = sprintf(__("The file was compressed from %s to %s saving %s percent using WP-Optimize", 'wp-optimize'), WP_Optimize()->format_size($original_size), WP_Optimize()->format_size(filesize($file_path)), $saved); | |
| 311 | + // translators: %1$s is a file size, %2$s is a file size, %3$s is a percentage | |
| 312 | + $info = sprintf(__('The file was compressed from %1$s to %2$s, saving %3$s percent, using WP-Optimize', 'wp-optimize'), WP_Optimize()->format_size($original_size), WP_Optimize()->format_size(filesize($file_path)), $saved); | |
| 288 | 313 | } |
| 289 | 314 | |
| 290 | 315 | $stats = array( |
| 291 | 316 | 'smushed-with' => $this->label, |
| @@ -296,19 +321,19 @@ | ||
| 296 | 321 | ); |
| 297 | 322 | |
| 298 | 323 | if (is_multisite()) { |
| 299 | 324 | switch_to_blog($this->get_option('blog_id', 1)); |
| 300 | - update_post_meta($attachment_id, 'smush-complete', true); | |
| 301 | - update_post_meta($attachment_id, 'smush-info', $info); | |
| 302 | - update_post_meta($attachment_id, 'smush-stats', $stats); | |
| 325 | + update_post_meta($attachment_id, '_wpo-smush-complete', true); | |
| 326 | + update_post_meta($attachment_id, '_wpo-smush-info', $info); | |
| 327 | + update_post_meta($attachment_id, '_wpo-smush-stats', $stats); | |
| 303 | 328 | restore_current_blog(); |
| 304 | 329 | } else { |
| 305 | - update_post_meta($attachment_id, 'smush-complete', true); | |
| 306 | - update_post_meta($attachment_id, 'smush-info', $info); | |
| 307 | - update_post_meta($attachment_id, 'smush-stats', $stats); | |
| 330 | + update_post_meta($attachment_id, '_wpo-smush-complete', true); | |
| 331 | + update_post_meta($attachment_id, '_wpo-smush-info', $info); | |
| 332 | + update_post_meta($attachment_id, '_wpo-smush-stats', $stats); | |
| 308 | 333 | } |
| 309 | 334 | |
| 310 | - $this->log("Successfully optimized the image - {$file_path}." . $info); | |
| 335 | + $this->log("Successfully optimized the image - $file_path." . $info); | |
| 311 | 336 | $this->set_status('complete'); |
| 312 | 337 | |
| 313 | 338 | return parent::complete(); |
| 314 | 339 | } |
| @@ -315,25 +340,26 @@ | ||
| 315 | 340 | |
| 316 | 341 | /** |
| 317 | 342 | * Fires if the task fails, any clean up code and logging goes here |
| 318 | 343 | * |
| 319 | - * @param String $error_code - A code for the failure | |
| 320 | - * @param String $error_message - A description for the failure | |
| 344 | + * @param string $error_code - A code for the failure | |
| 345 | + * @param string $error_message - A description for the failure | |
| 321 | 346 | */ |
| 322 | 347 | public function fail($error_code = "Unknown", $error_message = "Unknown") { |
| 323 | 348 | |
| 324 | 349 | $attachment_id = $this->get_option('attachment_id'); |
| 325 | 350 | |
| 326 | - $info = sprintf(__("Failed with error code %s - %s", 'wp-optimize'), $error_code, $error_message); | |
| 351 | + // translators: %1$s is the error code, %2$s is the error message | |
| 352 | + $info = sprintf(__('Failed with error code %1$s - %2$s', 'wp-optimize'), $error_code, $error_message); | |
| 327 | 353 | |
| 328 | 354 | if (is_multisite()) { |
| 329 | 355 | switch_to_blog($this->get_option('blog_id', 1)); |
| 330 | - update_post_meta($attachment_id, 'smush-info', $info); | |
| 331 | - update_post_meta($attachment_id, 'smush-complete', false); | |
| 356 | + update_post_meta($attachment_id, '_wpo-smush-info', $info); | |
| 357 | + update_post_meta($attachment_id, '_wpo-smush-complete', false); | |
| 332 | 358 | restore_current_blog(); |
| 333 | 359 | } else { |
| 334 | - update_post_meta($attachment_id, 'smush-info', $info); | |
| 335 | - update_post_meta($attachment_id, 'smush-complete', false); | |
| 360 | + update_post_meta($attachment_id, '_wpo-smush-info', $info); | |
| 361 | + update_post_meta($attachment_id, '_wpo-smush-complete', false); | |
| 336 | 362 | } |
| 337 | 363 | |
| 338 | 364 | |
| 339 | 365 | do_action('ud_smush_task_failed', $this, $error_code, $error_message); |
| @@ -356,36 +382,25 @@ | ||
| 356 | 382 | 'saving_image' => __('Saving optimized image', 'wp-optimize'), |
| 357 | 383 | 'completed' => __('Successful', 'wp-optimize'), |
| 358 | 384 | ); |
| 359 | 385 | |
| 360 | - return apply_filters('allowed_task_stages', $stages); | |
| 386 | + $filtered_stages = apply_filters('allowed_task_stages', $stages); | |
| 387 | + if (!empty($filtered_stages) && is_array($filtered_stages)) return $filtered_stages; | |
| 388 | + return $stages; | |
| 361 | 389 | } |
| 362 | 390 | |
| 363 | 391 | /** |
| 364 | - * Get features available with this service | |
| 365 | - * | |
| 366 | - * @return Array - an array of features | |
| 367 | - */ | |
| 368 | - public static function get_features() { | |
| 369 | - return array( | |
| 370 | - 'max_filesize' => self::MAX_FILESIZE, | |
| 371 | - 'lossy_compression' => true, | |
| 372 | - 'preserve_exif' => true, | |
| 373 | - ); | |
| 374 | - } | |
| 375 | - | |
| 376 | - /** | |
| 377 | 392 | * Retrieve default options for this task. |
| 378 | 393 | * This method should normally be over-ridden by the child. |
| 379 | 394 | * |
| 380 | - * @return Array - an array of options | |
| 395 | + * @return array - an array of options | |
| 381 | 396 | */ |
| 382 | 397 | public function get_default_options() { |
| 383 | 398 | |
| 384 | 399 | return array( |
| 385 | - 'allowed_file_types' => array('gif', 'png', 'jpg', 'tif', 'jpeg'), | |
| 400 | + 'allowed_file_types' => WPO_Image_Utils::get_allowed_extensions(), | |
| 386 | 401 | 'request_timeout' => 15, |
| 387 | - 'image_quality' => 90, | |
| 402 | + 'image_quality' => 92, | |
| 388 | 403 | 'backup_prefix' => '-updraft-pre-smush-original.' |
| 389 | 404 | ); |
| 390 | 405 | } |
| 391 | 406 | |
| @@ -391,9 +406,9 @@ | ||
| 391 | 406 | |
| 392 | 407 | /** |
| 393 | 408 | * Sets the task stage. |
| 394 | 409 | * |
| 395 | - * @param String $stage - the current stage of the task | |
| 410 | + * @param string $stage - the current stage of the task | |
| 396 | 411 | * @return bool - the result of the update |
| 397 | 412 | */ |
| 398 | 413 | public function set_current_stage($stage) { |
| 399 | 414 | |
| @@ -398,9 +413,9 @@ | ||
| 398 | 413 | public function set_current_stage($stage) { |
| 399 | 414 | |
| 400 | 415 | if (array_key_exists($stage, self::get_allowed_stages())) { |
| 401 | 416 | $this->stage = $stage; |
| 402 | - return $this->update_option('current_stage', $this->stage); | |
| 417 | + return (bool) $this->update_option('current_stage', $this->stage); | |
| 403 | 418 | } |
| 404 | 419 | |
| 405 | 420 | return false; |
| 406 | 421 | } |
| @@ -407,50 +422,17 @@ | ||
| 407 | 422 | |
| 408 | 423 | /** |
| 409 | 424 | * Gets the task stage |
| 410 | 425 | * |
| 411 | - * @return String $stage - the current stage of the task | |
| 426 | + * @return string $stage - the current stage of the task | |
| 412 | 427 | */ |
| 413 | 428 | public function get_current_stage() { |
| 414 | - if (isset($this->stage)) | |
| 415 | - return $this->stage; | |
| 416 | - else return $this->get_option('current_stage'); | |
| 429 | + return $this->stage ?? $this->get_option('current_stage'); | |
| 417 | 430 | } |
| 418 | 431 | |
| 419 | 432 | /** |
| 420 | - * Get image paths to resized attachment images. | |
| 433 | + * Check the mime type of downloaded file, returns true if it is a valid image mime type. | |
| 421 | 434 | * |
| 422 | - * @param int $attachment_id | |
| 423 | - * @return array | |
| 424 | - */ | |
| 425 | - private function get_attachment_files($attachment_id) { | |
| 426 | - $attachment_images = array(); | |
| 427 | - $upload_dir = function_exists('wp_get_upload_dir') ? wp_get_upload_dir() : wp_upload_dir(null, false); | |
| 428 | - | |
| 429 | - // get sizes info from attachment meta data. | |
| 430 | - $meta = wp_get_attachment_metadata($attachment_id); | |
| 431 | - if (!is_array($meta) || !array_key_exists('sizes', $meta)) return $attachment_images; | |
| 432 | - | |
| 433 | - $image_sizes = array_keys($meta['sizes']); | |
| 434 | - | |
| 435 | - // build list of resized images. | |
| 436 | - foreach ($image_sizes as $size) { | |
| 437 | - $image = image_get_intermediate_size($attachment_id, $size); | |
| 438 | - | |
| 439 | - if (is_array($image)) { | |
| 440 | - $file = trailingslashit($upload_dir['basedir']) . $image['path']; | |
| 441 | - if (is_file($file) && !in_array($file, $attachment_images)) { | |
| 442 | - $attachment_images[$size] = $file; | |
| 443 | - } | |
| 444 | - } | |
| 445 | - } | |
| 446 | - | |
| 447 | - return $attachment_images; | |
| 448 | - } | |
| 449 | - | |
| 450 | - /** | |
| 451 | - * Check the mime type of a downloaded file, returns true if it is a valid image mime type. | |
| 452 | - * | |
| 453 | 435 | * @param string $file_buffer The buffer string downloaded from the compression service |
| 454 | 436 | * @return boolean |
| 455 | 437 | */ |
| 456 | 438 | protected function is_downloaded_image_buffer_mime_type_valid($file_buffer) { |
| @@ -457,9 +439,9 @@ | ||
| 457 | 439 | // If the required class does not exist, return true to avoid breaking the functionality |
| 458 | 440 | if (!class_exists('finfo')) return true; |
| 459 | 441 | $accepted_types = apply_filters('wpo_image_compression_accepted_mime_types', array('image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/webp')); |
| 460 | 442 | // The ignore rule below is added because "finfo" doesn't exist in PHP5.2. |
| 461 | - $finfo = new finfo(FILEINFO_MIME_TYPE); // phpcs:ignore PHPCompatibility.Classes.NewClasses.finfoFound, PHPCompatibility.Constants.NewConstants.fileinfo_mime_typeFound | |
| 443 | + $finfo = new finfo(FILEINFO_MIME_TYPE); | |
| 462 | 444 | $mime_type = $finfo->buffer($file_buffer); |
| 463 | 445 | return in_array($mime_type, $accepted_types); |
| 464 | 446 | } |
| 465 | 447 | } |