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-wp-optimize-preloader.php +95 -44 3.2.5 → 4.7.0 View file →
@@ -1,15 +1,22 @@
1 1 <?php
2 2
3 3 if (!defined('ABSPATH')) die('No direct access allowed');
4 4
5 -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');
5 +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');
6 6
7 -abstract class WP_Optimize_Preloader extends Updraft_Task_Manager_1_3 {
7 +abstract class WP_Optimize_Preloader extends Updraft_Task_Manager_1_4 {
8 8
9 9 protected $options;
10 10
11 11 /**
12 + * If set to true, the preloader will not close the browser connection when running via AJAX.
13 + *
14 + * @var bool
15 + */
16 + protected $dont_close_browser_connection = false;
17 +
18 + /**
12 19 * WP_Optimize_Page_Cache_Preloader constructor.
13 20 */
14 21 public function __construct() {
15 22 parent::__construct();
@@ -15,9 +22,13 @@
15 22 parent::__construct();
16 23
17 24 $this->options = WP_Optimize()->get_options();
18 25 // setup loggers
19 - $this->set_loggers(WP_Optimize()->wpo_loggers());
26 + if (did_action('init')) {
27 + $this->setup_loggers();
28 + } else {
29 + add_action('init', array($this, 'setup_loggers'));
30 + }
20 31
21 32 add_action('wpo_' . $this->preload_type . '_preload_continue', array($this, 'process_tasks_queue'));
22 33 add_filter('updraft_interrupt_tasks_queue_'.$this->task_type, array($this, 'maybe_interrupt_queue'), 20);
23 34 }
@@ -22,8 +33,17 @@
22 33 add_filter('updraft_interrupt_tasks_queue_'.$this->task_type, array($this, 'maybe_interrupt_queue'), 20);
23 34 }
24 35
25 36 /**
37 + * Setup loggers
38 + *
39 + * @return void
40 + */
41 + public function setup_loggers() {
42 + $this->set_loggers(WP_Optimize()->wpo_loggers());
43 + }
44 +
45 + /**
26 46 * Get a schedule interval
27 47 *
28 48 * @param string $schedule_key The schedule to check
29 49 * @return integer
@@ -33,9 +53,9 @@
33 53 if (!isset($schedules[$schedule_key])) {
34 54 $this->log('Could not get interval for event of type '.$schedule_key);
35 55 return 0;
36 56 }
37 - return isset($schedules[$schedule_key]['interval']) ? $schedules[$schedule_key]['interval'] : 0;
57 + return (int) $schedules[$schedule_key]['interval'] ?? 0;
38 58 }
39 59
40 60 /**
41 61 * Get the interval to continuing a preload task
@@ -41,13 +61,14 @@
41 61 * Get the interval to continuing a preload task
42 62 *
43 63 * @return integer
44 64 */
45 - protected function get_continue_preload_cron_interval() {
65 + public function get_continue_preload_cron_interval() {
46 66 /**
47 67 * Filters the interval between each preload attempt, in seconds.
48 68 */
49 - return (int) apply_filters('wpo_' . $this->preload_type . '_preload_continue_interval', 600);
69 + $filtered_interval = apply_filters('wpo_' . $this->preload_type . '_preload_continue_interval', 600);
70 + return is_int($filtered_interval) ? $filtered_interval : 600;
50 71 }
51 72
52 73 /**
53 74 * Schedule action for continuously preload.
@@ -56,9 +77,9 @@
56 77 $continue_in = wp_next_scheduled('wpo_' . $this->preload_type .'_preload_continue');
57 78
58 79 // Action is still scheduled
59 80 if ($continue_in && $continue_in > 0) return;
60 - // Action is overdue, delete it and re schedule it
81 + // Action is overdue, delete it and re-schedule it
61 82 if ($continue_in && $continue_in < 0) $this->delete_preload_continue_action();
62 83
63 84 wp_schedule_event(time() + $this->get_schedule_interval('wpo_' . $this->preload_type . '_preload_continue_interval'), 'wpo_' . $this->preload_type . '_preload_continue_interval', 'wpo_' . $this->preload_type . '_preload_continue');
64 85 }
@@ -73,12 +94,13 @@
73 94 /**
74 95 * Run preload. If task queue is empty it creates tasks for site urls.
75 96 *
76 97 * @param string $type - The preload type (schedule | manual)
77 - * @param array $response - Specific response for echo into output thread when browser connection closing.
98 + * @param ?array $response - Specific response for echo into output thread when browser connection closing.
99 + * @param bool $silent - If DOING_AJAX, close the connection without sending any additional data (default: false)
78 100 * @return array|void - Void when closing the browser connection
79 101 */
80 - public function run($type = 'scheduled', $response = null) {
102 + public function run($type = 'scheduled', $response = null, $silent = false) {
81 103 if (!$this->is_option_active()) {
82 104 return $this->get_option_disabled_error();
83 105 }
84 106
@@ -101,20 +123,28 @@
101 123 }
102 124
103 125 $is_wp_cli = defined('WP_CLI') && WP_CLI;
104 126
105 - // close browser connection and continue work.
106 - // don't close connection for WP-CLI
107 - if (false == $is_wp_cli) {
108 - WP_Optimize()->close_browser_connection(json_encode($response));
127 + // close browser connection and continue work for ajax actions.
128 + if (defined('DOING_AJAX') && DOING_AJAX && !$this->dont_close_browser_connection) {
129 + if (true === $silent) {
130 + $output = '';
131 + } else {
132 + $output = wp_json_encode($response);
133 + }
134 +
135 + WP_Optimize()->close_browser_connection($output);
109 136 }
110 137
138 + // Reset the flag to not close the browser connection for the next runs.
139 + $this->dont_close_browser_connection = false;
140 +
111 141 // trying to change time limit.
112 142 WP_Optimize()->change_time_limit();
113 143
114 144 $status = $this->get_status($this->task_type);
115 145
116 - if (0 == $status['all_tasks'] && $lock) {
146 + if (0 === (int) $status['all_tasks'] && $lock) {
117 147 if (is_multisite()) {
118 148 $sites = WP_Optimize()->get_sites();
119 149
120 150 foreach ($sites as $site) {
@@ -137,8 +167,24 @@
137 167 }
138 168 }
139 169
140 170 /**
171 + * Set the flag to not close the browser connection when running via AJAX.
172 + *
173 + * @return void
174 + */
175 + public function maybe_dont_close_browser_connection() {
176 +
177 + if ($this->dont_close_browser_connection) return;
178 +
179 + $dont_close_browser_connection = apply_filters('wpo_' . $this->preload_type . '_preloader_dont_close_browser_connection', $this->dont_close_browser_connection);
180 +
181 + if ($dont_close_browser_connection) {
182 + $this->dont_close_browser_connection = true;
183 + }
184 + }
185 +
186 + /**
141 187 * Process tasks queue.
142 188 */
143 189 public function process_tasks_queue() {
144 190 // schedule continue preload action.
@@ -169,9 +215,9 @@
169 215
170 216 if ($interrupt) return $interrupt;
171 217
172 218 static $memory_threshold = null;
173 - if (null == $memory_threshold) {
219 + if (null === $memory_threshold) {
174 220 /**
175 221 * Filters the minimum memory required before stopping a queue. Default: 10MB
176 222 */
177 223 $memory_threshold = apply_filters('wpo_' . $this->preload_type . '_preload_memory_threshold', 10485760);
@@ -208,9 +254,9 @@
208 254 *
209 255 * @return bool
210 256 */
211 257 public function is_cancelled() {
212 - return $this->options->get_option("last_{$this->preload_type}_preload_cancel", false);
258 + return (bool) $this->options->get_option("last_{$this->preload_type}_preload_cancel", false);
213 259 }
214 260
215 261 /**
216 262 * Check if preloading queue is processing.
@@ -223,9 +269,9 @@
223 269
224 270 /**
225 271 * Get current status of preloading urls.
226 272 *
227 - * @return array
273 + * @return mixed
228 274 */
229 275 public function get_status_info() {
230 276
231 277 $status = $this->get_status($this->task_type);
@@ -233,9 +279,9 @@
233 279
234 280 if ($this->is_semaphore_locked('wpo_' . $this->preload_type . '_preloader_creating_tasks') && !$this->is_cancelled()) {
235 281 // we are still creating tasks.
236 282 return $this->get_preloading_message($preload_data);
237 - } elseif ($status['complete_tasks'] == $status['all_tasks']) {
283 + } elseif ((int) $status['complete_tasks'] === (int) $status['all_tasks']) {
238 284 $gmt_offset = (int) (3600 * get_option('gmt_offset'));
239 285
240 286 $last_preload_time = $this->options->get_option('wpo_last_' . $this->preload_type . '_preload');
241 287
@@ -247,10 +293,11 @@
247 293 }
248 294 } else {
249 295 $preload_resuming_time = wp_next_scheduled('wpo_' . $this->preload_type . '_preload_continue');
250 296 $preload_resuming_in = $preload_resuming_time ? $preload_resuming_time - time() : 0;
297 + // translators: %1$s: number of preloaded urls, %2$s: total number of urls
251 298 $preloaded_message = sprintf(_n('%1$s out of %2$s URL preloaded', '%1$s out of %2$s URLs preloaded', $status['all_tasks'], 'wp-optimize'), $status['complete_tasks'], $status['all_tasks']);
252 - if ('sitemap' == $this->options->get_option('wpo_last_' . $this->preload_type . '_preload_type', '')) {
299 + if ('sitemap' === $this->options->get_option('wpo_last_' . $this->preload_type . '_preload_type', '')) {
253 300 $preloaded_message = __('Preloading posts found in sitemap:', 'wp-optimize') .' '. $preloaded_message;
254 301 }
255 302 $return = $this->get_preload_progress_message($preload_data, $preloaded_message, $preload_resuming_in);
256 303 if (defined('DOING_AJAX') && DOING_AJAX) {
@@ -255,9 +302,9 @@
255 302 $return = $this->get_preload_progress_message($preload_data, $preloaded_message, $preload_resuming_in);
256 303 if (defined('DOING_AJAX') && DOING_AJAX) {
257 304 // if no cron was found or cron is overdue more than 20s, trigger it
258 305 if (!$preload_resuming_time || $preload_resuming_in < -20) {
259 - $this->run($return);
306 + $this->run('scheduled', $return);
260 307 }
261 308 }
262 309 return $return;
263 310 }
@@ -270,9 +317,9 @@
270 317 */
271 318 public function is_running() {
272 319 $status = $this->get_status($this->task_type);
273 320
274 - if ($status['all_tasks'] > 0) return true;
321 + return $status['all_tasks'] > 0;
275 322 }
276 323
277 324 /**
278 325 * Preload desktop version from url.
@@ -283,9 +330,9 @@
283 330 */
284 331 public function preload_desktop($url) {
285 332 $desktop_args = array(
286 333 'httpversion' => '1.1',
287 - 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
334 + 'user-agent' => WP_Optimize_Utils::get_user_agent(),
288 335 'timeout' => 10,
289 336 'headers' => apply_filters('wpo_preload_headers', array()),
290 337 );
291 338
@@ -307,9 +354,9 @@
307 354 if (!apply_filters('wpo_should_preload_amp', false, $url)) return;
308 355
309 356 $amp_args = array(
310 357 'httpversion' => '1.1',
311 - 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
358 + 'user-agent' => WP_Optimize_Utils::get_user_agent(),
312 359 'timeout' => 10,
313 360 'headers' => apply_filters('wpo_preload_headers', array()),
314 361 );
315 362
@@ -327,8 +374,9 @@
327 374 *
328 375 * @return string
329 376 */
330 377 protected function get_sitemap_filename() {
378 + $sitemap_filename = 'sitemap.xml';
331 379 /**
332 380 * Filter the sitemap file used to collect the URLs to preload
333 381 *
334 382 * @param string $filename - The sitemap name
@@ -333,9 +381,10 @@
333 381 *
334 382 * @param string $filename - The sitemap name
335 383 * @default sitemap.xml
336 384 */
337 - return apply_filters('wpo_cache_preload_sitemap_filename', 'sitemap.xml');
385 + $filtered_sitemap_filename = apply_filters('wpo_cache_preload_sitemap_filename', $sitemap_filename);
386 + return is_string($filtered_sitemap_filename) ? $filtered_sitemap_filename : $sitemap_filename;
338 387 }
339 388
340 389 /**
341 390 * Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls.
@@ -352,8 +401,9 @@
352 401 $urls = $this->get_post_urls();
353 402 $this->options->update_option('wpo_last_' . $this->preload_type . '_preload_type', 'posts');
354 403 }
355 404
405 + // translators: %d: number of urls
356 406 $this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls)));
357 407
358 408 /**
359 409 * Filter the URLs which will be preloaded
@@ -360,9 +410,10 @@
360 410 *
361 411 * @param array $urls
362 412 * @return array
363 413 */
364 - return apply_filters('wpo_preload_get_site_urls', $urls);
414 + $filtered_url = apply_filters('wpo_preload_get_site_urls', $urls);
415 + return is_array($filtered_url) ? $filtered_url : array();
365 416 }
366 417
367 418 /**
368 419 * Loads sitemap file and returns list of urls.
@@ -368,9 +419,9 @@
368 419 * Loads sitemap file and returns list of urls.
369 420 *
370 421 * @param string $sitemap_url
371 422 *
372 - * @return array|bool
423 + * @return mixed
373 424 */
374 425 public function get_sitemap_urls($sitemap_url = '') {
375 426
376 427 $urls = array();
@@ -390,9 +441,9 @@
390 441 if (is_wp_error($response)) {
391 442 $response = file_get_contents($sitemap_url);
392 443
393 444 // if response is empty then try load from file.
394 - if (empty($response) && '' == $sitemap_url) {
445 + if (empty($response) && '' === $sitemap_url) {
395 446 $sitemap_file = $this->get_local_sitemap_file();
396 447
397 448 $response = file_get_contents($sitemap_file);
398 449 }
@@ -398,16 +449,16 @@
398 449 }
399 450
400 451 if (empty($response)) return $urls;
401 452
402 - $xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
453 + $xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress warnings when error found in XML data
403 454 } else {
404 455 // parse xml answer.
405 - $xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
456 + $xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress warnings when error found in XML data
406 457 }
407 458
408 459 // xml file has not valid xml content then return false.
409 - if (false === $xml) return false;
460 + if (false === $xml) return array();
410 461
411 462 // if exists urls then return them.
412 463 if (isset($xml->url)) {
413 464 foreach ($xml->url as $element) {
@@ -414,17 +465,14 @@
414 465 if (!isset($element->loc)) continue;
415 466 $urls[] = (string) $element->loc;
416 467 }
417 468 } elseif (isset($xml->sitemap)) {
418 - // if has links to other sitemap files then get urls from them.
469 + // if it has links to other sitemap files then get urls from them.
419 470 foreach ($xml->sitemap as $element) {
420 471 if (!isset($element->loc)) continue;
421 472
422 473 $sitemap_urls = $this->get_sitemap_urls($element->loc);
423 -
424 - if (is_array($sitemap_urls)) {
425 - $urls = array_merge($urls, $sitemap_urls);
426 - }
474 + $urls = array_merge($urls, $sitemap_urls);
427 475 }
428 476 }
429 477
430 478 return $urls;
@@ -434,9 +482,11 @@
434 482 * Get the path to a local sitemap file
435 483 *
436 484 * @return string
437 485 */
438 - private function get_local_sitemap_file() {
486 + protected function get_local_sitemap_file() {
487 + global $wp_file_descriptions; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Make the scope of $wp_file_descriptions global, so that when wp-admin/includes/file.php assigns to it, it is adjusting the global variable as intended
488 +
439 489 if (!function_exists('get_home_path')) {
440 490 include_once ABSPATH . '/wp-admin/includes/file.php';
441 491 }
442 492 return trailingslashit(get_home_path()) . $this->get_sitemap_filename();
@@ -475,9 +525,9 @@
475 525 $urls[] = $permalink;
476 526
477 527 // check page separators in the post content
478 528 preg_match_all('/\<\!--nextpage--\>/', $post->post_content, $matches);
479 - // if there any separators add urls for each page
529 + // if there are any separators add urls for each page
480 530 if (count($matches[0])) {
481 531 $prefix = strpos($permalink, '?') ? '&page=' : '';
482 532 for ($page = 0; $page < count($matches[0]); $page++) {
483 533 if ('' != $prefix) {
@@ -519,9 +569,9 @@
519 569 * @return bool
520 570 */
521 571 public function is_domain_mapping_enabled() {
522 572 // SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin.
523 - $enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE);
573 + $enabled = is_multisite() && defined('SUNRISE') && 'on' === strtolower(SUNRISE);
524 574
525 575 /**
526 576 * Filters if Multisite Domain mapping is enabled.
527 577 * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use.
@@ -526,9 +576,9 @@
526 576 * Filters if Multisite Domain mapping is enabled.
527 577 * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use.
528 578 * Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option.
529 579 */
530 - return apply_filters('wpo_is_domain_mapping_enabled', $enabled);
580 + return (bool) apply_filters('wpo_is_domain_mapping_enabled', $enabled);
531 581 }
532 582
533 583 /**
534 584 * Return mapped domain by $blog_id.
@@ -542,11 +592,11 @@
542 592
543 593 $domain = '';
544 594 $multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping';
545 595 // Check if table exists
546 - if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) {
596 + if ($wpdb->get_var("SHOW TABLES LIKE '" . esc_sql($multisite_plugin_table_name) . "'") != $multisite_plugin_table_name) {
547 597 // This table created in WordPress MU Domain Mapping plugin.
548 - $row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A);
598 + $row = $wpdb->get_row($wpdb->prepare("SELECT `domain` FROM " . esc_sql($multisite_plugin_table_name) . " WHERE `blog_id` = %d AND `active` = %d", $blog_id, 1), ARRAY_A);
549 599 if (!empty($row)) {
550 600 $domain = $row['domain'];
551 601 }
552 602 } else {
@@ -559,16 +609,17 @@
559 609 *
560 610 * @param string $domain The domain name
561 611 * @param integer $blog_id The blog ID
562 612 */
563 - return apply_filters('wpo_get_mapped_domain', $domain, $blog_id);
613 + $filtered_domain = apply_filters('wpo_get_mapped_domain', $domain, $blog_id);
614 + return is_string($filtered_domain) ? $filtered_domain : $domain;
564 615 }
565 616
566 617 /**
567 618 * Captures and logs any interesting messages
568 619 *
569 - * @param String $message - the error message
570 - * @param String $error_type - the error type
620 + * @param string $message - the error message
621 + * @param string $error_type - the error type
571 622 */
572 623 public function log($message, $error_type = 'info') {
573 624
574 625 if (isset($this->loggers)) {