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.php +569 -373 3.2.3 → 4.7.0 View file →
@@ -4,13 +4,13 @@
4 4 */
5 5
6 6 if (!defined('ABSPATH')) die('Access denied.');
7 7
8 -if (!class_exists('Updraft_Task_Manager_1_3')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager.php');
8 +if (!class_exists('Updraft_Task_Manager_1_4')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager.php');
9 9
10 10 if (!class_exists('Updraft_Smush_Manager')) :
11 11
12 -class Updraft_Smush_Manager extends Updraft_Task_Manager_1_3 {
12 +class Updraft_Smush_Manager extends Updraft_Task_Manager_1_4 {
13 13
14 14 static protected $_instance = null;
15 15
16 16 /**
@@ -46,20 +46,14 @@
46 46 */
47 47 public function __construct() {
48 48 parent::__construct();
49 49
50 - if (!class_exists('Updraft_Smush_Manager_Commands')) include_once('class-updraft-smush-manager-commands.php');
51 - if (!class_exists('Updraft_Smush_Task')) include_once('class-updraft-smush-task.php');
52 - if (!class_exists('Re_Smush_It_Task')) include_once('class-updraft-resmushit-task.php');
53 - if (!class_exists('Updraft_Logger_Interface')) include_once('class-updraft-logger-interface.php');
54 - if (!class_exists('Updraft_Abstract_Logger')) include_once('class-updraft-abstract-logger.php');
55 - if (!class_exists('Updraft_File_Logger')) include_once('class-updraft-file-logger.php');
56 - if (!class_exists('WP_Optimize_Transients_Cache')) include_once('class-wp-optimize-transients-cache.php');
57 50
58 51 $this->commands = new Updraft_Smush_Manager_Commands($this);
59 52 $this->options = WP_Optimize()->get_options();
60 53
61 - if (!isset($this->options)) {
54 + // we set default options when compression server is false - it means that options was not saved before
55 + if (!$this->options->get_option('compression_server')) {
62 56 $this->set_default_options();
63 57 }
64 58
65 59 $this->webservice = $this->options->get_option('compression_server', 'resmushit');
@@ -79,12 +73,11 @@
79 73 add_action('ud_task_started', array($this, 'set_task_logger'));
80 74 add_action('ud_task_completed', array($this, 'record_stats'));
81 75 add_action('ud_task_failed', array($this, 'record_stats'));
82 76 add_action('prune_smush_logs', array($this, 'prune_smush_logs'));
83 - add_action('autosmush_process_queue', array($this, 'autosmush_process_queue'));
84 - if ('show' == $this->options->get_option('show_smush_metabox', 'show')) {
77 + add_action('process_smush_tasks', array($this, 'process_smush_tasks'));
78 + if ('show' === $this->options->get_option('show_smush_metabox', 'show')) {
85 79 add_action('add_meta_boxes_attachment', array($this, 'add_smush_metabox'), 10, 2);
86 - add_filter('attachment_fields_to_edit', array($this, 'add_compress_button_to_media_modal' ), 10, 2);
87 80 }
88 81 add_action('delete_attachment', array($this, 'unscheduled_original_file_deletion'));
89 82
90 83 add_filter('manage_media_columns', array($this, 'manage_media_columns'));
@@ -95,11 +88,25 @@
95 88
96 89 // add filter for already compressed images by EWWW Image Optimizer.
97 90 add_filter('wpo_get_uncompressed_images_args', array($this, 'ewww_image_optimizer_compressed_images_args'));
98 91
99 - if (!wp_next_scheduled('wpo_smush_clear_backup_images')) {
100 - wp_schedule_event(time(), 'daily', 'wpo_smush_clear_backup_images');
92 + // schedule or unschedule clear backup images cron, if needed
93 + $scheduled = wp_next_scheduled('wpo_smush_clear_backup_images');
94 + if ($this->options->get_option('back_up_delete_after', true)) {
95 + if (!$scheduled) {
96 + wp_schedule_event(time(), 'daily', 'wpo_smush_clear_backup_images');
97 + }
98 + } else {
99 + if ($scheduled) {
100 + wp_unschedule_event($scheduled, 'wpo_smush_clear_backup_images');
101 + }
101 102 }
103 +
104 + // Schedule CRON job for deleting failed smush tasks
105 + add_action('wpo_smush_clear_failed_tasks', array($this, 'clear_failed_tasks'));
106 + if (!wp_next_scheduled('wpo_smush_clear_failed_tasks')) {
107 + wp_schedule_event(time(), 'wpo_monthly', 'wpo_smush_clear_failed_tasks');
108 + }
102 109 }
103 110
104 111 /**
105 112 * Add custom column to Media Library.
@@ -104,9 +111,9 @@
104 111 /**
105 112 * Add custom column to Media Library.
106 113 *
107 114 * @param array $columns
108 - * @return mixed
115 + * @return array
109 116 */
110 117 public function manage_media_columns($columns) {
111 118 $columns['wpo_smush'] = 'WP-Optimize';
112 119
@@ -120,34 +127,88 @@
120 127 * @param int $attachment_id
121 128 */
122 129 public function manage_media_custom_column($column, $attachment_id) {
123 130 if ('wpo_smush' !== $column) return;
131 + echo $this->get_smush_details($attachment_id); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output already escaped when generating smush details
132 + }
133 +
134 + /**
135 + * Get smush details of given image ID
136 + *
137 + * @param int $attachment_id
138 + *
139 + * @return string smush details
140 + */
141 + public function get_smush_details($attachment_id) {
142 + $info = '<div class="wpo-smush-media-library-column" data-blog="'.esc_attr(get_current_blog_id()).'" data-id="'.esc_attr($attachment_id).'">';
143 + $info .= $this->get_media_smush_column_content($attachment_id);
144 + $info .= '</div>';
124 145
125 - if (!$this->is_compressed($attachment_id)) return;
146 + return $info;
147 + }
126 148
127 - $smush_stats = get_post_meta($attachment_id, 'smush-stats', true);
149 + /**
150 + * Get content for Media Library column.
151 + *
152 + * @param int $attachment_id
153 + *
154 + * @return string
155 + */
156 + public function get_media_smush_column_content($attachment_id) {
157 + $file = get_attached_file($attachment_id);
158 + if (false === $file) {
159 + return '';
160 + }
161 + $ext = WPO_Image_Utils::get_extension($file);
162 + $allowed_extensions = WPO_Image_Utils::get_allowed_extensions();
128 163
129 - if (empty($smush_stats)) {
130 - _e('The file was either compressed using another tool or marked as compressed', 'wp-optimize');
131 - return;
164 + $compressed = get_post_meta($attachment_id, '_wpo-smush-complete', true) ? true : false;
165 + $has_backup = get_post_meta($attachment_id, '_wpo-original-file', true) ? true : false;
166 +
167 + $smush_info = get_post_meta($attachment_id, '_wpo-smush-info', true);
168 + $smush_stats = get_post_meta($attachment_id, '_wpo-smush-stats', true);
169 + $marked = get_post_meta($attachment_id, '_wpo-smush-marked');
170 +
171 + $extract = array(
172 + 'blog_id' => get_current_blog_id(),
173 + 'post_id' => $attachment_id,
174 + 'smush_info_display'=> $compressed ? "display:inline-block;" : "display:none;",
175 + 'smush_display' => $compressed ? "display:none;" : "display:inline-block;",
176 + 'before_smush_sep' => !$compressed ? '<span class="wpo-action-separator"> | </span>' : '',
177 + 'restore_action' => $has_backup && $compressed ? "display:block;" : "display:none;",
178 + 'smush_mark' => !$compressed && !$marked ? "display:inline-block;" : "display:none;",
179 + 'smush_unmark' => $marked ? "display:inline-block;" : "display:none;",
180 + 'smush_info' => $smush_info ?: ' ',
181 + 'smush_details' => '',
182 + 'restore_tooltip' => $this->get_restore_image_tooltip_text(),
183 + 'smush_marked' => $marked,
184 + );
185 +
186 + if (!empty($smush_stats['sizes-info'])) {
187 + $extract['smush_details'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info']));
132 188 }
133 189
134 - $original_size = $smush_stats['original-size'];
135 - $smushed_size = $smush_stats['smushed-size'];
190 + $extract['compressed_by_another_plugin'] = $this->is_image_compressed_by_another_plugin($attachment_id);
136 191
137 - if (0 == $original_size) {
138 - $info = sprintf(__('The file was compressed to %s using WP-Optimize', 'wp-optimize'), WP_Optimize()->format_size($smushed_size));
192 + $output = '';
193 +
194 + if (WPO_Image_Utils::is_supported_extension($ext, $allowed_extensions)) {
195 + $output .= WP_Optimize()->include_template('admin-medialibrary-smush-column.php', true, $extract);
139 196 } else {
140 - $saved = round((($original_size - $smushed_size) / $original_size * 100), 2);
141 - $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($smushed_size), $saved);
197 + $message = __('Compressing this file type extension is not supported', 'wp-optimize');
198 + $output .= sprintf("<p>%s</p>", esc_html($message));
199 +
142 200 }
143 201
144 - echo htmlentities($info);
202 + if (WPO_Image_Utils::is_supported_extension($ext, array_diff($allowed_extensions, array('gif'))) && file_exists($file) && !file_exists($file . '.webp')) {
203 + if (WPO_WebP_Utils::can_do_webp_conversion()) {
204 + $link_text = __('Convert to WebP', 'wp-optimize');
205 + $output .= '<span class="wpo-action-separator"> | </span>';
206 + $output .= sprintf('<a href="#" class="convert-to-webp" data-attachment-id="%d">%s</a><br>', esc_attr($attachment_id), esc_html($link_text));
207 + }
208 + }
145 209
146 - // Display additional information about resized images.
147 - if (!empty($smush_stats['sizes-info'])) {
148 - WP_Optimize()->include_template('images/smush-details.php', false, array('sizes_info' => $smush_stats['sizes-info']));
149 - }
210 + return $output;
150 211 }
151 212
152 213 /**
153 214 * The Task Manager AJAX handler
@@ -153,21 +214,25 @@
153 214 * The Task Manager AJAX handler
154 215 */
155 216 public function updraft_smush_ajax() {
156 217
157 - $nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
218 + $nonce = TeamUpdraft\WP_Optimize\Includes\Fragments\verify_nonce('nonce', 'updraft-task-manager-ajax-nonce');
219 + $subaction = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal('request', 'subaction', null, 'sanitize_key');
220 + $data = TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal('request', 'data');
158 221
159 - if (!wp_verify_nonce($nonce, 'updraft-task-manager-ajax-nonce') || empty($_REQUEST['subaction']))
222 + if (empty($nonce) || empty($subaction)) {
160 223 die('Security check failed');
224 + }
161 225
162 - $subaction = $_REQUEST['subaction'];
226 + if (!WP_Optimize()->current_user_can()) {
227 + die('You are not allowed to run this command.');
228 + }
163 229
164 230 $allowed_commands = Updraft_Smush_Manager_Commands::get_allowed_ajax_commands();
165 231
166 232 if (in_array($subaction, $allowed_commands)) {
167 233
168 - if (isset($_REQUEST['data'])) {
169 - $data = $_REQUEST['data'];
234 + if ($data) {
170 235 $results = call_user_func(array($this->commands, $subaction), $data);
171 236 } else {
172 237 $results = call_user_func(array($this->commands, $subaction));
173 238 }
@@ -181,13 +246,13 @@
181 246 'error_data' => $results->get_error_data(),
182 247 );
183 248 }
184 249
185 - echo json_encode($results);
250 + echo wp_json_encode($results);
186 251 } else {
187 - echo json_encode(array('error' => 'No such command found'));
252 + echo wp_json_encode(array('error' => 'No such command found'));
188 253 }
189 - die;
254 + die();
190 255 }
191 256
192 257 /**
193 258 * Creates a task to auto compress an image on upload
@@ -196,66 +261,78 @@
196 261 */
197 262 public function autosmush_create_task($post_id) {
198 263
199 264 $post = get_post($post_id);
265 + $file = get_attached_file($post_id);
266 + $ext = WPO_Image_Utils::get_extension($file);
267 + $allowed_extensions = WPO_Image_Utils::get_allowed_extensions();
200 268
201 - if (!$this->options->get_option('autosmush', false))
269 + if(!in_array($ext, $allowed_extensions)) return;
270 +
271 + if (!$this->options->get_option('autosmush'))
202 272 return;
203 273
204 - if (!'image' == substr($post->post_mime_type, 0, 5))
274 + if ('image' !== substr($post->post_mime_type, 0, 5))
205 275 return;
206 276
207 277 if ($this->task_exists($post_id))
208 278 return;
209 -
210 - $options = array(
211 - 'attachment_id' => $post_id,
212 - 'blog_id' => get_current_blog_id(),
213 - 'image_quality' => $this->options->get_option('image_quality', 96),
214 - 'keep_original' => $this->options->get_option('back_up_original', true),
215 - 'preserve_exif' => $this->options->get_option('preserve_exif', true),
216 - 'lossy_compression' => $this->options->get_option('lossy_compression', false)
217 - );
218 279
219 - if (filesize(get_attached_file($post_id)) > 5242880) {
220 - $options['request_timeout'] = 180;
280 + $task_options = $this->get_smush_options();
281 + $task_options = array_merge($task_options, array('attachment_id' => $post_id, 'blog_id' => get_current_blog_id()));
282 +
283 + if (filesize($file) > 5242880) {
284 + $task_options['request_timeout'] = 180;
221 285 }
222 286
223 287 $server = $this->options->get_option('compression_server', $this->webservice);
224 288 $task_name = $this->get_associated_task($server);
225 289
226 - $description = "$task_name with attachment ID : ".$post_id.", autocreated on : ".date("F d, Y h:i:s", time());
227 - $task = call_user_func(array($task_name, 'create_task'), 'smush', $description, $options, $task_name);
228 -
229 - if ($task) $task->add_logger($this->logger);
290 + $blog_info = is_multisite() ? ', blog ID : '.get_current_blog_id() : '';
291 + $description = "$task_name with attachment ID : ".$post_id . $blog_info .", auto created on : ".gmdate("F d, Y h:i:s", time());
292 +
293 + $task = call_user_func(array($task_name, 'create_task'), 'smush', $description, $task_options, $task_name);
294 +
295 + if ($task) $this->set_task_logger($task);
230 296 $this->log($description);
231 297
232 - if (!wp_next_scheduled('autosmush_process_queue')) {
233 - wp_schedule_single_event(time() + 300, 'autosmush_process_queue');
298 + if (!wp_next_scheduled('process_smush_tasks')) {
299 + wp_schedule_single_event(time() + 300, 'process_smush_tasks');
234 300 }
235 301 }
236 302
237 303 /**
238 - * Process the autosmush queue and sets up a cron job if needed
239 - * for future processing
304 + * Processes the smush tasks in the queue, then cleans up the completed tasks.
305 + *
306 + * Before processing the queue, it first schedules a cron job to re-initiate the process after a certain
307 + * interval, ensuring that the process will be completed later in case the current processing fails
308 + * or is interrupted. This method can be invoked directly or scheduled as a cron job.
240 309 */
241 - public function autosmush_process_queue() {
242 -
243 - if (!wp_next_scheduled('autosmush_process_queue') && !$this->is_queue_processed()) {
244 - wp_schedule_single_event(time() + 600, 'autosmush_process_queue');
310 + public function process_smush_tasks() {
311 + /*
312 + * Only add log header when called as a cron job, assuming the log header is already added by the caller
313 + * when called directly. This is to avoid duplicate log headers in the log file.
314 + */
315 + if (defined('DOING_CRON') && DOING_CRON) {
316 + $this->write_log_header();
245 317 }
246 318
247 - $this->write_log_header();
248 - $this->clear_cached_data();
249 - $this->process_queue('smush');
250 -
319 + // If there are no pending tasks, nothing to process. In that case, attempt to clean up old tasks and return
251 320 if ($this->is_queue_processed()) {
252 321 $this->clean_up_old_tasks('smush');
322 + return;
253 323 }
254 324
325 + if (!wp_next_scheduled('process_smush_tasks')) {
326 + wp_schedule_single_event(time() + 600, 'process_smush_tasks');
327 + }
328 +
329 + // Process the queue
330 + $this->clear_cached_data();
331 + $this->process_queue('smush');
332 + $this->clean_up_old_tasks('smush');
255 333 }
256 334
257 -
258 335 /**
259 336 * Process the compression of a single image
260 337 *
261 338 * @param int $image - ID of image
@@ -261,16 +338,17 @@
261 338 * @param int $image - ID of image
262 339 * @param array $options - options to use
263 340 * @param string $server - the server to process with
264 341 *
265 - * @return boolean - Status of the task
342 + * @return bool | WP_Error - Status of the task
266 343 */
267 344 public function compress_single_image($image, $options, $server) {
268 345 $task_name = $this->get_associated_task($server);
269 - $description = "$task_name - attachment ID : ". $image. ", started on : ". date("F d, Y h:i:s", time());
346 + $blog_info = is_multisite() ? ', blog ID : '.get_current_blog_id() : '';
347 + $description = "$task_name - attachment ID : ". $image . $blog_info. ", started on : ". gmdate("F d, Y h:i:s", time());
270 348
271 349 $task = call_user_func(array($task_name, 'create_task'), 'smush', $description, $options, $task_name);
272 - $task->add_logger($this->logger);
350 + if ($task) $this->set_task_logger($task);
273 351 $this->clear_cached_data();
274 352
275 353 if (!wp_next_scheduled('prune_smush_logs')) {
276 354 wp_schedule_single_event(time() + 7200, 'prune_smush_logs');
@@ -289,9 +367,9 @@
289 367 */
290 368 public function restore_single_image($image_id, $blog_id) {
291 369
292 370 $switched_blog = false;
293 - if (is_multisite() && current_user_can('manage_network_options')) {
371 + if (is_multisite() && WP_Optimize()->current_user_can('manage_network_options')) {
294 372 switch_to_blog($blog_id);
295 373 $switched_blog = true;
296 374 } elseif (is_multisite() && get_current_blog_id() != $blog_id) {
297 375 return new WP_Error('restore_backup_wrong_blog_id', __('The blog ID provided does not match the current blog.', 'wp-optimize'));
@@ -299,15 +377,23 @@
299 377
300 378 $error = false;
301 379
302 380 $image_path = get_attached_file($image_id);
303 - $backup_path = get_post_meta($image_id, 'original-file', true);
304 -
381 + $backup_path = get_post_meta($image_id, '_wpo-original-file', true);
382 + $uploads_dir = wp_upload_dir();
383 + $uploads_basedir = realpath($uploads_dir['basedir']);
384 +
385 + if (false === $uploads_basedir) {
386 + if ($switched_blog) {
387 + restore_current_blog();
388 + }
389 + return new WP_Error('restore_backup_issue', __('The uploads base directory is not correct.', 'wp-optimize'));
390 + }
391 +
392 + $uploads_basedir = trailingslashit($uploads_basedir);
393 +
305 394 // If the file doesn't exist, check if it's relative
306 395 if (!is_file($backup_path)) {
307 - $uploads_dir = wp_upload_dir();
308 - $uploads_basedir = trailingslashit($uploads_dir['basedir']);
309 -
310 396 if (is_file($uploads_basedir . $backup_path)) {
311 397 $backup_path = $uploads_basedir . $backup_path;
312 398 }
313 399 }
@@ -336,17 +422,27 @@
336 422 $backup_path = $uploads_basedir . $backup_path;
337 423 }
338 424 }
339 425
426 + $backup_path = realpath($backup_path);
427 + if (!$backup_path || 0 !== strpos(trailingslashit(dirname($backup_path)), $uploads_basedir)) {
428 + if ($switched_blog) {
429 + restore_current_blog();
430 + }
431 + return new WP_Error('restore_failed', __('The backup file path seems suspicious, and could not be deleted.', 'wp-optimize'));
432 + }
433 +
434 +
340 435 if (!is_file($backup_path)) {
341 436 // Delete information about backup.
342 - delete_post_meta($image_id, 'original-file');
437 + delete_post_meta($image_id, '_wpo-original-file');
343 438 $error = new WP_Error('restore_backup_not_found', __('The backup was not found; it may have been deleted or was already restored', 'wp-optimize'));
344 - } elseif (!is_writable($image_path)) {
345 - $error = new WP_Error('restore_failed', __('The destination could not be written to.', 'wp-optimize').' '.__("Please check your folder's permissions", 'wp-optimize'));
439 + } elseif (!wp_is_writable($image_path)) {
440 + $error = new WP_Error('restore_failed', __('The destination could not be written to.', 'wp-optimize').' '.__("Please check your folder's permissions", 'wp-optimize'));
346 441 } elseif (!copy($backup_path, $image_path)) {
347 - $error = new WP_Error('restore_failed', __('The file could not be copied; check your PHP error logs for details', 'wp-optimize'));
348 - } elseif (!unlink($backup_path)) {
442 + $error = new WP_Error('restore_failed', __('The file could not be copied; check your PHP error logs for details', 'wp-optimize'));
443 + } elseif (!WP_Optimize_Utils::wp_delete_file($backup_path)) {
444 + // translators: %s is the backup file path
349 445 $error = new WP_Error('restore_failed', sprintf(__('The backup file %s could not be deleted.', 'wp-optimize'), $backup_path));
350 446 }
351 447
352 448 if (!$error) {
@@ -351,12 +447,12 @@
351 447
352 448 if (!$error) {
353 449 // if backup image deleted successfully
354 450 // then delete from attachment meta associated smush data
355 - delete_post_meta($image_id, 'smush-complete');
356 - delete_post_meta($image_id, 'smush-stats');
357 - delete_post_meta($image_id, 'original-file');
358 - delete_post_meta($image_id, 'smush-info');
451 + delete_post_meta($image_id, '_wpo-smush-complete');
452 + delete_post_meta($image_id, '_wpo-smush-stats');
453 + delete_post_meta($image_id, '_wpo-original-file');
454 + delete_post_meta($image_id, '_wpo-smush-info');
359 455 }
360 456
361 457 if ($switched_blog) {
362 458 restore_current_blog();
@@ -378,9 +474,9 @@
378 474 *
379 475 * @param bool $restore_backup if true then restore images from backup otherwise just delete meta.
380 476 * @param int $blog_id blog id.
381 477 * @param int $images_limit how many images process per time.
382 - * @param bool $delete_only_backups_meta meta fields will deleted only for images those will restored from backup.
478 + * @param bool $delete_only_backups_meta meta fields will be deleted only for images those will be restored from backup.
383 479 *
384 480 * @return array ['completed' => (bool), 'message' => (string), 'error' => (string)]
385 481 */
386 482 public function bulk_restore_compressed_images($restore_backup, $blog_id = 1, $images_limit = 100, $delete_only_backups_meta = false) {
@@ -392,8 +488,9 @@
392 488
393 489 $result = array(
394 490 'completed' => false,
395 491 'message' => '',
492 + 'smushed_images_count' => 0,
396 493 );
397 494
398 495 $processed = 0;
399 496
@@ -398,9 +495,9 @@
398 495 $processed = 0;
399 496
400 497 if ($restore_backup) {
401 498 // get post ids those have backup meta field.
402 - $image_ids = $wpdb->get_results($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = 'original-file' LIMIT %d;", $images_limit), ARRAY_A);
499 + $image_ids = $wpdb->get_results($wpdb->prepare("SELECT post_id FROM `{$wpdb->postmeta}` WHERE meta_key = '_wpo-original-file' LIMIT %d;", $images_limit), ARRAY_A);
403 500
404 501 if (!empty($image_ids)) {
405 502 // run restore function for each found image.
406 503 foreach ($image_ids as $image) {
@@ -405,9 +502,9 @@
405 502 // run restore function for each found image.
406 503 foreach ($image_ids as $image) {
407 504 $restore_result = $this->restore_single_image($image['post_id'], $blog_id);
408 505
409 - // if we get an error then we stop the work, except situation when "backup already restored'.
506 + // if we get an error then we stop the work, except situation when "backup already restored".
410 507 if (is_wp_error($restore_result) && 'restore_backup_not_found' != $restore_result->get_error_code()) {
411 508 // we need to stop the work as we haven't restored the backup.
412 509 $result['error'] = $restore_result->get_error_message();
413 510 $this->options->delete_option('smush_images_restored');
@@ -420,9 +517,9 @@
420 517
421 518 $images_count = count($image_ids);
422 519
423 520 // if all images processed then set flag completed to true.
424 - if ($processed == $images_count && $images_count < $images_limit) {
521 + if ($processed === $images_count && $images_count < $images_limit) {
425 522 $this->options->delete_option('smush_images_restored');
426 523 $result['completed'] = true;
427 524 } else {
428 525 // save into options total processed count.
@@ -429,10 +526,12 @@
429 526 $processed += $this->options->get_option('smush_images_restored', 0);
430 527 $this->options->update_option('smush_images_restored', $processed);
431 528
432 529 if (is_multisite()) {
433 - $result['message'] = sprintf(__('%s compressed images were restored from their backup for the site %s', 'wp-optimize'), $processed, get_site_url($blog_id));
530 + // translators: %1$s is the number of restored images, %2$s is the site url.
531 + $result['message'] = sprintf(__('%1$s compressed images were restored from their backup for the site %2$s', 'wp-optimize'), $processed, get_site_url($blog_id));
434 532 } else {
533 + // translators: %s is the number of restored images.
435 534 $result['message'] = sprintf(__('%s compressed images were restored from their backup', 'wp-optimize'), $processed);
436 535 }
437 536 }
438 537
@@ -441,16 +540,35 @@
441 540 $result['completed'] = true;
442 541 }
443 542
444 543 if ($result['completed']) {
544 +
545 + $smushed_images_count = $wpdb->get_var("SELECT COUNT(*) FROM `{$wpdb->postmeta}` WHERE meta_key='_wpo-smush-complete' AND meta_value=1");
546 + $result['smushed_images_count'] = $smushed_images_count;
547 +
445 548 if ($delete_only_backups_meta) {
446 549 if (is_multisite()) {
447 - $result['message'] = sprintf(__('All the compressed images for the site %s were successfully restored.', 'wp-optimize'), get_site_url($blog_id));
550 + if ($smushed_images_count > 0) {
551 + // translators: %s is the site url
552 + $result['message'] = sprintf(__('All the compressed images for site %s with backup copies of their original files were successfully restored.', 'wp-optimize'), get_site_url($blog_id));
553 + // translators: %s is the number of images
554 + $result['message'] .= ' '.sprintf(_n('Unable to restore %s image without backup files.', 'Unable to restore %s images without backup files.', $smushed_images_count, 'wp-optimize'), $smushed_images_count);
555 + } else {
556 + // translators: %s is the site url
557 + $result['message'] = sprintf(__('All the compressed images for the site %s were successfully restored.', 'wp-optimize'), get_site_url($blog_id));
558 + }
448 559 } else {
449 - $result['message'] = __('All the compressed images were successfully restored.', 'wp-optimize');
560 + if ($smushed_images_count > 0) {
561 + $result['message'] = __('All the compressed images with backup copies of their original files were successfully restored.', 'wp-optimize');
562 + // translators: %s is the number of images
563 + $result['message'] .= ' '.sprintf(_n('Unable to restore %s image without backup files.', 'Unable to restore %s images without backup files.', $smushed_images_count, 'wp-optimize'), $smushed_images_count);
564 + } else {
565 + $result['message'] = __('All the compressed images were successfully restored.', 'wp-optimize');
566 + }
450 567 }
451 568 } else {
452 569 if (is_multisite()) {
570 + // translators: %s is the site url
453 571 $result['message'] = sprintf(__('All the compressed images for the site %s were successfully marked as uncompressed.', 'wp-optimize'), get_site_url($blog_id));
454 572 } else {
455 573 $result['message'] = __('All the compressed images were successfully marked as uncompressed.', 'wp-optimize');
456 574 }
@@ -457,11 +575,11 @@
457 575 }
458 576
459 577 // clear all metas for smushed images after work completed.
460 578 // if $delete_only_backup_meta set to true then all meta fields was deleted in restore_single_image()
461 - // and we don't need delete metas for other images.
579 + // and we don't need to delete metas for other images.
462 580 if (!$delete_only_backups_meta) {
463 - $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key IN ('smush-complete', 'smush-stats', 'original-file', 'smush-info');");
581 + $wpdb->query("DELETE FROM `{$wpdb->postmeta}` WHERE meta_key IN ('_wpo-smush-complete', '_wpo-smush-stats', '_wpo-original-file', '_wpo-smush-info');");
464 582 }
465 583 }
466 584
467 585 if (is_multisite()) {
@@ -477,9 +595,9 @@
477 595 * @param array $images - the array of images to process
478 596 * @return bool - true if processing complete
479 597 */
480 598 public function process_bulk_smush($images = array()) {
481 -
599 +
482 600 // Get a list of pending tasks so we can exclude those
483 601 $pending_tasks = $this->get_pending_tasks();
484 602 $queued_images = array();
485 603
@@ -492,37 +610,25 @@
492 610 'blog_id' => $task->get_option('blog_id')
493 611 );
494 612 }
495 613 }
496 -
614 + $default_task_options = $this->get_smush_options();
497 615 foreach ($images as $image) {
498 616 // Skip if already in the queue
499 617 if (in_array($image, $queued_images)) continue;
500 618
501 - $options = array(
502 - 'attachment_id' => intval($image['attachment_id']),
503 - 'blog_id' => intval($image['blog_id']),
504 - 'image_quality' => $this->options->get_option('image_quality', 85),
505 - 'keep_original' => $this->options->get_option('back_up_original', true),
506 - 'preserve_exif' => $this->options->get_option('preserve_exif', true),
507 - 'lossy_compression' => $this->options->get_option('lossy_compression', false)
508 - );
509 -
619 + $task_options = array_merge($default_task_options, array('attachment_id' => intval($image['attachment_id']), 'blog_id' => intval($image['blog_id'])));
510 620 $server = $this->options->get_option('compression_server', $this->webservice);
511 621 $task_name = $this->get_associated_task($server);
512 622
513 - $description = "$task_name - Attachment ID : ". intval($image['attachment_id']) . ", Started on : ". date("F d, Y h:i:s", time());
514 - $task = call_user_func(array($task_name, 'create_task'), 'smush', $description, $options, $task_name);
515 - $task->add_logger($this->logger);
623 + $blog_info = is_multisite() ? ', Blog ID : '.intval($image['blog_id']) : '';
624 + $description = "$task_name - Attachment ID : ". intval($image['attachment_id']) . $blog_info . ", Started on : ". gmdate("F d, Y h:i:s", time());
625 + $task = call_user_func(array($task_name, 'create_task'), 'smush', $description, $task_options, $task_name);
626 + if ($task) $this->set_task_logger($task);
516 627 }
517 628
518 - $this->clear_cached_data();
519 - $this->process_queue('smush');
629 + $this->process_smush_tasks();
520 630
521 - if ($this->is_queue_processed()) {
522 - $this->clean_up_old_tasks('smush');
523 - }
524 -
525 631 if (!wp_next_scheduled('prune_smush_logs')) {
526 632 wp_schedule_single_event(time() + 7200, 'prune_smush_logs');
527 633 }
528 634
@@ -550,9 +656,9 @@
550 656 return $online;
551 657 }
552 658
553 659 /**
554 - * Checks if the queue for smushing is compleete
660 + * Checks if the queue for smushing is complete
555 661 *
556 662 * @return bool - true if processed, false otherwise
557 663 */
558 664 public function is_queue_processed() {
@@ -557,14 +663,10 @@
557 663 */
558 664 public function is_queue_processed() {
559 665
560 666 $active = $this->get_pending_tasks();
561 - if ($active && 0 != count($active))
562 - return false;
667 + if ($active && 0 != count($active)) return false;
563 668
564 - if (false !== get_option('updraft_semaphore_smush'))
565 - return false;
566 -
567 669 return true;
568 670 }
569 671
570 672 /**
@@ -574,19 +676,19 @@
574 676 */
575 677 public function record_stats($task) {
576 678
577 679 $attachment_id = $task->get_option('attachment_id');
578 - $completed_task_count = $this->options->get_option('completed_task_count', false);
680 + $completed_task_count = $this->options->get_option('completed_task_count');
579 681 $failed_task_count = $this->options->get_option('failed_task_count', 0);
580 - $total_bytes_saved = $this->options->get_option('total_bytes_saved', false);
682 + $total_bytes_saved = $this->options->get_option('total_bytes_saved');
581 683 $total_percent_saved = $this->options->get_option('total_percent_saved', 0);
582 684
583 - if ('ud_task_failed' == current_action()) {
685 + if ('ud_task_failed' === current_action()) {
584 686 $this->options->update_option('failed_task_count', ++$failed_task_count);
585 687 return;
586 688 }
587 689
588 - if (false === $completed_task_count) {
690 + if (empty($completed_task_count)) {
589 691 $completed_task_count = $total_bytes_saved = 0;
590 692 }
591 693
592 694 if (!$total_bytes_saved) {
@@ -594,12 +696,12 @@
594 696 }
595 697
596 698 if (is_multisite()) {
597 699 switch_to_blog($task->get_option('blog_id', 1));
598 - $stats = get_post_meta($attachment_id, 'smush-stats', true);
700 + $stats = get_post_meta($attachment_id, '_wpo-smush-stats', true);
599 701 restore_current_blog();
600 702 } else {
601 - $stats = get_post_meta($attachment_id, 'smush-stats', true);
703 + $stats = get_post_meta($attachment_id, '_wpo-smush-stats', true);
602 704 }
603 705
604 706 if (isset($stats['sizes-info'])) {
605 707
@@ -612,11 +714,11 @@
612 714 }
613 715
614 716 $percent = round((($original_size - $compressed_size) / $original_size * 100), 2);
615 717 } else {
616 - $original_size = isset($stats['original-size']) ? $stats['original-size'] : 0;
617 - $compressed_size = isset($stats['smushed-size']) ? $stats['smushed-size'] : 0;
618 - $percent = isset($stats['savings-percent']) ? $stats['savings-percent'] : 0;
718 + $original_size = $stats['original-size'] ?? 0;
719 + $compressed_size = $stats['smushed-size'] ?? 0;
720 + $percent = $stats['savings-percent'] ?? 0;
619 721 }
620 722
621 723 $saved = $original_size - $compressed_size;
622 724 $completed_task_count++;
@@ -629,29 +731,8 @@
629 731 $this->options->update_option('total_percent_saved', $total_percent_saved);
630 732 }
631 733
632 734 /**
633 - * Cleans out all complete + failed tasks from the DB.
634 - *
635 - * @param String $type type of the task
636 - * @return bool - true if processing complete
637 - */
638 - public function clean_up_old_tasks($type) {
639 - $completed_tasks = $this->get_tasks('all', $type);
640 -
641 - if (!$completed_tasks) return false;
642 -
643 - $this->log(sprintf('Cleaning up tasks of type (%s). A total of %d tasks will be deleted.', $type, count($completed_tasks)));
644 -
645 - foreach ($completed_tasks as $task) {
646 - $task->delete_meta();
647 - $task->delete();
648 - }
649 -
650 - return true;
651 - }
652 -
653 - /**
654 735 * Get current smush options.
655 736 *
656 737 * @return array
657 738 */
@@ -659,17 +740,18 @@
659 740 static $smush_options = array();
660 741 if (empty($smush_options)) {
661 742 $smush_options = array(
662 743 'compression_server' => $this->options->get_option('compression_server', $this->get_default_webservice()),
663 - 'image_quality' => $this->options->get_option('image_quality', 'very_good'),
664 - 'lossy_compression' => $this->options->get_option('lossy_compression', false),
744 + 'image_quality' => $this->options->get_option('image_quality', 92),
745 + 'lossy_compression' => $this->options->get_option('lossy_compression'),
746 + 'keep_original' => $this->options->get_option('back_up_original', true),//repeated below
665 747 'back_up_original' => $this->options->get_option('back_up_original', true),
666 748 'back_up_delete_after' => $this->options->get_option('back_up_delete_after', true),
667 749 'back_up_delete_after_days' => $this->options->get_option('back_up_delete_after_days', 50),
668 750 'preserve_exif' => $this->options->get_option('preserve_exif', false),
669 - 'autosmush' => $this->options->get_option('autosmush', false),
670 - 'show_smush_metabox' => $this->options->get_option('show_smush_metabox', 'show') == 'show' ? true : false,
671 - 'webp_conversion' => $this->options->get_option('webp_conversion', false)
751 + 'autosmush' => $this->options->get_option('autosmush'),
752 + 'show_smush_metabox' => $this->options->get_option('show_smush_metabox', 'show') === 'show',
753 + 'webp_conversion' => $this->options->get_option('webp_conversion')
672 754 );
673 755 }
674 756 return $smush_options;
675 757 }
@@ -674,20 +756,29 @@
674 756 return $smush_options;
675 757 }
676 758
677 759 /**
678 - * Updates global smush options
760 + * Update smush options
761 + * Only options whose values differ from the stored values are updated.
679 762 *
680 - * @param array $options - sent in via AJAX
681 - * @return bool - status of the update
763 + * @param array $options Associative array of option names and values sent in via AJAX.
764 + * @return bool True if all updates succeeded or no changes were required,
765 + * false if at least one option update failed.
682 766 */
683 767 public function update_smush_options($options) {
684 -
768 + $success = true;
685 769 foreach ($options as $option => $value) {
686 - $this->options->update_option($option, $value);
770 + // Here we only store string, array as string after serialization, boolean, and integer values which will be stored as strings (LONGTEXT field type)
771 + // So loose comparison is fine, strict comparison results to buggy behavior
772 + if ($this->options->get_option($option) == $value) {
773 + continue;
774 + }
775 +
776 + if (!$this->options->update_option($option, $value)) {
777 + $success = false;
778 + }
687 779 }
688 -
689 - return true;
780 + return $success;
690 781 }
691 782
692 783 /**
693 784 * Clears smush related stats
@@ -708,26 +799,40 @@
708 799 *
709 800 * @return array - translations used in JS
710 801 */
711 802 public function smush_js_translations() {
803 + $resmushit_article_link = WP_Optimize()->wp_optimize_url('https://resmush.it/api/', __('resmushIt', 'wp-optimize'), '', '', true);
804 +
712 805 return apply_filters('updraft_smush_js_translations', array(
713 806 'all_images_compressed' => __('No uncompressed images were found.', 'wp-optimize'),
714 - 'error_unexpected_response' => __('An unexpected response was received from the server. More information has been logged in the browser console.', 'wp-optimize'),
807 + 'error_unexpected_response' => __('An unexpected response was received from the server.', 'wp-optimize') . ' ' . __('More information has been logged in the browser console.', 'wp-optimize'),
715 808 'compress_single_image_dialog' => __('Please wait: compressing the selected image.', 'wp-optimize'),
716 809 'error_try_again_later' => __('Please try again later.', 'wp-optimize'),
717 810 'server_check' => __('Connecting to the Smush API server, please wait', 'wp-optimize'),
718 811 'please_wait' => __('Please wait while the request is being processed', 'wp-optimize'),
719 - 'server_error' => __('There was an error connecting to the image compression server. This could mean either the server is temporarily unavailable or there are connectivity issues with your internet connection. Please try later.', 'wp-optimize'),
812 + 'server_error' => __('There was an error connecting to the image compression server.', 'wp-optimize') .
813 + '<br>' . __('This could mean either the server is temporarily unavailable or there are connectivity issues with your internet connection.', 'wp-optimize') . ' ' .
814 + // translators: %s is a link
815 + '<i>' . sprintf(__('(Also ensure IPs listed at the bottom of this %s page are whitelisted by your webserver).', 'wp-optimize'), $resmushit_article_link) . '</i>' .
816 + '<br>' . __('Please try later.', 'wp-optimize'),
817 + 'exceeded_max_filesize' => __('This image is too large to be optimized — it exceeds the provider\'s size limit', 'wp-optimize'),
720 818 'please_select_images' => __('Please select the images you want compressed from the "Uncompressed images" panel first', 'wp-optimize'),
721 819 'please_updating_images_info' => __('Please wait: updating information about the selected image.', 'wp-optimize'),
722 820 'please_select_compressed_images' => __('Please select the images you want to mark as already compressed from the "Uncompressed images" panel first', 'wp-optimize'),
723 821 'view_image' => __('View Image', 'wp-optimize'),
724 - 'delete_image_backup_confirm' => __('Do you really want to delete all backup images now? This action is irreversible.', 'wp-optimize'),
725 - 'mark_all_images_uncompressed' => __('Do you really want to mark all the images as uncompressed? This action is irreversible.', 'wp-optimize'),
822 + 'delete_image_backup_confirm' => __('Do you really want to delete all backup images now?', 'wp-optimize') . ' ' . __('This action is irreversible.', 'wp-optimize'),
823 + 'mark_all_images_uncompressed' => __('Do you really want to mark all the images as uncompressed?', 'wp-optimize') . ' ' . __('This action is irreversible.', 'wp-optimize'),
726 824 'restore_images_from_backup' => __('Do you want to restore the original images from the backup (where they exist?)', 'wp-optimize'),
727 825 'restore_all_compressed_images' => __('Do you really want to restore all the compressed images?', 'wp-optimize'),
826 + 'webp_conversion_tool_error' => __('No WebP conversion tools are available on your web-server.', 'wp-optimize'),
827 + 'webp_conversion_tool_how_to' => __('How to get the WebP conversion tools to work?', 'wp-optimize'),
728 828 'more' => __('More', 'wp-optimize'),
729 829 'less' => __('Less', 'wp-optimize'),
830 + 'converting_to_webp' => __('Converting image to WebP format, please wait', 'wp-optimize'),
831 + 'compress_image' => __('Compress Image', 'wp-optimize'),
832 + 'compress' => __('Compress', 'wp-optimize'),
833 + 'cancel' => __('Cancel', 'wp-optimize'),
834 + 'close' => __('Close', 'wp-optimize'),
730 835 ));
731 836 }
732 837
733 838 /**
@@ -752,32 +857,36 @@
752 857 * @param WP_Post $post - a post object
753 858 */
754 859 public function render_smush_metabox($post) {
755 860
756 - $compressed = get_post_meta($post->ID, 'smush-complete', true) ? true : false;
757 - $has_backup = get_post_meta($post->ID, 'original-file', true) ? true : false;
861 + $compressed = (bool) get_post_meta($post->ID, '_wpo-smush-complete', true);
862 + $has_backup = (bool) get_post_meta($post->ID, '_wpo-original-file', true);
758 863
759 - $smush_info = get_post_meta($post->ID, 'smush-info', true);
760 - $smush_stats = get_post_meta($post->ID, 'smush-stats', true);
761 - $marked = get_post_meta($post->ID, 'smush-marked', false);
864 + $smush_info = get_post_meta($post->ID, '_wpo-smush-info', true);
865 + $smush_stats = get_post_meta($post->ID, '_wpo-smush-stats', true);
866 + $marked = get_post_meta($post->ID, '_wpo-smush-marked');
762 867
763 868 $options = Updraft_Smush_Manager()->get_smush_options();
764 -
869 +
765 870 $file = get_attached_file($post->ID);
871 + $ext = WPO_Image_Utils::get_extension($file);
872 + $allowed_extensions = WPO_Image_Utils::get_allowed_extensions();
766 873 $file_size = ($file && is_file($file)) ? filesize($file) : 0;
767 874
768 875 $extract = array(
769 876 'post_id' => $post->ID,
770 - 'smush_display' => $compressed ? "style='display:none;'" : "style='display:block;'",
771 - 'restore_display' => $compressed ? "style='display:block;'" : "style='display:none;'",
772 - 'restore_action' => $has_backup ? "style='display:block;'" : "style='display:none;'",
773 - 'smush_mark' => !$compressed && !$marked ? "style='display:block;'" : "style='display:none;'",
774 - 'smush_unmark' => $marked ? "style='display:block;'" : "style='display:none;'",
775 - 'smush_info' => $smush_info ? $smush_info : ' ',
877 + 'smush_display' => $compressed ? "display:none;" : "display:block;",
878 + 'restore_display' => $compressed ? "display:block;" : "display:none;",
879 + 'restore_action' => $has_backup ? "display:block;" : "display:none;",
880 + 'smush_mark' => !$compressed && !$marked ? "display:block;" : "display:none;",
881 + 'smush_unmark' => $marked ? "display:block;" : "display:none;",
882 + 'smush_info' => $smush_info ?: ' ',
776 883 'file_size' => $file_size,
777 884 'smush_options' => $options,
778 - 'custom' => 100 == $options['image_quality'] || 90 == $options['image_quality'] ? false : true,
885 + 'custom' => 90 >= $options['image_quality'] && 65 <= $options['image_quality'],
779 886 'smush_details' => '',
887 + 'restore_tooltip' => $this->get_restore_image_tooltip_text(),
888 + 'smush_marked' => $marked,
780 889 );
781 890
782 891 if (!empty($smush_stats['sizes-info'])) {
783 892 $extract['smush_details'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info']));
@@ -782,11 +891,28 @@
782 891 if (!empty($smush_stats['sizes-info'])) {
783 892 $extract['smush_details'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info']));
784 893 }
785 894
895 + $extract['smush_settings_form'] = WP_Optimize()->include_template('admin-metabox-smush-settings.php', true, $extract);
786 896 $extract['compressed_by_another_plugin'] = $this->is_image_compressed_by_another_plugin($post->ID);
897 + if (WPO_Image_Utils::is_supported_extension($ext, $allowed_extensions)) {
898 + WP_Optimize()->include_template('admin-metabox-smush.php', false, $extract);
899 + } else {
900 + printf("<p>%s</p>", esc_html__('Compressing this file type extension is not supported', 'wp-optimize'));
901 + }
902 + }
787 903
788 - WP_Optimize()->include_template('admin-metabox-smush.php', false, $extract);
904 + /**
905 + * Get text for restore image tooltip.
906 + *
907 + * @return string
908 + */
909 + private function get_restore_image_tooltip_text() {
910 + $text = __('Only the original image will be restored.', 'wp-optimize');
911 + $text .= ' ';
912 + $text .= __('In order to restore the other sizes, you should use a plugin such as "Regenerate Thumbnails".', 'wp-optimize');
913 +
914 + return $text;
789 915 }
790 916
791 917 /**
792 918 * Check if a single image compressed by another plugin.
@@ -795,10 +921,11 @@
795 921 * @return bool
796 922 */
797 923 private function is_image_compressed_by_another_plugin($image_id) {
798 924 global $wpdb;
925 + static $is_ewwwio_images_table_exists = null;
799 926
800 - $meta = $wpdb->get_results("SELECT meta_key, meta_value FROM {$wpdb->postmeta} WHERE `post_id`={$image_id}", ARRAY_A);
927 + $meta = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value FROM `{$wpdb->postmeta}` WHERE `post_id`=%d", $image_id), ARRAY_A);
801 928
802 929 if (is_array($meta)) {
803 930 foreach ($meta as $row) {
804 931 // Smush, Imagify, Compress JPEG & PNG images by TinyPNG.
@@ -803,16 +930,18 @@
803 930 foreach ($meta as $row) {
804 931 // Smush, Imagify, Compress JPEG & PNG images by TinyPNG.
805 932 if (in_array($row['meta_key'], array('wp-smpro-smush-data', '_imagify_optimization_level', 'tiny_compress_images'))) return true;
806 933 // ShortPixel Image Optimizer
807 - if ('_shortpixel_status' == $row['meta_key'] && 2 <= $row['meta_key'] && 3 > $row['meta_key']) return true;
934 + if ('_shortpixel_status' === $row['meta_key'] && 2 <= (int) $row['meta_value'] && 3 > (int) $row['meta_value']) return true;
808 935 }
809 936 }
810 937
811 - if (WP_Optimize()->get_db_info()->table_exists('ewwwio_images')) {
938 + $is_ewwwio_images_table_exists = is_null($is_ewwwio_images_table_exists) ? WP_Optimize()->get_db_info()->table_exists('ewwwio_images') : $is_ewwwio_images_table_exists;
939 +
940 + if ($is_ewwwio_images_table_exists) {
812 941 $old_show_errors = $wpdb->show_errors(false);
813 942 // EWWW Image Optimizer.
814 - $ewww_image = $wpdb->get_col("SELECT attachment_id FROM {$wpdb->prefix}ewwwio_images WHERE attachment_id={$image_id} AND gallery='media' LIMIT 1");
943 + $ewww_image = $wpdb->get_col($wpdb->prepare("SELECT attachment_id FROM `{$wpdb->prefix}ewwwio_images` WHERE attachment_id=%d AND gallery='media' LIMIT 1", $image_id));
815 944 if (!empty($ewww_image)) return true;
816 945 $wpdb->show_errors($old_show_errors);
817 946 }
818 947
@@ -831,15 +960,15 @@
831 960
832 961 if (!WP_Optimize()->get_db_info()->table_exists('ewwwio_images')) return $args;
833 962
834 963 $old_show_errors = $wpdb->show_errors(false);
835 - $compressed_images = $wpdb->get_col("SELECT DISTINCT(attachment_id) FROM {$wpdb->prefix}ewwwio_images WHERE gallery='media'");
964 + $compressed_images = $wpdb->get_col("SELECT DISTINCT(attachment_id) FROM `{$wpdb->prefix}ewwwio_images` WHERE gallery='media'");
836 965 $wpdb->show_errors($old_show_errors);
837 966
838 967 if (isset($args['post__not_in'])) {
839 - $args['post__not_in'] = array_merge($args['post__not_in'], $compressed_images);
968 + $args['post__not_in'] = array_merge($args['post__not_in'], $compressed_images); // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- is necessary and used with caution
840 969 } else {
841 - $args['post__not_in'] = $compressed_images;
970 + $args['post__not_in'] = $compressed_images; // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- is necessary and used with caution
842 971 }
843 972
844 973 return $args;
845 974 }
@@ -846,78 +975,32 @@
846 975
847 976 /**
848 977 * Returns a list of images for smush (from cache if available)
849 978 *
979 + * @param string $use_cache
850 980 * @return array - uncompressed images
851 981 */
852 - public function get_uncompressed_images() {
853 -
854 - $uncompressed_images = $this->get_from_cache('uncompressed_images');
982 + public function get_uncompressed_images($use_cache = "true") {
983 + if ("true" === $use_cache) {
984 + $uncompressed_images = $this->get_from_cache('uncompressed_images');
985 + if ($uncompressed_images && is_array($uncompressed_images)) return $uncompressed_images;
986 + }
855 987
856 - if ($uncompressed_images) return $uncompressed_images;
857 -
858 988 $uncompressed_images = array();
989 + $accepted_mimes = array('image/jpeg', 'image/gif', 'image/png');
859 990
860 991 $args = array(
861 992 'post_type' => 'attachment',
862 - 'post_mime_type' => 'image',
993 + 'post_mime_type' => $accepted_mimes,
863 994 'post_status' => 'inherit',
864 995 'posts_per_page' => apply_filters('updraft_smush_posts_per_page', 1000),
865 - 'meta_query' => array(
866 - 'relation' => 'AND',
867 - array(
868 - 'relation' => 'OR',
869 - array(
870 - 'key' => 'smush-complete',
871 - 'compare' => '!=',
872 - 'value' => '1',
873 - ),
874 - array(
875 - 'key' => 'smush-complete',
876 - 'compare' => 'NOT EXISTS',
877 - 'value' => '',
878 - ),
879 - ),
880 - // ShortPixel Image Optimizer plugin
881 - array(
882 - 'relation' => 'OR',
883 - array(
884 - 'key' => '_shortpixel_status',
885 - 'compare' => '<',
886 - 'value' => '2',
887 - ),
888 - array(
889 - 'key' => '_shortpixel_status',
890 - 'compare' => '>=',
891 - 'value' => '3',
892 - ),
893 - array(
894 - 'key' => '_shortpixel_status',
895 - 'compare' => 'NOT EXISTS',
896 - 'value' => '',
897 - ),
898 - ),
899 - // Smush plugin
900 - array(
901 - 'key' => 'wp-smpro-smush-data',
902 - 'compare' => 'NOT EXISTS',
903 - 'value' => '',
904 - ),
905 - // Imagify
906 - array(
907 - 'key' => '_imagify_optimization_level',
908 - 'compare' => 'NOT EXISTS',
909 - 'value' => '',
910 - ),
911 - // Compress JPEG & PNG images by TinyPNG
912 - array(
913 - 'key' => 'tiny_compress_images',
914 - 'compare' => 'NOT EXISTS',
915 - 'value' => '',
916 - ),
917 - )
996 + 'meta_query' => $this->get_uncompressed_images_meta_query(),
997 + 'no_found_rows' => true,
998 + 'fields' => 'ids'
918 999 );
919 1000
1001 + $allowed_extensions = WPO_Image_Utils::get_allowed_extensions();
1002 +
920 1003 if (is_multisite()) {
921 1004
922 1005 $sites = WP_Optimize()->get_sites();
923 1006
@@ -928,16 +1011,25 @@
928 1011 $args = apply_filters('wpo_get_uncompressed_images_args', $args);
929 1012 $images = new WP_Query($args);
930 1013
931 1014 foreach ($images->posts as $image) {
932 - if (file_exists(get_attached_file($image->ID))) {
933 - $uncompressed_images[$site->blog_id][] = array(
934 - 'id' => $image->ID,
935 - 'thumb_url' => wp_get_attachment_thumb_url($image->ID),
936 - 'filesize' => filesize(get_attached_file($image->ID))
937 - );
1015 + // If `field` is removed from $args it returns a WP_Post obj
1016 + $image_id = is_int($image) ? $image : $image->ID;
1017 +
1018 + $file = get_attached_file($image_id);
1019 + $ext = WPO_Image_Utils::get_extension($file);
1020 + if (file_exists($file)) {
1021 + if (WPO_Image_Utils::is_supported_extension($ext, $allowed_extensions)) {
1022 + $uncompressed_images[$site->blog_id][] = array(
1023 + 'id' => $image_id,
1024 + 'thumb_url' => wp_get_attachment_thumb_url($image_id),
1025 + 'filesize' => filesize(get_attached_file($image_id))
1026 + );
1027 + } else {
1028 + $this->log("Blog_id=$site->blog_id, ID=$image_id, File=$file This image type is not supported.");
1029 + }
938 1030 } else {
939 - $this->log("Could not find file for image: blog_id={$site->blog_id}, ID={$image->ID}, file=".get_attached_file($image->ID));
1031 + $this->log("Could not find file for image: blog_id=$site->blog_id, ID=$image_id, file=$file");
940 1032 }
941 1033 }
942 1034
943 1035 restore_current_blog();
@@ -946,16 +1038,26 @@
946 1038 } else {
947 1039 $args = apply_filters('wpo_get_uncompressed_images_args', $args);
948 1040 $images = new WP_Query($args);
949 1041 foreach ($images->posts as $image) {
950 - if (file_exists(get_attached_file($image->ID))) {
951 - $uncompressed_images[1][] = array(
952 - 'id' => $image->ID,
953 - 'thumb_url' => wp_get_attachment_thumb_url($image->ID),
954 - 'filesize' => filesize(get_attached_file($image->ID))
955 - );
1042 + // If `field` is removed from $args it returns a WP_Post obj
1043 + $image_id = is_int($image) ? $image : $image->ID;
1044 +
1045 + $file = get_attached_file($image_id);
1046 + $ext = WPO_Image_Utils::get_extension($file);
1047 +
1048 + if (file_exists($file)) {
1049 + if (WPO_Image_Utils::is_supported_extension($ext, $allowed_extensions)) {
1050 + $uncompressed_images[1][] = array(
1051 + 'id' => $image_id,
1052 + 'thumb_url' => wp_get_attachment_thumb_url($image_id),
1053 + 'filesize' => filesize(get_attached_file($image_id))
1054 + );
1055 + } else {
1056 + $this->log("Image ID=$image_id, File=$file This image type is not supported.");
1057 + }
956 1058 } else {
957 - $this->log("Could not find file for image: ID={$image->ID}, file=".get_attached_file($image->ID));
1059 + $this->log("Could not find file for image: ID=$image_id, file=$file");
958 1060 }
959 1061 }
960 1062 }
961 1063
@@ -1002,17 +1104,22 @@
1002 1104 * @return bool - true if yes, false otherwise
1003 1105 */
1004 1106 public function task_exists($image) {
1005 1107
1108 + $blog_id = get_current_blog_id();
1006 1109 $pending_tasks = $this->get_active_tasks('smush');
1007 - $queued_images = array();
1008 1110
1009 1111 if (!empty($pending_tasks)) {
1010 1112 foreach ($pending_tasks as $task) {
1011 - $queued_images[] = $task->get_option('attachment_id');
1113 + $task_attachment_id = $task->get_option('attachment_id');
1114 + $task_blog_id = $task->get_option('blog_id');
1115 +
1116 + if ($image === $task_attachment_id && $blog_id === $task_blog_id) {
1117 + return true;
1118 + }
1012 1119 }
1013 1120 }
1014 - return in_array($image, $queued_images);
1121 + return false;
1015 1122 }
1016 1123
1017 1124 /**
1018 1125 * Returns the status of images compressed in this iteration of the bulk compress
@@ -1025,13 +1132,13 @@
1025 1132 $stats = array();
1026 1133
1027 1134 foreach ($images as $image) {
1028 1135 if (is_multisite()) {
1029 - switch_to_blog($image['blog_id'], 1);
1030 - $stats[] = get_post_meta($image['attachment_id'], 'smush-complete', true) ? 'success' : 'fail';
1136 + switch_to_blog($image['blog_id']);
1137 + $stats[] = get_post_meta($image['attachment_id'], '_wpo-smush-complete', true) ? 'success' : 'fail';
1031 1138 restore_current_blog();
1032 1139 } else {
1033 - $stats[] = get_post_meta($image['attachment_id'], 'smush-complete', true) ? 'success' : 'fail';
1140 + $stats[] = get_post_meta($image['attachment_id'], '_wpo-smush-complete', true) ? 'success' : 'fail';
1034 1141 }
1035 1142 }
1036 1143
1037 1144 return array_count_values($stats);
@@ -1039,9 +1146,9 @@
1039 1146
1040 1147 /**
1041 1148 * Returns a list of images for smush (from cache if available)
1042 1149 *
1043 - * @return array - List of task objects with uncompressed images
1150 + * @return array|mixed - List of task objects with uncompressed images
1044 1151 */
1045 1152 public function get_pending_tasks() {
1046 1153 return $this->get_active_tasks('smush');
1047 1154 }
@@ -1047,16 +1154,20 @@
1047 1154 }
1048 1155
1049 1156 /**
1050 1157 * Deletes and removes any pending tasks from queue
1158 + *
1159 + * @return bool
1051 1160 */
1052 1161 public function clear_pending_images() {
1053 1162
1054 1163 $pending_tasks = $this->get_active_tasks('smush');
1055 1164
1056 - foreach ($pending_tasks as $task) {
1057 - $task->delete_meta();
1058 - $task->delete();
1165 + if (!empty($pending_tasks)) {
1166 + foreach ($pending_tasks as $task) {
1167 + $task->delete_meta();
1168 + $task->delete();
1169 + }
1059 1170 }
1060 1171
1061 1172 return true;
1062 1173 }
@@ -1075,23 +1186,37 @@
1075 1186 * Adds the required scripts and styles
1076 1187 */
1077 1188 public function admin_enqueue_scripts() {
1078 1189 $current_screen = get_current_screen();
1079 - // load scripts and styles only on WP-Optimize pages or if show_smush_metabox option enabled.
1080 - if (!preg_match('/wp\-optimize/i', $current_screen->id) && 'show' != $this->options->get_option('show_smush_metabox', 'show')) return;
1190 + if (null === $current_screen) return;
1191 + // load scripts and styles only on WP-Optimize pages
1192 + if (!preg_match('/wp\-optimize|attachment|upload/i', $current_screen->id)) return;
1081 1193
1082 - $enqueue_version = (defined('WP_DEBUG') && WP_DEBUG) ? WPO_VERSION.'.'.time() : WPO_VERSION;
1083 - $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
1084 - $min_or_not_internal = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '-'. str_replace('.', '-', WPO_VERSION). '.min';
1085 -
1194 + $enqueue_version = WP_Optimize()->get_enqueue_version();
1195 + $min_or_not = WP_Optimize()->get_min_or_not_string();
1196 + $min_or_not_internal = WP_Optimize()->get_min_or_not_internal_string();
1197 +
1086 1198 $js_variables = $this->smush_js_translations();
1087 1199 $js_variables['ajaxurl'] = admin_url('admin-ajax.php');
1088 1200 $js_variables['features'] = $this->get_features();
1089 1201
1090 1202 $js_variables['smush_ajax_nonce'] = wp_create_nonce('updraft-task-manager-ajax-nonce');
1203 + $js_variables['smush_settings'] = $this->get_smush_options();
1204 + $js_variables['blog_id'] = get_current_blog_id();
1205 + $js_variables['compress'] = esc_html__('Compress', 'wp-optimize');
1206 + $js_variables['cancel'] = esc_html__('Cancel', 'wp-optimize');
1207 + $js_variables['cancelling'] = esc_html__('Cancelling...', 'wp-optimize');
1208 + $js_variables['images_restored_successfully'] = esc_html__('The images were restored successfully', 'wp-optimize');
1209 + $js_variables['logo_src'] = esc_url(WPO_PLUGIN_URL.'images/notices/wp_optimize_logo.png');
1091 1210
1092 - wp_enqueue_script('block-ui-js', WPO_PLUGIN_URL.'js/jquery.blockUI'.$min_or_not.'.js', array('jquery'), $enqueue_version);
1093 - wp_enqueue_script('smush-js', WPO_PLUGIN_URL.'js/wposmush'.$min_or_not_internal.'.js', array('jquery', 'block-ui-js'), $enqueue_version);
1211 + wp_enqueue_script('block-ui-js', WPO_PLUGIN_URL.'includes/blockui/jquery.blockUI'.$min_or_not.'.js', array('jquery'), $enqueue_version);
1212 + wp_enqueue_script('wp-optimize-heartbeat-js', WPO_PLUGIN_URL.'js/heartbeat'.$min_or_not_internal.'.js', array('jquery'), $enqueue_version);
1213 + wp_localize_script('wp-optimize-heartbeat-js', 'wpo_heartbeat_ajax', array(
1214 + 'ajaxurl' => admin_url('admin-ajax.php'),
1215 + 'nonce' => wp_create_nonce('heartbeat-nonce'),
1216 + 'interval' => WPO_Ajax::HEARTBEAT_INTERVAL
1217 + ));
1218 + wp_enqueue_script('smush-js', WPO_PLUGIN_URL.'js/wposmush'.$min_or_not_internal.'.js', array('jquery', 'block-ui-js', 'wp-optimize-block-ui', 'wp-optimize-send-command', 'wp-optimize-heartbeat-js'), $enqueue_version);
1094 1219 wp_enqueue_style('smush-css', WPO_PLUGIN_URL.'css/smush'.$min_or_not_internal.'.css', array(), $enqueue_version);
1095 1220 wp_localize_script('smush-js', 'wposmush', $js_variables);
1096 1221 }
1097 1222
@@ -1110,9 +1235,9 @@
1110 1235 public function set_default_options() {
1111 1236
1112 1237 $options = array(
1113 1238 'compression_server' => $this->get_default_webservice(),
1114 - 'image_quality' => 'very_good',
1239 + 'image_quality' => 92,
1115 1240 'lossy_compression' => false,
1116 1241 'back_up_original' => true,
1117 1242 'preserve_exif' => false,
1118 1243 'autosmush' => false,
@@ -1117,8 +1242,9 @@
1117 1242 'preserve_exif' => false,
1118 1243 'autosmush' => false,
1119 1244 'back_up_delete_after' => $this->options->get_option('back_up_delete_after', true),
1120 1245 'back_up_delete_after_days' => $this->options->get_option('back_up_delete_after_days', 50),
1246 + 'webp_conversion' => false,
1121 1247 );
1122 1248
1123 1249 $this->update_smush_options($options);
1124 1250 }
@@ -1141,9 +1267,9 @@
1141 1267
1142 1268 /**
1143 1269 * Gets allowed service providers for smush
1144 1270 *
1145 - * @return array - key value pair of service name => task name
1271 + * @return array - A pair of key/value. e.g. service name => task name
1146 1272 */
1147 1273 public function get_allowed_services() {
1148 1274 return array(
1149 1275 'resmushit' => 'Re_Smush_It_Task',
@@ -1150,11 +1276,32 @@
1150 1276 );
1151 1277 }
1152 1278
1153 1279 /**
1280 + * Gets current compression server hint.
1281 + *
1282 + * @return string
1283 + */
1284 + public function get_compression_server_hint() {
1285 +
1286 + switch ($this->webservice) {
1287 + case 'resmushit':
1288 + $title = 'reSmush.it';
1289 + break;
1290 + default:
1291 + $title = $this->webservice;
1292 + }
1293 +
1294 + // translators: %s is a service used to compress images
1295 + $hint = sprintf(__('Service is provided by %s', 'wp-optimize'), $title);
1296 +
1297 + return $hint;
1298 + }
1299 +
1300 + /**
1154 1301 * Gets allowed service provider features smush
1155 1302 *
1156 - * @return array - key value pair of service name => features exposed
1303 + * @return array - A pair of key/value. e.g. service name => features exposed
1157 1304 */
1158 1305 public function get_features() {
1159 1306 $features = array();
1160 1307 foreach ($this->get_allowed_services() as $service => $class_name) {
@@ -1168,17 +1315,24 @@
1168 1315 *
1169 1316 * @return string - file path
1170 1317 */
1171 1318 public function get_logfile_path() {
1172 - $upload_dir = wp_upload_dir();
1173 - $upload_base = $upload_dir['basedir'];
1174 - return $upload_base . '/smush-' . substr(md5(wp_salt()), 0, 20) . '.log';
1319 + return WP_Optimize_Utils::get_log_file_path('smush');
1175 1320 }
1176 1321
1177 1322 /**
1323 + * Delete all smush log files
1324 + *
1325 + * @deprecated 3.5.0
1326 + */
1327 + public function delete_log_files() {
1328 + _deprecated_function(__METHOD__, '3.5.0');
1329 + }
1330 +
1331 + /**
1178 1332 * Adds a logger to the task
1179 1333 *
1180 - * @param Mixed $task - a task object
1334 + * @param mixed $task - a task object
1181 1335 */
1182 1336 public function set_task_logger($task) {
1183 1337 if (!$this->logger) {
1184 1338 $this->logger = new Updraft_File_Logger($this->get_logfile_path());
@@ -1192,15 +1346,14 @@
1192 1346 /**
1193 1347 * Writes a standardised header to the log file
1194 1348 */
1195 1349 public function write_log_header() {
1196 -
1197 1350 global $wpdb;
1198 1351
1199 1352 // phpcs:disable
1200 1353 $wp_version = $this->get_wordpress_version();
1201 1354 $mysql_version = $wpdb->db_version();
1202 - $safe_mode = $this->detect_safe_mode();
1355 + $disabled_functions = ini_get('disable_functions');
1203 1356 $max_execution_time = (int) @ini_get("max_execution_time");
1204 1357
1205 1358 $memory_limit = ini_get('memory_limit');
1206 1359 $memory_usage = round(@memory_get_usage(false)/1048576, 1);
@@ -1212,30 +1365,35 @@
1212 1365 $log_header = array();
1213 1366
1214 1367 // phpcs:enable
1215 1368 $log_header[] = "\n";
1216 - $log_header[] = "Header for logs at time: ".date('r')." on ".network_site_url();
1369 + $log_header[] = "Header for logs at time: ".gmdate('r')." on ".network_site_url();
1217 1370 $log_header[] = "WP: ".$wp_version;
1218 - $log_header[] = "PHP: ".phpversion()." (".PHP_SAPI.", ".@php_uname().")";// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1371 + $php_uname = '';
1372 + if (function_exists('php_uname')) {
1373 + $php_uname = ", " . php_uname();
1374 + }
1375 + $log_header[] = "PHP: ".phpversion()." (".PHP_SAPI.$php_uname.")";
1219 1376 $log_header[] = "MySQL: $mysql_version";
1220 1377 $log_header[] = "WPLANG: ".get_locale();
1221 - $log_header[] = "Server: ".$_SERVER["SERVER_SOFTWARE"];
1378 + $log_header[] = "Server: ". TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal('server', 'SERVER_SOFTWARE', 'string', 'sanitize_text_field', '-');
1222 1379 $log_header[] = "Outbound connections: ".(defined('WP_HTTP_BLOCK_EXTERNAL') ? 'Y' : 'N');
1223 - $log_header[] = "safe_mode: $safe_mode";
1380 + $log_header[] = "Disabled Functions: $disabled_functions";
1224 1381 $log_header[] = "max_execution_time: $max_execution_time";
1225 - $log_header[] = "memory_limit: $memory_limit (used: ${memory_usage}M | ${total_memory_usage}M)";
1382 + $log_header[] = "memory_limit: $memory_limit (used: {$memory_usage}M | {$total_memory_usage}M)";
1226 1383 $log_header[] = "multisite: ".(is_multisite() ? 'Y' : 'N');
1227 1384 $log_header[] = "openssl: ".(defined('OPENSSL_VERSION_TEXT') ? OPENSSL_VERSION_TEXT : 'N');
1228 1385
1229 -
1230 - foreach ($log_header as $log_entry) {
1231 - $this->log($log_entry);
1386 + if (apply_filters("wpo_write_server_info_in_smush_log", false)) {
1387 + foreach ($log_header as $log_entry) {
1388 + $this->log($log_entry);
1389 + }
1232 1390 }
1233 1391
1234 - $memlim = $this->memory_check_current();
1392 + $memory_limit = $this->memory_check_current();
1235 1393
1236 - if ($memlim<65 && $memlim>0) {
1237 - $this->log(sprintf('The amount of memory (RAM) allowed for PHP is very low (%s Mb) - you should increase it to avoid failures due to insufficient memory (consult your web hosting company for more help)', round($memlim, 1)), 'warning');
1394 + if ($memory_limit<65 && $memory_limit>0) {
1395 + $this->log(sprintf('The amount of memory (RAM) allowed for PHP is very low (%s Mb) - you should increase it to avoid failures due to insufficient memory (consult your web hosting company for more help)', round($memory_limit, 1)), 'warning');
1238 1396 }
1239 1397
1240 1398 if ($max_execution_time>0 && $max_execution_time<20) {
1241 1399 $this->log(sprintf('The amount of time allowed for WordPress plugins to run is very low (%s seconds) - you should increase it to avoid failures due to time-outs (consult your web hosting company for more help - it is the max_execution_time PHP setting; the recommended value is %s seconds or more)', $max_execution_time, 90), 'warning');
@@ -1252,9 +1410,9 @@
1252 1410
1253 1411 /**
1254 1412 * Get the WordPress version
1255 1413 *
1256 - * @return String - the version
1414 + * @return string - the version
1257 1415 */
1258 1416 public function get_wordpress_version() {
1259 1417 static $got_wp_version = false;
1260 1418
@@ -1259,9 +1417,9 @@
1259 1417 static $got_wp_version = false;
1260 1418
1261 1419 if (!$got_wp_version) {
1262 1420 global $wp_version;
1263 - @include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1421 + @include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress warning if `version.php` does not exist
1264 1422 $got_wp_version = $wp_version;
1265 1423 }
1266 1424
1267 1425 return $got_wp_version;
@@ -1269,16 +1427,18 @@
1269 1427
1270 1428 /**
1271 1429 * Get the current memory limit
1272 1430 *
1273 - * @return String - memory limit in megabytes
1431 + * @param ?string $memory_limit Memory limit in megabytes
1432 + *
1433 + * @return string - memory limit in megabytes
1274 1434 */
1275 - public function memory_check_current($memory_limit = false) {
1435 + public function memory_check_current($memory_limit = null) {
1276 1436 // Returns in megabytes
1277 - if (false == $memory_limit) $memory_limit = ini_get('memory_limit');
1437 + if (empty($memory_limit)) $memory_limit = ini_get('memory_limit');
1278 1438 $memory_limit = rtrim($memory_limit);
1279 1439 $memory_unit = $memory_limit[strlen($memory_limit)-1];
1280 - if (0 == (int) $memory_unit && '0' !== $memory_unit) {
1440 + if (0 === (int) $memory_unit && '0' !== $memory_unit) {
1281 1441 $memory_limit = substr($memory_limit, 0, strlen($memory_limit)-1);
1282 1442 } else {
1283 1443 $memory_unit = '';
1284 1444 }
@@ -1300,17 +1460,8 @@
1300 1460 return $memory_limit;
1301 1461 }
1302 1462
1303 1463 /**
1304 - * Detect if safe_mode is on
1305 - *
1306 - * @return Integer - 1 or 0
1307 - */
1308 - public function detect_safe_mode() {
1309 - return (@ini_get('safe_mode') && strtolower(@ini_get('safe_mode')) != "off") ? 1 : 0;// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1310 - }
1311 -
1312 - /**
1313 1464 * Saves a value to the cache.
1314 1465 *
1315 1466 * @param string $key
1316 1467 * @param mixed $value
@@ -1319,9 +1470,9 @@
1319 1470 public function save_to_cache($key, $value, $blog_id = 1) {
1320 1471 $transient_limit = 3600 * 48;
1321 1472 $key = 'wpo_smush_cache_' . $blog_id . '_'. $key;
1322 1473
1323 - return WP_Optimize_Transients_Cache::get_instance()->set($key, $value, $transient_limit);
1474 + WP_Optimize_Transients_Cache::get_instance()->set_transient($key, $value, $transient_limit);
1324 1475 }
1325 1476
1326 1477 /**
1327 1478 * Gets value from the cache.
@@ -1332,11 +1483,9 @@
1332 1483 */
1333 1484 public function get_from_cache($key, $blog_id = 1) {
1334 1485 $key = 'wpo_smush_cache_' . $blog_id . '_'. $key;
1335 1486
1336 - $value = WP_Optimize_Transients_Cache::get_instance()->get($key);
1337 -
1338 - return $value;
1487 + return WP_Optimize_Transients_Cache::get_instance()->get($key);
1339 1488 }
1340 1489
1341 1490 /**
1342 1491 * Deletes a value from the cache.
@@ -1372,11 +1521,11 @@
1372 1521 global $wpdb;
1373 1522
1374 1523 // get list of cached data by optimization.
1375 1524 if ($this->is_multisite_mode()) {
1376 - $keys = $wpdb->get_col("SELECT meta_key FROM {$wpdb->sitemeta} WHERE meta_key LIKE '%wpo_smush_cache_%'");
1525 + $keys = $wpdb->get_col("SELECT meta_key FROM `{$wpdb->sitemeta}` WHERE meta_key LIKE '%wpo_smush_cache_%'");
1377 1526 } else {
1378 - $keys = $wpdb->get_col("SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '%wpo_smush_cache_%'");
1527 + $keys = $wpdb->get_col("SELECT option_name FROM `{$wpdb->options}` WHERE option_name LIKE '%wpo_smush_cache_%'");
1379 1528 }
1380 1529
1381 1530 if (!empty($keys)) {
1382 1531 $transient_keys = array();
@@ -1416,19 +1565,19 @@
1416 1565 $year = (int) $match[1];
1417 1566 $month = (int) $match[2];
1418 1567
1419 1568 $limit = strtotime('-'.$days_ago.' '.(($days_ago > 1) ? 'days' : 'day'));
1420 - $year_limit = (int) date('Y', $limit);
1421 - $month_limit = (int) date('m', $limit);
1422 - $day_limit = (int) date('j', $limit);
1569 + $year_limit = (int) gmdate('Y', $limit);
1570 + $month_limit = (int) gmdate('m', $limit);
1571 + $day_limit = (int) gmdate('j', $limit);
1423 1572
1424 1573 // if current directory is newer than needed then we skip it.
1425 - if ($year_limit < $year || ($year_limit == $year && $month_limit < $month)) {
1574 + if ($year_limit < $year || ($year_limit === $year && $month_limit < $month)) {
1426 1575 return;
1427 1576 }
1428 1577
1429 1578 // we will check dates only in directory that contain limit date.
1430 - $check_date = ($year_limit == $year && $month_limit == $month);
1579 + $check_date = ($year_limit === $year && $month_limit === $month);
1431 1580 }
1432 1581
1433 1582 // GLOB_BRACE isn't defined on some systems (Solaris, SunOS and more) > https://www.php.net/manual/en/function.glob.php
1434 1583 $files = glob($directory . '*-updraft-pre-smush-original.*', (defined('GLOB_BRACE') ? GLOB_BRACE : 0));
@@ -1434,13 +1583,13 @@
1434 1583 $files = glob($directory . '*-updraft-pre-smush-original.*', (defined('GLOB_BRACE') ? GLOB_BRACE : 0));
1435 1584
1436 1585 foreach ($files as $file) {
1437 1586 if ($check_date) {
1438 - $filedate_day = (int) date('j', filectime($file));
1587 + $filedate_day = (int) gmdate('j', filectime($file));
1439 1588 if ($filedate_day >= $day_limit) continue;
1440 1589 }
1441 1590
1442 - unlink($file);
1591 + wp_delete_file($file);
1443 1592 }
1444 1593
1445 1594 } else {
1446 1595 // scan directories recursively.
@@ -1451,9 +1600,9 @@
1451 1600 $file = readdir($handle);
1452 1601
1453 1602 while (false !== $file) {
1454 1603
1455 - if ('.' == $file || '..' == $file) {
1604 + if ('.' === $file || '..' === $file) {
1456 1605 $file = readdir($handle);
1457 1606 continue;
1458 1607 }
1459 1608
@@ -1461,9 +1610,9 @@
1461 1610 $this->clear_backup_images_directory($directory . $file, $days_ago);
1462 1611 } elseif (is_file($directory . $file) && preg_match('/^.+-updraft-pre-smush-original\.\S{3,4}/i', $file)) {
1463 1612 // check the file time and compare with $days_ago.
1464 1613 $filedate_day = (int) filectime($directory . $file);
1465 - if ($filedate_day > 0 && ($current_time - $filedate_day) / 86400 >= $days_ago) unlink($directory . $file);
1614 + if ($filedate_day > 0 && ($current_time - $filedate_day) / 86400 >= $days_ago) wp_delete_file($directory . $file);
1466 1615 }
1467 1616
1468 1617 $file = readdir($handle);
1469 1618 }
@@ -1474,9 +1623,9 @@
1474 1623 /**
1475 1624 * Clean backup smush images according to saved options.
1476 1625 */
1477 1626 public function clear_backup_images() {
1478 - $back_up_delete_after = $this->options->get_option('back_up_delete_after', false);
1627 + $back_up_delete_after = $this->options->get_option('back_up_delete_after');
1479 1628
1480 1629 if (!$back_up_delete_after) return;
1481 1630
1482 1631 $back_up_delete_after_days = $this->options->get_option('back_up_delete_after_days', 50);
@@ -1494,48 +1643,12 @@
1494 1643 *
1495 1644 * @return bool
1496 1645 */
1497 1646 public function is_compressed($attachment_id) {
1498 - return (true == get_post_meta($attachment_id, 'smush-complete', true));
1647 + return (true === (bool) get_post_meta($attachment_id, '_wpo-smush-complete', true));
1499 1648 }
1500 1649
1501 1650 /**
1502 - * @param array $form_fields
1503 - * @param WP_Post $post
1504 - *
1505 - * @return array
1506 - */
1507 - public function add_compress_button_to_media_modal($form_fields, $post) {
1508 -
1509 - if (!is_admin() || !function_exists('get_current_screen')) return $form_fields;
1510 -
1511 - /**
1512 - * In media modal get_current_screen() return null or id = 'async-upload' We don't need add smush fields elsewhere.
1513 - */
1514 - $current_screen = get_current_screen();
1515 - if (null !== $current_screen && 'async-upload' != $current_screen->id) return $form_fields;
1516 -
1517 - /**
1518 - * Don't show additional fields for non-image attachments.
1519 - */
1520 - if (!wp_attachment_is_image($post->ID)) return $form_fields;
1521 -
1522 - ob_start();
1523 - $this->render_smush_metabox($post);
1524 - $smush_metabox = ob_get_contents();
1525 - ob_end_clean();
1526 -
1527 - $form_fields['wpo_compress_image'] = array(
1528 - 'value' => '',
1529 - 'label' => __('Compress image', 'wp-optimize'),
1530 - 'input' => 'html',
1531 - 'html' => $smush_metabox,
1532 - );
1533 -
1534 - return $form_fields;
1535 - }
1536 -
1537 - /**
1538 1651 * Returns true if multisite
1539 1652 *
1540 1653 * @return bool
1541 1654 */
@@ -1548,15 +1661,37 @@
1548 1661 *
1549 1662 * @param int $post_id - WordPress Post ID
1550 1663 */
1551 1664 public function unscheduled_original_file_deletion($post_id) {
1552 - $the_original_file = get_post_meta($post_id, 'original-file', true);
1553 - if ('' != $the_original_file && file_exists($the_original_file)) {
1554 - @unlink($the_original_file);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1665 + $the_original_file = get_post_meta($post_id, '_wpo-original-file', true);
1666 + // If no original file meta exists, there is nothing to delete.
1667 + if (empty($the_original_file)) {
1668 + return;
1555 1669 }
1670 + $uploads_dir = wp_get_upload_dir();
1671 + $uploads_basedir = realpath($uploads_dir['basedir']);
1672 + if (!$uploads_basedir) return;
1673 + $uploads_basedir = trailingslashit($uploads_basedir);
1674 + $the_original_file = realpath($uploads_basedir . $the_original_file);
1675 + if ($the_original_file && 0 === strpos($the_original_file, $uploads_basedir) && file_exists($the_original_file)) {
1676 + wp_delete_file($the_original_file);
1677 + }
1556 1678 }
1557 1679
1558 1680 /**
1681 + * Remove failed smush tasks from the wp_tm_tasks table
1682 + */
1683 + public function clear_failed_tasks() {
1684 + $failed_tasks = $this->get_tasks('failed', 'smush');
1685 + if (empty($failed_tasks)) return;
1686 +
1687 + foreach ($failed_tasks as $task) {
1688 + $task->delete_meta();
1689 + $task->delete();
1690 + }
1691 + }
1692 +
1693 + /**
1559 1694 * Instance of WP_Optimize_Page_Cache_Preloader.
1560 1695 *
1561 1696 * @return self
1562 1697 */
@@ -1566,12 +1701,73 @@
1566 1701 }
1567 1702
1568 1703 return self::$_instance;
1569 1704 }
1705 +
1706 + /**
1707 + * Meta query array for getting uncompressed images
1708 + *
1709 + * @return array
1710 + */
1711 + public function get_uncompressed_images_meta_query() {
1712 + return array(
1713 + 'relation' => 'AND',
1714 + array(
1715 + 'relation' => 'OR',
1716 + array(
1717 + 'key' => '_wpo-smush-complete',
1718 + 'compare' => '!=',
1719 + 'value' => '1',
1720 + ),
1721 + array(
1722 + 'key' => '_wpo-smush-complete',
1723 + 'compare' => 'NOT EXISTS',
1724 + 'value' => '',
1725 + ),
1726 + ),
1727 + // ShortPixel Image Optimizer plugin
1728 + array(
1729 + 'relation' => 'OR',
1730 + array(
1731 + 'key' => '_shortpixel_status',
1732 + 'compare' => '<',
1733 + 'value' => '2',
1734 + ),
1735 + array(
1736 + 'key' => '_shortpixel_status',
1737 + 'compare' => '>=',
1738 + 'value' => '3',
1739 + ),
1740 + array(
1741 + 'key' => '_shortpixel_status',
1742 + 'compare' => 'NOT EXISTS',
1743 + 'value' => '',
1744 + ),
1745 + ),
1746 + // Smush plugin
1747 + array(
1748 + 'key' => 'wp-smpro-smush-data',
1749 + 'compare' => 'NOT EXISTS',
1750 + 'value' => '',
1751 + ),
1752 + // Imagify
1753 + array(
1754 + 'key' => '_imagify_optimization_level',
1755 + 'compare' => 'NOT EXISTS',
1756 + 'value' => '',
1757 + ),
1758 + // Compress JPEG & PNG images by TinyPNG
1759 + array(
1760 + 'key' => 'tiny_compress_images',
1761 + 'compare' => 'NOT EXISTS',
1762 + 'value' => '',
1763 + ),
1764 + );
1765 + }
1570 1766 }
1571 1767
1572 1768 /**
1573 - * Returns a Updraft_Smush_Manager instance
1769 + * Returns Updraft_Smush_Manager instance
1574 1770 */
1575 1771 function Updraft_Smush_Manager() {
1576 1772 return Updraft_Smush_Manager::instance();
1577 1773 }