PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.3
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.3
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
wp-optimize / cache / class-wpo-cache-preloader.php

class-wpo-cache-preloader.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.2.3, at cache/class-wpo-cache-preloader.php

704 lines 21.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access allowed');
4
5
6 if (!class_exists('WP_Optimize_Load_Url_Task')) require_once(dirname(__FILE__) . '/class-wpo-load-url-task.php');
7
8 if (!class_exists('WP_Optimize_Preloader')) require_once(WPO_PLUGIN_MAIN_PATH . 'includes/class-wpo-preloader.php');
9
10 class WP_Optimize_Page_Cache_Preloader extends WP_Optimize_Preloader {
11
12 protected $preload_type = 'page_cache';
13
14 protected $task_type = 'load-url-task';
15
16 static protected $_instance = null;
17
18 /**
19 * WP_Optimize_Page_Cache_Preloader constructor.
20 */
21 public function __construct() {
22 parent::__construct();
23
24 add_filter('cron_schedules', array($this, 'cron_add_intervals'));
25 add_action('wpo_page_cache_schedule_preload', array($this, 'run_scheduled_cache_preload'));
26 add_filter('wpo_preload_headers', array($this, 'preload_headers'));
27 }
28
29 /**
30 * Check if cache is active.
31 *
32 * @return bool
33 */
34 public function is_option_active() {
35 return WP_Optimize()->get_page_cache()->is_enabled();
36 }
37
38 /**
39 * Schedule or delete automatic preload action on cache settings update.
40 *
41 * @param array $new_settings The new settings
42 * @param array $previous_settings Settings before saving
43 */
44 public function cache_settings_updated($new_settings, $previous_settings) {
45 if (!$new_settings['enable_page_caching']) {
46 wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
47 $this->delete_preload_continue_action();
48 return;
49 }
50
51 if (!empty($new_settings['enable_schedule_preload'])) {
52
53 $last_schedule_type = $previous_settings['preload_schedule_type'];
54
55 if (wp_next_scheduled('wpo_page_cache_schedule_preload')) {
56 // if already scheduled this schedule type
57 if ($new_settings['preload_schedule_type'] == $last_schedule_type) {
58 // If the schedule type is cache lifespan, check if the cache lifespan changed.
59 if ('wpo_use_cache_lifespan' == $new_settings['preload_schedule_type']) {
60 // Else, if the settings cache lifespan settings haven't changed, returns
61 if ($new_settings['page_cache_length_value'] == $previous_settings['page_cache_length_value'] && $new_settings['page_cache_length_unit'] == $previous_settings['page_cache_length_unit']) {
62 return;
63 }
64 } else {
65 return;
66 }
67 }
68 // clear currently scheduled preload action.
69 wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
70 }
71 // schedule preload action.
72 wp_schedule_event((time() + $this->get_schedule_interval($new_settings['preload_schedule_type'])), $new_settings['preload_schedule_type'], 'wpo_page_cache_schedule_preload');
73 } else {
74 wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
75 }
76
77 }
78
79 /**
80 * Clear active preload tasks, reschedule preload action.
81 */
82 public function reschedule_preload() {
83 // clear scheduled action.
84 if (wp_next_scheduled('wpo_page_cache_schedule_preload')) {
85 wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
86 }
87
88 // schedule preload action if need.
89 if ($this->is_scheduled_preload_enabled()) {
90 $preload_schedule_type = $this->get_cache_config('preload_schedule_type');
91 wp_schedule_event(time() + $this->get_schedule_interval($preload_schedule_type), $preload_schedule_type, 'wpo_page_cache_schedule_preload');
92 }
93 }
94
95 /**
96 * Check if scheduled preload enabled.
97 *
98 * @return bool
99 */
100 public function is_scheduled_preload_enabled() {
101 $enable_schedule_preload = $this->get_cache_config('enable_schedule_preload');
102 return !empty($enable_schedule_preload);
103 }
104
105 /**
106 * Add intervals to cron schedules.
107 *
108 * @param array $schedules
109 *
110 * @return array
111 */
112 public function cron_add_intervals($schedules) {
113 $interval = $this->get_continue_preload_cron_interval();
114 $schedules['wpo_page_cache_preload_continue_interval'] = array(
115 'interval' => $interval,
116 'display' => round($interval / 60, 1).' minutes'
117 );
118
119 $schedules['wpo_use_cache_lifespan'] = array(
120 'interval' => WPO_Cache_Config::instance()->get_option('page_cache_length'),
121 'display' => 'Same as cache lifespan: '.WPO_Cache_Config::instance()->get_option('page_cache_length_value').' '.WPO_Cache_Config::instance()->get_option('page_cache_length_unit')
122 );
123
124 return $schedules;
125 }
126
127
128 /**
129 * Check if we need run cache preload and run it.
130 */
131 public function run_scheduled_cache_preload() {
132
133 $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type');
134 if (!$schedule_type) return;
135
136 // Don't run preload if cache lifespan option enabled and cache not expired yet.
137 if ('wpo_use_cache_lifespan' == $schedule_type) {
138
139 /**
140 * Filters the allowed time difference between the cache exiry and the current time, in seconds.
141 * If the cache expires in less than $allowed_time_difference, preload. Otherwise leave it.
142 *
143 * @param integer $allowed_time_difference The time difference, in seconds (default = 600)
144 */
145 $allowed_time_difference = apply_filters('wpo_preload_allowed_time_difference', 600);
146 $page_cache_lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length', 0);
147 $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload', 0);
148 $time_since_last_preload = time() - $last_preload_time;
149 $minimum_time_to_next_schedule_preload = $page_cache_lifespan - $allowed_time_difference;
150 // Skip this if the last preload is not as old as the cache lifespan minus $allowed_time_difference
151 if ($page_cache_lifespan > 0 && $time_since_last_preload < $minimum_time_to_next_schedule_preload) return;
152 }
153
154 $this->run();
155 }
156
157
158 /**
159 * Get cache config option value.
160 *
161 * @return mixed
162 */
163 public function get_cache_config($option) {
164 static $config = null;
165
166 if (null === $config) $config = WPO_Page_Cache::instance()->config->get();
167
168 if (is_array($config) && array_key_exists($option, $config)) {
169 return $config[$option];
170 }
171
172 return false;
173 }
174
175 /**
176 * Create tasks (WP_Optimize_Load_Url_Task) for preload all urls from site.
177 *
178 * @param string $type The preload type (currently: scheduled, manual)
179 * @return void
180 */
181 public function create_tasks_for_preload_site_urls($type) {
182 $urls = $this->get_site_urls();
183
184 if (!empty($urls)) {
185
186 $this->log(__('Creating tasks for preload site urls.', 'wp-optimize'));
187
188 foreach ($urls as $url) {
189 if (wpo_url_in_exceptions($url)) continue;
190
191 if ($this->url_is_already_cached($url, $type)) {
192 continue;
193 }
194
195 // this description is being used for internal purposes.
196 $description = 'Preload - '.$url;
197 $options = array('url' => $url, 'preload_type' => $type, 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI));
198
199 WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task');
200 }
201
202 $this->log(__('Tasks for preload site urls created.', 'wp-optimize'));
203 }
204 }
205
206 /**
207 * Preload mobile version from $url.
208 *
209 * @param string $url
210 *
211 * @return void
212 */
213 public function preload_mobile($url) {
214 static $is_mobile_caching_enabled;
215 if (!isset($is_mobile_caching_enabled)) {
216 $is_mobile_caching_enabled = $this->get_cache_config('enable_mobile_caching');
217 }
218
219 // Only run if option is active
220 if (!$is_mobile_caching_enabled) return;
221
222 $mobile_args = array(
223 'httpversion' => '1.1',
224 'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
225 'timeout' => 10,
226 'headers' => apply_filters('wpo_preload_headers', array()),
227 );
228
229 $mobile_args = apply_filters('wpo_page_cache_preloader_mobile_args', $mobile_args, $url);
230
231 $this->log('preload_mobile - ' . $url);
232
233 wp_remote_get($url, $mobile_args);
234 }
235
236 /**
237 * Preload amp version from $url.
238 *
239 * @param string $url
240 *
241 * @return void
242 */
243 public function preload_amp($url) {
244 if (!apply_filters('wpo_should_preload_amp', false, $url)) return;
245
246 $amp_args = array(
247 'httpversion' => '1.1',
248 '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',
249 'timeout' => 10,
250 'headers' => array(
251 'X-WP-Optimize-Cache-Preload' => 'Yes',
252 ),
253 );
254
255 $url = untrailingslashit($url) . '/amp/';
256
257 $amp_args = apply_filters('wpo_page_cache_preloader_amp_args', $amp_args, $url);
258
259 $this->log('preload_amp - ' . $url);
260
261 wp_remote_get($url, $amp_args);
262 }
263
264 /**
265 * Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls.
266 *
267 * @return array
268 */
269 public function get_site_urls() {
270
271 $urls = $this->get_sitemap_urls();
272
273 if (!empty($urls)) {
274 $this->options->update_option('wpo_last_page_cache_preload_type', 'sitemap');
275 } else {
276 $urls = $this->get_post_urls();
277 $this->options->update_option('wpo_last_page_cache_preload_type', 'posts');
278 }
279
280 $this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls)));
281
282 /**
283 * Filter the URLs which will be preloaded
284 *
285 * @param array $urls
286 * @return array
287 */
288 return apply_filters('wpo_preload_get_site_urls', $urls);
289 }
290
291 /**
292 * Loads sitemap file and returns list of urls.
293 *
294 * @param string $sitemap_url
295 *
296 * @return array|bool
297 */
298 public function get_sitemap_urls($sitemap_url = '') {
299
300 $urls = array();
301
302 // if sitemap url is empty then use main sitemap file name.
303 $sitemap_url = ('' === $sitemap_url) ? site_url('/'.$this->get_sitemap_filename()) : $sitemap_url;
304
305 // if simplexml_load_string not available then we don't load sitemap.
306 if (!function_exists('simplexml_load_string')) {
307 return $urls;
308 }
309
310 // load sitemap file.
311 $response = wp_remote_get($sitemap_url, array('timeout' => 30));
312
313 // if we get error then
314 if (is_wp_error($response)) {
315 $response = file_get_contents($sitemap_url);
316
317 // if response is empty then try load from file.
318 if (empty($response) && '' == $sitemap_url) {
319 $sitemap_file = $this->get_local_sitemap_file();
320
321 $response = file_get_contents($sitemap_file);
322 }
323
324 if (empty($response)) return $urls;
325
326 $xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
327 } else {
328 // parse xml answer.
329 $xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
330 }
331
332 // xml file has not valid xml content then return false.
333 if (false === $xml) return false;
334
335 // if exists urls then return them.
336 if (isset($xml->url)) {
337 foreach ($xml->url as $element) {
338 if (!isset($element->loc)) continue;
339 $urls[] = (string) $element->loc;
340 }
341 } elseif (isset($xml->sitemap)) {
342 // if has links to other sitemap files then get urls from them.
343 foreach ($xml->sitemap as $element) {
344 if (!isset($element->loc)) continue;
345
346 $sitemap_urls = $this->get_sitemap_urls($element->loc);
347
348 if (is_array($sitemap_urls)) {
349 $urls = array_merge($urls, $sitemap_urls);
350 }
351 }
352 }
353
354 return $urls;
355 }
356
357 /**
358 * Get the path to a local sitemap file
359 *
360 * @return string
361 */
362 private function get_local_sitemap_file() {
363 if (!function_exists('get_home_path')) {
364 include_once ABSPATH . '/wp-admin/includes/file.php';
365 }
366 return trailingslashit(get_home_path()) . $this->get_sitemap_filename();
367 }
368
369 /**
370 * Get all posts of any post type and returns urls for them.
371 *
372 * @return array
373 */
374 public function get_post_urls() {
375 global $post;
376
377 $offset = 0;
378 $posts_per_page = 1000;
379 $urls = array();
380
381 $urls[] = site_url('/');
382
383 do {
384 $query = new WP_Query(array(
385 'post_type' => 'any',
386 'post_status' => 'publish',
387 'posts_per_page' => $posts_per_page,
388 'offset' => $offset,
389 'orderby' => 'ID',
390 'order' => 'ASC',
391 'cache_results' => false, // disable cache to avoid memory error.
392 ));
393
394 $posts_loaded = $query->post_count;
395
396 while ($query->have_posts()) {
397 $query->the_post();
398 $permalink = get_permalink();
399 $urls[] = $permalink;
400
401 // check page separators in the post content
402 preg_match_all('/\<\!--nextpage--\>/', $post->post_content, $matches);
403 // if there any separators add urls for each page
404 if (count($matches[0])) {
405 $prefix = strpos($permalink, '?') ? '&page=' : '';
406 for ($page = 0; $page < count($matches[0]); $page++) {
407 if ('' != $prefix) {
408 $urls[] = $permalink . $prefix . ($page+2);
409 } else {
410 $urls[] = trailingslashit($permalink) . ($page+2);
411 }
412 }
413 }
414 }
415
416 $offset += $posts_loaded;
417 } while ($posts_loaded > 0);
418
419 /**
420 * If domain mapping enabled then replace domains in urls.
421 */
422 if ($this->is_domain_mapping_enabled()) {
423 $blog_id = get_current_blog_id();
424
425 $mapped_domain = $this->get_mapped_domain($blog_id);
426 $blog_details = get_blog_details($blog_id);
427
428 if ($mapped_domain) {
429 foreach ($urls as $i => $url) {
430 $urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1);
431 }
432 }
433 }
434
435 wp_reset_postdata();
436
437 return $urls;
438 }
439
440 /**
441 * Check if domain mapping enabled.
442 *
443 * @return bool
444 */
445 public function is_domain_mapping_enabled() {
446 // SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin.
447 $enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE);
448
449 /**
450 * Filters if Multisite Domain mapping is enabled.
451 * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use.
452 * Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option.
453 */
454 return apply_filters('wpo_is_domain_mapping_enabled', $enabled);
455 }
456
457 /**
458 * Return mapped domain by $blog_id.
459 *
460 * @param int $blog_id
461 *
462 * @return string
463 */
464 public function get_mapped_domain($blog_id) {
465 global $wpdb;
466
467 $domain = '';
468 $multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping';
469 // Check if table exists
470 if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) {
471 // This table created in WordPress MU Domain Mapping plugin.
472 $row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A);
473 if (!empty($row)) {
474 $domain = $row['domain'];
475 }
476 } else {
477 // When using the WP Core method, the site url option contains the mapped domain.
478 $domain = get_site_url($blog_id);
479 }
480
481 /**
482 * Filters the mapped domain name
483 *
484 * @param string $domain The domain name
485 * @param integer $blog_id The blog ID
486 */
487 return apply_filters('wpo_get_mapped_domain', $domain, $blog_id);
488 }
489
490 /**
491 * Captures and logs any interesting messages
492 *
493 * @param String $message - the error message
494 * @param String $error_type - the error type
495 */
496 public function log($message, $error_type = 'info') {
497
498 if (isset($this->loggers)) {
499 foreach ($this->loggers as $logger) {
500 $logger->log($message, $error_type);
501 }
502 }
503 }
504
505 /**
506 * Instance of WP_Optimize_Page_Cache_Preloader.
507 *
508 * @return WP_Optimize_Page_Cache_Preloader
509 */
510 public static function instance() {
511 if (empty(self::$_instance)) {
512 self::$_instance = new WP_Optimize_Page_Cache_Preloader();
513 }
514
515 return self::$_instance;
516 }
517
518 /**
519 * Check if the URL is already cached, or needs to be preloaded
520 *
521 * @param string $url The preloaded url
522 * @param string $preload_type The preload type (manual | scheduled)
523 * @return boolean
524 */
525 private function url_is_already_cached($url, $preload_type) {
526 static $files = array();
527 $regenerate_count = 0;
528 $folder = trailingslashit(WPO_CACHE_FILES_DIR) . wpo_get_url_path($url);
529 // If the folder does not exist, consider the URL as cleared
530 if (!is_dir($folder)) return false;
531
532 if (empty($files)) {
533 // Check only the base files
534 $files[] = 'index.html';
535
536 if (WPO_Cache_Config::instance()->get_option('enable_mobile_caching')) {
537 $files[] = 'mobile.index.html';
538 }
539 $files = apply_filters('wpo_maybe_clear_files_list', $files);
540 }
541
542 foreach ($files as $file) {
543 $file_path = trailingslashit($folder).$file;
544 if (!file_exists($file_path)) {
545 // The file does not exist, count it as "deleted"
546 $regenerate_count++;
547 continue;
548 }
549
550 if ($this->should_regenerate_file($file_path, $preload_type)) {
551 // delefe the expired cache file
552 unlink($file_path);
553 $regenerate_count++;
554 }
555 }
556
557 // if 0 == $regenerate_count, nothing all the expected files exist, and none were deleted.
558 return 0 == $regenerate_count;
559 }
560
561 /**
562 * Determine if a file should be regenerated
563 *
564 * @param string $path The file to check
565 * @param string $preload_type The preload type (manual | scheduled)
566 *
567 * @return boolean
568 */
569 private function should_regenerate_file($path, $preload_type) {
570 // Store the variables, as they'll be used for each file and each file
571 static $is_preloader_scheduled = null;
572 static $lifespan = null;
573 static $schedule_type = null;
574 static $schedule_interval = null;
575 static $lifespan_expiry_threshold = null;
576 static $always_regenerate_file_if_preload_is_manual = null;
577 static $always_regenerate_file_if_preload_is_scheduled = null;
578 static $regenerate_file_when_no_expiry_date = null;
579
580 // Sets the variables once per request:
581 if (null === $is_preloader_scheduled) {
582 $is_preloader_scheduled = WPO_Cache_Config::instance()->get_option('enable_schedule_preload');
583 $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type');
584 $lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length');
585 $schedule_interval = $this->get_schedule_interval($schedule_type);
586
587 /**
588 * Expiry threshold: the current file will be considered stale if within the threshold. Default: 600s (10min)
589 */
590 $lifespan_expiry_threshold = apply_filters('wpo_lifespan_expiry_threshold', 600);
591
592 /**
593 * Filters if a cache should systematically be regenerated when running a manual preload. Default: false
594 */
595 $always_regenerate_file_if_preload_is_manual = apply_filters('wpo_always_regenerate_file_if_preload_is_manual', false);
596
597 /**
598 * Filters if a cache should systematically be regenerated when running a scheduled preload. Default: false
599 */
600 $always_regenerate_file_if_preload_is_scheduled = apply_filters('wpo_always_regenerate_file_if_preload_is_scheduled', false);
601
602 /**
603 * Filters if a cache should systematically be regenerated when running a preload and no schedule is set, and cache does not expire. Default: true
604 */
605 $regenerate_file_when_no_expiry_date = apply_filters('wpo_regenerate_file_when_no_expiry_date', true);
606 }
607
608 if (($always_regenerate_file_if_preload_is_manual && 'manual' == $preload_type) || ($always_regenerate_file_if_preload_is_scheduled && 'scheduled' == $preload_type)) {
609 $result = true;
610 } else {
611
612 $modified_time = (int) filemtime($path);
613
614 // cache lifespan is set.
615 if (0 != $lifespan) {
616 $expiry_time = $modified_time + $lifespan - $lifespan_expiry_threshold;
617 $result = time() > $expiry_time;
618 } elseif ($is_preloader_scheduled) {
619 $expiry_time = $modified_time + $schedule_interval - $lifespan_expiry_threshold;
620 $result = time() > $expiry_time;
621 } else {
622 $result = $regenerate_file_when_no_expiry_date;
623 }
624
625 }
626
627 return apply_filters('wpo_preloader_should_regenerate_file', $result, $path, $preload_type);
628 }
629
630 /**
631 * Add preloader headers
632 */
633 public function preload_headers($headers) {
634 $headers['X-WP-Optimize-Cache-Preload'] = 'Yes';
635 return $headers;
636 }
637
638 /**
639 * Option disabled error message
640 *
641 * @return array
642 */
643 protected function get_option_disabled_error() {
644 return array(
645 'success' => false,
646 'error' => __('Page cache is disabled.', 'wp-optimize')
647 );
648 }
649
650 /**
651 * Get preload already running error message
652 *
653 * @return array
654 */
655 protected function get_preload_already_running_error() {
656 return array(
657 'success' => false,
658 'error' => __('Probably page cache preload is running already.', 'wp-optimize')
659 );
660 }
661
662 protected function get_preload_data() {
663 return WP_Optimize()->get_page_cache()->get_cache_size();
664 }
665
666 protected function get_preloading_message($cache_size) {
667 return array(
668 'done' => false,
669 'message' => __('Loading URLs...', 'wp-optimize'),
670 'size' => WP_Optimize()->format_size($cache_size['size']),
671 'file_count' => $cache_size['file_count']
672 );
673 }
674
675 protected function get_last_preload_message($cache_size, $last_preload_time_str) {
676 return array(
677 'done' => true,
678 'message' => sprintf(__('Last preload finished at %s', 'wp-optimize'), $last_preload_time_str),
679 'size' => WP_Optimize()->format_size($cache_size['size']),
680 'file_count' => $cache_size['file_count']
681 );
682 }
683
684 protected function get_preload_success_message($cache_size) {
685 return array(
686 'done' => true,
687 'size' => WP_Optimize()->format_size($cache_size['size']),
688 'file_count' => $cache_size['file_count']
689 );
690 }
691
692 protected function get_preload_progress_message($cache_size, $preloaded_message, $preload_resuming_in) {
693 return array(
694 'done' => false,
695 'message' => $preloaded_message,
696 'size' => WP_Optimize()->format_size($cache_size['size']),
697 'file_count' => $cache_size['file_count'],
698 'resume_in' => $preload_resuming_in
699 );
700 }
701 }
702
703 WP_Optimize_Page_Cache_Preloader::instance();
704