PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.22
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.22
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-page-cache.php

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

1,472 lines 45.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Page caching functionality
4 *
5 * Acknowledgement: The page cache functionality was loosely based on the simple cache plugin - https://github.com/tlovett1/simple-cache
6 */
7
8 if (!defined('ABSPATH')) die('No direct access allowed');
9
10 /**
11 * Base cache directory, everything else goes under here
12 */
13 if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache');
14
15 /**
16 * Extensions directory.
17 */
18 if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions');
19
20 /**
21 * Directory that stores config and related files
22 */
23 if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config');
24
25 /**
26 * Directory that stores the cache, including gzipped files and mobile specific cache
27 */
28 if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache');
29
30 require_once dirname(__FILE__) . '/file-based-page-cache-functions.php';
31
32 if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
33 require_once dirname(__FILE__) . '/php-5.3-functions.php';
34 }
35
36 wpo_cache_load_extensions();
37
38 if (!class_exists('WPO_Page_Cache')) :
39
40 class WPO_Page_Cache {
41
42 /**
43 * Cache config object
44 *
45 * @var mixed
46 */
47 public $config;
48
49 /**
50 * Logger for this class
51 *
52 * @var mixed
53 */
54 public $logger;
55
56 /**
57 * Instance of this class
58 *
59 * @var mixed
60 */
61 public static $instance;
62
63 /**
64 * Store last advanced cache file writing status
65 * If true then last writing finished with error
66 *
67 * @var bool
68 */
69 public $advanced_cache_file_writing_error;
70
71 /**
72 * Store errors
73 *
74 * @var array
75 */
76 private $_errors = array();
77
78 /**
79 * Last advanced cache file content
80 *
81 * @var string
82 */
83 public $advanced_cache_file_content;
84
85 /**
86 * Store the latest advanced-cache.php version required
87 *
88 * @var string
89 */
90 private $_minimum_advanced_cache_file_version = '3.0.17';
91
92 public $should_purge;
93
94 /**
95 * Set everything up here
96 */
97 public function __construct() {
98 $this->config = WPO_Cache_Config::instance();
99 WPO_Cache_Rules::instance();
100 $this->logger = new Updraft_PHP_Logger();
101
102 add_action('activated_plugin', array($this, 'activate_deactivate_plugin'));
103 add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin'));
104 add_action('wpo_purge_old_cache', array($this, 'purge_old'));
105
106 /**
107 * Regenerate config file on cache flush.
108 */
109 add_action('wpo_cache_flush', array($this, 'update_cache_config'));
110 add_action('wpo_cache_flush', array($this, 'delete_cache_size_information'));
111 add_action('update_option_permalink_structure', array($this, 'update_option_permalink_structure'), 10, 3);
112
113 // Add purge cache link to admin bar.
114 add_filter('wpo_cache_admin_bar_menu_items', array($this, 'admin_bar_purge_cache'), 20, 1);
115
116 // Handle single page purge.
117 add_action('wp_loaded', array($this, 'handle_purge_single_page_cache'));
118
119 add_action('admin_init', array($this, 'admin_init'));
120
121 add_action('update_option_gmt_offset', array($this, 'update_gmt_offset_timezone_string_config'), 10, 3);
122 add_action('update_option_timezone_string', array($this, 'update_gmt_offset_timezone_string_config'), 10, 3);
123 add_action('update_option_date_format', array($this, 'update_option_date_format'), 10, 2);
124 add_action('update_option_time_format', array($this, 'update_option_time_format'), 10, 2);
125
126 $this->check_compatibility_issues();
127
128 add_filter('cron_schedules', array($this, 'cron_schedules'));
129 add_action('wpo_save_images_settings', array($this, 'update_webp_images_option'));
130 }
131
132 /**
133 * Activate cron job for deleting expired cache files
134 */
135 public function cron_activate() {
136 $page_cache_length = $this->config->get_option('page_cache_length');
137 if (!wp_next_scheduled('wpo_purge_old_cache')) {
138 wp_schedule_event(time() + (false === $page_cache_length ? '86400' : $page_cache_length), 'wpo_purge_old_cache', 'wpo_purge_old_cache');
139 }
140 }
141
142 /**
143 * Do required actions on activate/deactivate any plugin.
144 */
145 public function activate_deactivate_plugin() {
146
147 wp_clear_scheduled_hook('wpo_purge_old_cache');
148
149 $this->update_cache_config();
150
151 $this->purge();
152 }
153
154 /**
155 * Check if current user can purge cache.
156 *
157 * @return bool
158 */
159 public function can_purge_cache() {
160 if (!$this->is_enabled()) return false;
161 $required_capability = is_multisite() ? 'manage_network_options' : 'manage_options';
162
163 if (WP_Optimize::is_premium()) {
164 return current_user_can($required_capability) || WP_Optimize_Premium()->can_purge_the_cache();
165 } else {
166 return current_user_can($required_capability);
167 }
168 }
169
170 /**
171 * Add Purge from cache in admin bar.
172 *
173 * @param array $menu_items
174 * @return array
175 */
176 public function admin_bar_purge_cache($menu_items) {
177 global $pagenow;
178 if (!$this->can_purge_cache()) return $menu_items;
179
180 $act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged'));
181
182 $cache_size = $this->get_cache_size();
183 $cache_size_info = '<h4>'.__('Page cache', 'wp-optimize').'</h4>';
184 $cache_size_info .= '<span>'.__('Cache size:', 'wp-optimize').' '. WP_Optimize()->format_size($cache_size['size']).' '.sprintf(__('(%d files)', 'wp-optimize'), $cache_size['file_count']).'</span>';
185
186 $menu_items[] = array(
187 'id' => 'wpo_cache_stats',
188 'title' => $cache_size_info,
189 'meta' => array(
190 'class' => 'wpo-cache-stats',
191 ),
192 'parent' => 'wpo_purge_cache',
193 );
194
195 $menu_items[] = array(
196 'id' => 'wpo_purge_all_pages_cache',
197 'title' => __('Purge cache for all pages', 'wp-optimize'),
198 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url),
199 'meta' => array(
200 'title' => __('Purge cache for all pages', 'wp-optimize'),
201 ),
202 'parent' => 'wpo_purge_cache',
203 );
204
205 if (!is_admin() || 'post.php' == $pagenow) {
206 $menu_items[] = array(
207 'id' => 'wpo_purge_this_page_cache',
208 'title' => __('Purge cache for this page', 'wp-optimize'),
209 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url),
210 'meta' => array(
211 'title' => __('Purge cache for this page', 'wp-optimize'),
212 ),
213 'parent' => 'wpo_purge_cache',
214 );
215 }
216
217 return $menu_items;
218
219 }
220
221 /**
222 * Check if purge single page action sent and purge cache.
223 */
224 public function handle_purge_single_page_cache() {
225
226 if (!$this->can_purge_cache()) return;
227
228 if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) {
229 if (isset($_GET['wpo_single_page_cache_purged'])) {
230 $notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error';
231 } else {
232 $notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error';
233 }
234
235 add_action('admin_notices', array($this, $notice_function));
236
237 return;
238 }
239
240 if (!isset($_GET['_wpo_purge'])) return;
241
242 if (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_single_page_cache')) {
243 $success = false;
244
245 if (is_admin()) {
246 $post = isset($_GET['post']) ? (int) $_GET['post'] : 0;
247 if ($post > 0) {
248 $success = self::delete_single_post_cache($post);
249 }
250 } else {
251 $success = self::delete_cache_by_url(wpo_current_url());
252 }
253
254 // remove nonce from url and reload page.
255 wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge')));
256 exit;
257
258 } elseif (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_all_pages_cache')) {
259 $success = self::purge();
260
261 // remove nonce from url and reload page.
262 wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge')));
263 exit;
264 }
265 }
266
267 /**
268 * Show notification when page cache purged successfully.
269 */
270 public function notice_purge_single_page_cache_success() {
271 $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success');
272 }
273
274 /**
275 * Show notification when page cache wasn't purged.
276 */
277 public function notice_purge_single_page_cache_error() {
278 $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error');
279 }
280
281 /**
282 * Show notification when all pages cache purged successfully.
283 */
284 public function notice_purge_all_pages_cache_success() {
285 $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success');
286 }
287
288 /**
289 * Show notification when all pages cache wasn't purged.
290 */
291 public function notice_purge_all_pages_cache_error() {
292 $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error');
293 }
294
295 /**
296 * Show notification in WordPress admin.
297 *
298 * @param string $message HTML (no further escaping is performed)
299 * @param string $type error, warning, success, or info
300 */
301 public function show_notice($message, $type) {
302 global $current_screen;
303
304 if ($current_screen && is_callable(array($current_screen, 'is_block_editor')) && $current_screen->is_block_editor()) : ?>
305 <script>
306 window.addEventListener('load', function() {
307 (function(wp) {
308 if (window.wp && wp.hasOwnProperty('data') && 'function' == typeof wp.data.dispatch) {
309 wp.data.dispatch('core/notices').createNotice(
310 '<?php echo $type; ?>',
311 '<?php echo $message; ?>',
312 {
313 isDismissible: true,
314 }
315 );
316 }
317 })(window.wp);
318 });
319 </script>
320 <?php else : ?>
321 <div class="notice wpo-notice notice-<?php echo $type; ?> is-dismissible">
322 <p><?php echo $message; ?></p>
323 </div>
324 <?php
325 endif;
326 }
327
328 /**
329 * Enables page cache
330 *
331 * @param bool $force_enable - Force regenerating everything. E.g. we want to do that when saving the settings
332 *
333 * @return WP_Error|bool - true on success, error otherwise
334 */
335 public function enable($force_enable = false) {
336 static $already_ran_enable = false;
337
338 if ($already_ran_enable) return $already_ran_enable;
339
340 $folders_created = $this->create_folders();
341 if (is_wp_error($folders_created)) {
342 $already_ran_enable = $folders_created;
343 return $already_ran_enable;
344 }
345
346 if (!file_exists($this->config->get_config_file_path())) {
347 $result = $this->update_cache_config();
348 if (is_wp_error($result)) return $result;
349 }
350
351 // if WPO_ADVANCED_CACHE isn't set, or environment doesn't contain the right constant, force regeneration
352 if (!defined('WPO_ADVANCED_CACHE') || !defined('WP_CACHE')) {
353 $force_enable = true;
354 }
355
356 $this->maybe_regenerate_cache_config_file();
357
358 if (!$force_enable) {
359 $already_ran_enable = true;
360 return true;
361 }
362
363 if (!$this->write_advanced_cache() && version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<')) {
364 $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename()));
365 $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize');
366
367 if (!defined('WP_CLI') || !WP_CLI) {
368 $message .= "\n\n1. ".sprintf(__('Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename())));
369 $message .= "\n2. ".__('Edit or create a file with the name advanced-cache.php', 'wp-optimize');
370 $message .= "\n3. ".__('Copy and paste the following lines into the file:', 'wp-optimize');
371 }
372
373 $already_ran_enable = new WP_Error("write_advanced_cache", $message);
374 return $already_ran_enable;
375 }
376
377 if (!$this->write_wp_config(true)) {
378 $already_ran_enable = new WP_Error("write_wp_config", "Could not turn on the WP_CACHE constant in wp-config.php. Check your permissions.");
379 return $already_ran_enable;
380 }
381
382 if (!$this->verify_cache()) {
383 $errors = $this->get_errors();
384 $already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled: \n".implode("\n- ", $errors));
385 return $already_ran_enable;
386 }
387
388 $already_ran_enable = true;
389
390 return true;
391 }
392
393 /**
394 * Disables page cache
395 *
396 * @return bool - true on success, false otherwise
397 */
398 public function disable() {
399 $ret = true;
400
401 $advanced_cache_file = $this->get_advanced_cache_filename();
402
403 // N.B. The only use of WP_CACHE in WP core is to include('advanced-cache.php') (and run a function if it's then defined); so, if the decision to leave it enable is, for some unexpected reason, technically incorrect, it still can't cause a problem.
404 $disabled_wp_config = $this->write_wp_config(false);
405 if (!$disabled_wp_config) {
406 $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH);
407 $action = "deactivate_".$plugin_basename."/wp-optimize.php";
408 if (current_action() === $action) {
409 $cache_config = WPO_Cache_Config::instance()->config;
410 $cache_config['enable_page_caching'] = false;
411 WPO_Cache_Config::instance()->update($cache_config, true);
412 }
413 $this->log("Could not turn off the WP_CACHE constant in wp-config.php");
414 $this->add_warning('error_disabling', __('Could not turn off the WP_CACHE constant in wp-config.php', 'wp-optimize'));
415 }
416
417 $disabled_advanced_cache = true;
418 // First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed')
419 // We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php
420 if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) {
421 if (file_exists($advanced_cache_file) && (!unlink($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) {
422 $disabled_advanced_cache = false;
423 $this->log("The request to the filesystem to remove or empty advanced-cache.php failed");
424 $this->add_warning('error_disabling', __('The request to the filesystem to remove or empty advanced-cache.php failed', 'wp-optimize'));
425 }
426 }
427
428 // If both actions failed, the cache wasn't disabled. So we send an error. If only one succeeds, it will still be disabled.
429 if (!$disabled_wp_config && !$disabled_advanced_cache) {
430 $ret = new WP_Error('error_disabling_cache', __('The page caching could not be disabled: the WP_CACHE constant could not be removed from wp-config.php and the request to the filesystem to remove or empty advanced-cache.php failed.', 'wp-optimize'));
431 }
432
433 // Delete cache to avoid stale cache on next activation
434 $this->purge();
435
436 return $ret;
437 }
438
439
440 /**
441 * Purges the cache
442 *
443 * @return bool - true on success, false otherwise
444 */
445 public function purge() {
446 /**
447 * Filters whether activating / deactivating a plugin will purge the cache.
448 */
449 $this->should_purge = apply_filters('wpo_purge_page_cache_on_activate_deactivate_plugin', true);
450 $purge_actions = array(
451 'deactivate_' . plugin_basename(WPO_PLUGIN_MAIN_PATH . 'wp-optimize.php'),
452 'deactivate_plugin',
453 'activated_plugin',
454 );
455 $is_deactivation_action = in_array(current_action(), $purge_actions, true);
456 if ($is_deactivation_action && !$this->should_purge) return false;
457
458 if (!self::delete(WPO_CACHE_FILES_DIR)) {
459 $this->log("The request to the filesystem to delete the cache failed");
460 return false;
461 }
462
463 /**
464 * Fires after purging the cache
465 */
466 do_action('wpo_cache_flush');
467
468 return true;
469 }
470
471 /**
472 * Purge cache files older than cache life span
473 *
474 * @return array Log messages.
475 */
476 public function purge_old() {
477 $log = array();
478 $page_cache_length = $this->config->get_option('page_cache_length');
479 if (0 === $page_cache_length) return $log;
480 $expires = time() - $page_cache_length;
481 $cache_folder = WPO_CACHE_FILES_DIR . '/' . str_ireplace(array('http://', 'https://'), '', get_site_url());
482 // get all directories that are a direct child of current directory
483 if (is_dir($cache_folder) && is_writable($cache_folder)) {
484 if ($handle = opendir($cache_folder)) {
485 while (false !== ($d = readdir($handle))) {
486 if (0 == strcmp($d, '.') || 0 == strcmp($d, '..')) {
487 continue;
488 }
489
490 if ($this->is_front_page_cache($d)) {
491 $modified_time = (int) filemtime("$cache_folder/$d");
492 if ($modified_time <= $expires) {
493 unlink("$cache_folder/$d");
494 }
495 continue;
496 }
497
498 $dir = $cache_folder.'/'.$d;
499 if (!is_dir($dir)) continue;
500
501 $stat = stat($dir);
502 $modified_time = $stat['mtime'];
503 $log[] = "checking if cache has expired - $d";
504 if ($modified_time <= $expires) {
505 $log[] = "deleting cache in $dir";
506 wpo_delete_files($dir, true);
507 if (file_exists($dir)) rmdir($dir);
508 }
509 }
510 closedir($handle);
511 }
512 }
513 return $log;
514 }
515
516 /**
517 * Finds out given cache file is of front page or not
518 *
519 * @return bool
520 */
521 private function is_front_page_cache($d) {
522 return in_array($d, array('index.html', 'index.html.gz'));
523 }
524
525 /**
526 * Purges the cache
527 *
528 * @return bool - true on success, false otherwise
529 */
530 public function clean_up() {
531
532 $this->disable();
533
534 if (!self::delete(WPO_CACHE_DIR, true)) {
535 $this->log("The request to the filesystem to clean up the cache failed");
536 return false;
537 }
538
539 return true;
540 }
541
542 /**
543 * Check if cache is enabled and working
544 *
545 * @return bool - true on success, false otherwise
546 */
547 public function is_enabled() {
548
549 if (!$this->config->get_option('enable_page_caching')) return false;
550
551 if (!defined('WP_CACHE') || !WP_CACHE) {
552 if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) {
553 $this->log("WP_CACHE constant is not present in wp-config.php");
554 return false;
555 }
556 }
557
558 if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) {
559 if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) {
560 $this->log("WPO_ADVANCED_CACHE constant is not present in advanced-cache.php");
561 return false;
562 }
563 }
564
565 $config_file = WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename();
566 if (!file_exists($config_file)) {
567 if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) {
568 $this->log("Cache config file $config_file is not present");
569 return false;
570 }
571 }
572
573 return true;
574 }
575
576 /**
577 * Create the folder structure needed for cache to work
578 *
579 * @return bool - true on success, false otherwise
580 */
581 public function create_folders() {
582 $permissions_str = __('Please check your file permissions.', 'wp-optimize');
583
584 if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) {
585 return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s.', 'wp-optimize'), str_ireplace(ABSPATH, '', WPO_CACHE_DIR)) .' '. $permissions_str);
586 }
587
588 if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) {
589 return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s.', 'wp-optimize'), str_ireplace(ABSPATH, '', WPO_CACHE_CONFIG_DIR)) .' '. $permissions_str);
590 }
591
592 if (!is_dir(WPO_CACHE_FILES_DIR)) {
593 if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) {
594 return new WP_Error('create_folders', sprintf(__('The request to the filesystem failed: unable to create directory %s.', 'wp-optimize'), str_ireplace(ABSPATH, '', WPO_CACHE_FILES_DIR)) .' '. $permissions_str);
595 } else {
596 wpo_disable_cache_directories_viewing();
597 }
598 }
599
600 return true;
601 }
602
603 /**
604 * Get advanced-cache.php file name with full path.
605 *
606 * @return string
607 */
608 public function get_advanced_cache_filename() {
609 return untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php';
610 }
611
612 /**
613 * Writes advanced-cache.php
614 *
615 * @param boolean $update_required - Whether the update is required or not.
616 * @return bool
617 */
618 private function write_advanced_cache($update_required = false) {
619 $config_file_basename = $this->config->get_cache_config_filename();
620 $cache_file_basename = untrailingslashit(plugin_dir_path(__FILE__));
621 $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH);
622 $cache_path = '/wpo-cache';
623 $cache_files_path = '/cache/wpo-cache';
624 $cache_extensions_path = WPO_CACHE_EXT_DIR;
625 $wpo_version = WPO_VERSION;
626 $wpo_home_url = trailingslashit(home_url());
627
628 // CS does not like heredoc
629 // phpcs:disable
630 $this->advanced_cache_file_content = <<<EOF
631 <?php
632
633 if (!defined('ABSPATH')) die('No direct access allowed');
634
635 // WP-Optimize advanced-cache.php (written by version: $wpo_version) (do not change this line, it is used for correctness checks)
636
637 if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true);
638
639 \$possible_plugin_locations = array(
640 defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR.'/$plugin_basename/cache' : false,
641 defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR.'/plugins/$plugin_basename/cache' : false,
642 dirname(__FILE__).'/plugins/$plugin_basename/cache',
643 '$cache_file_basename',
644 );
645
646 \$plugin_location = false;
647
648 foreach (\$possible_plugin_locations as \$possible_location) {
649 if (false !== \$possible_location && @file_exists(\$possible_location.'/file-based-page-cache.php')) {
650 \$plugin_location = \$possible_location;
651 break;
652 }
653 }
654
655 if (false === \$plugin_location) {
656 if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', true);
657 \$protocol = \$_SERVER['REQUEST_SCHEME'];
658 \$host = \$_SERVER['HTTP_HOST'];
659 \$request_uri = \$_SERVER['REQUEST_URI'];
660 if (strcasecmp('$wpo_home_url', \$protocol . '://' . \$host . \$request_uri) === 0) {
661 error_log('WP-Optimize: No caching took place, because the plugin location could not be found');
662 }
663 } else {
664 if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', false);
665 }
666
667 if (is_admin()) { return; }
668
669 if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', WP_CONTENT_DIR.'$cache_path');
670 if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config');
671 if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WP_CONTENT_DIR.'$cache_files_path');
672 if (false !== \$plugin_location) {
673 if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', \$plugin_location.'/extensions');
674 } else {
675 if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path');
676 }
677
678 if (!@file_exists(WPO_CACHE_CONFIG_DIR . '/$config_file_basename')) { return; }
679
680 \$GLOBALS['wpo_cache_config'] = @json_decode(file_get_contents(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'), true);
681
682 if (empty(\$GLOBALS['wpo_cache_config'])) {
683 include_once(WPO_CACHE_CONFIG_DIR . '/$config_file_basename');
684 }
685
686 if (empty(\$GLOBALS['wpo_cache_config'])) {
687 error_log('WP-Optimize: Caching failed because the configuration data could not be loaded from the config file.');
688 return;
689 }
690
691 if (empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; }
692
693 if (false !== \$plugin_location) { include_once(\$plugin_location.'/file-based-page-cache.php'); }
694
695 EOF;
696
697 // phpcs:enable
698 $advanced_cache_filename = $this->get_advanced_cache_filename();
699
700 // If the file content is already up to date, success
701 if (is_file($advanced_cache_filename) && file_get_contents($advanced_cache_filename) === $this->advanced_cache_file_content) {
702 $this->advanced_cache_file_writing_error = false;
703 return true;
704 }
705
706 // check if we can't write the advanced cache file
707 // case 1: the directory is read-only and the file doesn't exist
708 if (!is_file($advanced_cache_filename) && !is_writable(dirname($advanced_cache_filename))) {
709 $this->advanced_cache_file_writing_error = true;
710 return false;
711 }
712
713 // case 2: the file already exists but it's read-only
714 if (is_file($advanced_cache_filename) && !is_writable($advanced_cache_filename)) {
715 if (version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<') || $update_required) {
716 $this->advanced_cache_file_writing_error = true;
717 return false;
718 } else {
719 $this->advanced_cache_file_writing_error = false;
720 return true;
721 }
722 }
723
724 if (!file_put_contents($this->get_advanced_cache_filename(), $this->advanced_cache_file_content)) {
725 $this->advanced_cache_file_writing_error = true;
726 return false;
727 }
728
729 $this->advanced_cache_file_writing_error = false;
730 return true;
731 }
732
733 /**
734 * Update advanced cache version if needed.
735 */
736 public function maybe_update_advanced_cache() {
737
738 if (!$this->is_enabled()) return;
739
740 if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND') || (defined('WPO_PLUGIN_LOCATION_NOT_FOUND') && true === WPO_PLUGIN_LOCATION_NOT_FOUND)) {
741 if (!$this->write_advanced_cache(true)) {
742 add_action('admin_notices', array($this, 'show_admin_notice_advanced_cache'));
743 }
744 }
745
746 // from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php
747 $advanced_cache_current_version = $this->get_advanced_cache_version();
748 if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=')) return;
749
750 if (!$this->write_advanced_cache()) {
751 add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error'));
752 } else {
753 $this->update_cache_config();
754 }
755 }
756
757 /**
758 * Show notification when advanced-cache.php could not be updated.
759 */
760 public function notice_advanced_cache_autoupdate_error() {
761 $this->show_notice(__('The file advanced-cache.php needs to be updated, but the automatic process failed.', 'wp-optimize').
762 ' <a href="'.admin_url('admin.php?page=wpo_cache').'">'.__('Please try to disable and then re-enable the WP-Optimize cache manually.', 'wp-optimize').'</a>', 'error');
763 }
764
765 /**
766 * Get WPO version number from advanced-cache.php file.
767 *
768 * @return bool|mixed
769 */
770 public function get_advanced_cache_version() {
771 if (!is_file($this->get_advanced_cache_filename())) return false;
772
773 $version = false;
774 $content = file_get_contents($this->get_advanced_cache_filename());
775
776 if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) {
777 $version = $match[1];
778 }
779
780 return $version;
781 }
782
783 /**
784 * Set WP_CACHE on or off in wp-config.php
785 *
786 * @param boolean $status value of WP_CACHE.
787 * @return boolean true if the value was set, false otherwise
788 */
789 private function write_wp_config($status = true) {
790 // If we changed the value in wp-config, save it, in case we need to change it again in the same run.
791 static $changed = false;
792
793 if (defined('WP_CACHE') && WP_CACHE === $status && !$changed) {
794 return true;
795 }
796
797 $config_path = $this->_get_wp_config();
798
799 // Couldn't find wp-config.php.
800 if (!$config_path) {
801 return false;
802 }
803
804 $config_file_string = file_get_contents($config_path);
805
806 // Config file is empty. Maybe couldn't read it?
807 if (empty($config_file_string)) {
808 return false;
809 }
810
811 $config_file = preg_split("#(\n|\r\n)#", $config_file_string);
812 $line_key = false;
813
814 foreach ($config_file as $key => $line) {
815 if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) {
816 continue;
817 }
818
819 if ('WP_CACHE' === $match[2]) {
820 $line_key = $key;
821 }
822 }
823
824 if (false !== $line_key) {
825 unset($config_file[$line_key]);
826 }
827
828
829 if ($status) {
830 array_shift($config_file);
831 array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache");
832 }
833
834 foreach ($config_file as $key => $line) {
835 if ('' === $line) {
836 unset($config_file[$key]);
837 }
838 }
839 if (!file_put_contents($config_path, implode(PHP_EOL, $config_file))) {
840 return false;
841 }
842 $changed = true;
843 return true;
844 }
845
846 /**
847 * Verify we can write to the file system
848 *
849 * @return boolean
850 */
851 private function verify_cache() {
852 if (function_exists('clearstatcache')) {
853 clearstatcache();
854 }
855 $errors = 0;
856
857 // First check wp-config.php.
858 if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) {
859 $this->log("Unable to write to or find wp-config.php; please check file/folder permissions");
860 $this->add_warning('verify_cache', __("Unable to write to or find wp-config.php; please check file/folder permissions.", 'wp-optimize'));
861 }
862
863 $advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php';
864
865 // Now check wp-content. We need to be able to create files of the same user as this file.
866 if ((!file_exists($advanced_cache_file) || false === strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) && !is_writable($advanced_cache_file) && !is_writable(untrailingslashit(WP_CONTENT_DIR))) {
867 $this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions");
868 $this->add_error('verify_cache', __("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions", 'wp-optimize'));
869 $errors++;
870 }
871
872 if (file_exists(WPO_CACHE_FILES_DIR)) {
873 if (!is_writable(WPO_CACHE_FILES_DIR)) {
874 $this->log("Unable to write inside the cache files folder; please check file/folder permissions");
875 $this->add_warning('verify_cache', sprintf(__("Unable to write inside the cache files folder (%s); please check file/folder permissions (no cache files will be able to be created otherwise)", 'wp-optimize'), WPO_CACHE_FILES_DIR));
876 }
877 }
878
879 if (file_exists(WPO_CACHE_CONFIG_DIR)) {
880 if (!is_writable(WPO_CACHE_CONFIG_DIR)) {
881 $this->log("Unable to write inside the cache configuration folder; please check file/folder permissions");
882 // If the config exists, only send a warning. Otherwise send an error.
883 $type = 'warning';
884 if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename())) {
885 $type = 'error';
886 $errors++;
887 }
888 $this->add_error('verify_cache', sprintf(__("Unable to write inside the cache configuration folder (%s); please check file/folder permissions", 'wp-optimize'), WPO_CACHE_CONFIG_DIR), $type);
889 }
890 }
891
892 return !$errors;
893 }
894
895 /**
896 * Update permalink structure in cache config
897 *
898 * @param string $old_value Old value of permalink_structure option
899 * @param string $value New value of permalink_structure option
900 * @param string $option Option name `permalink_structure`
901 */
902 public function update_option_permalink_structure($old_value, $value, $option) {
903 $current_config = $this->config->get();
904 if ($old_value != $value) {
905 $current_config[$option] = $value;
906 $this->config->update($current_config, true);
907 }
908 }
909
910 /**
911 * Update cache config. Used to support 3d party plugins.
912 *
913 * @return {boolean|WP_Error}
914 */
915 public function update_cache_config() {
916 // get current cache settings.
917 $current_config = $this->config->get();
918 // and call update to change if need cookies and query variable names.
919 return $this->config->update($current_config);
920 }
921
922 /**
923 * Delete information about cache size.
924 */
925 public function delete_cache_size_information() {
926 delete_transient('wpo_get_cache_size');
927 }
928
929 /**
930 * Get current cache size.
931 *
932 * @return array
933 */
934 public function get_cache_size() {
935 $cache_size = get_transient('wpo_get_cache_size');
936
937 if (!empty($cache_size)) return $cache_size;
938
939 $infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR);
940 $cache_size = array(
941 'size' => $infos['size'],
942 'file_count' => $infos['file_count']
943 );
944
945 set_transient('wpo_get_cache_size', $cache_size);
946
947 return $cache_size;
948 }
949
950 /**
951 * Fetch directory information.
952 *
953 * @param string $dir
954 * @return array
955 */
956 private function get_dir_infos($dir) {
957 $dir_size = 0;
958 $file_count = 0;
959
960 $handle = is_dir($dir) ? opendir($dir) : false;
961
962 if (false === $handle) {
963 return array('size' => 0, 'file_count' => 0);
964 }
965
966 $file = readdir($handle);
967
968 while (false !== $file) {
969
970 if ('.' != $file && '..' != $file) {
971 $current_file = $dir.'/'.$file;
972
973 if (is_dir($current_file)) {
974 $sub_dir_infos = $this->get_dir_infos($current_file);
975 $dir_size += $sub_dir_infos['size'];
976 $file_count += $sub_dir_infos['file_count'];
977 } elseif (is_file($current_file)) {
978 $dir_size += filesize($current_file);
979 $file_count++;
980 }
981 }
982
983 $file = readdir($handle);
984
985 }
986
987 return array('size' => $dir_size, 'file_count' => $file_count);
988 }
989
990 /**
991 * Returns the path to wp-config
992 *
993 * @return string|boolean wp-config.php path.
994 */
995 private function _get_wp_config() {
996
997 $config_path = false;
998
999 foreach (get_included_files() as $filename) {
1000 if (preg_match('/(\\\\|\/)wp-config\.php$/i', $filename)) {
1001 $config_path = $filename;
1002 break;
1003 }
1004 }
1005
1006 // WP-CLI doesn't include wp-config.php that's why we use function from WP-CLI to locate config file.
1007 if (!$config_path && is_callable('wpo_wp_cli_locate_wp_config')) {
1008 $config_path = wpo_wp_cli_locate_wp_config();
1009 }
1010
1011 return $config_path;
1012 }
1013
1014 /**
1015 * Util to delete folders and/or files
1016 *
1017 * @param string $src
1018 * @return boolean
1019 */
1020 public static function delete($src) {
1021
1022 return wpo_delete_files($src);
1023
1024 }
1025
1026 /**
1027 * Delete cached files for specific url.
1028 *
1029 * @param string $url
1030 * @param bool $recursive If true child elements will deleted too
1031 *
1032 * @return bool
1033 */
1034 public static function delete_cache_by_url($url, $recursive = false) {
1035 if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return;
1036
1037 $path = self::get_full_path_from_url($url);
1038
1039 do_action('wpo_delete_cache_by_url', $url, $recursive);
1040
1041 return wpo_delete_files($path, $recursive);
1042 }
1043
1044 /**
1045 * Delete cached files for single post.
1046 *
1047 * @param integer $post_id The post ID
1048 *
1049 * @return bool
1050 */
1051 public static function delete_single_post_cache($post_id) {
1052 $is_cache_deleted = self::really_delete_single_post_cache($post_id);
1053
1054 do_action('wpo_single_post_cache_deleted', $post_id);
1055
1056 return $is_cache_deleted;
1057 }
1058
1059 /**
1060 * Really delete cached files for single post.
1061 *
1062 * @param integer $post_id The post ID
1063 *
1064 * @return bool
1065 */
1066 public static function really_delete_single_post_cache($post_id) {
1067
1068 if (!defined('WPO_CACHE_FILES_DIR')) return;
1069
1070 $post_url = get_permalink($post_id);
1071
1072 $path = self::get_full_path_from_url($post_url);
1073
1074 // for posts with pagination run purging cache recursively.
1075 $post = get_post($post_id);
1076 $recursive = preg_match('/\<\!--nextpage--\>/', $post->post_content) ? true : false;
1077
1078 do_action('wpo_delete_cache_by_url', $post_url, $recursive);
1079
1080 return wpo_delete_files($path, $recursive);
1081 }
1082
1083 /**
1084 * Delete cached home page files.
1085 */
1086 public static function delete_homepage_cache() {
1087
1088 if (!defined('WPO_CACHE_FILES_DIR')) return;
1089
1090 $homepage_url = get_home_url(get_current_blog_id());
1091
1092 $path = self::get_full_path_from_url($homepage_url);
1093
1094 do_action('wpo_delete_cache_by_url', $homepage_url, false);
1095
1096 wpo_delete_files($path, false);
1097 }
1098
1099 /**
1100 * Delete sitemap cache.
1101 */
1102 public static function delete_sitemap_cache() {
1103 if (!defined('WPO_CACHE_FILES_DIR')) return;
1104
1105 $homepage_url = get_home_url(get_current_blog_id());
1106
1107 $path = trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($homepage_url));
1108
1109 if (!is_dir($path)) return;
1110
1111 $handle = opendir($path);
1112
1113 if (false !== $handle) {
1114 $file = readdir($handle);
1115
1116 while (false !== $file) {
1117
1118 if ('.' != $file && '..' != $file && is_dir($path . $file) && preg_match('/.*sitemap.*\.xml/i', $file)) {
1119 do_action('wpo_delete_cache_by_url', $path . $file, false);
1120 wpo_delete_files($path . $file, true);
1121 }
1122
1123 $file = readdir($handle);
1124 }
1125 }
1126
1127 closedir($handle);
1128 }
1129
1130 /**
1131 * Delete feed from cache.
1132 */
1133 public static function delete_feed_cache() {
1134 if (!defined('WPO_CACHE_FILES_DIR')) return;
1135
1136 $homepage_url = get_home_url(get_current_blog_id());
1137
1138 $path = self::get_full_path_from_url($homepage_url) . 'feed/';
1139
1140 do_action('wpo_delete_cache_by_url', $path, true);
1141
1142 wpo_delete_files($path, true);
1143 }
1144
1145 /**
1146 * Delete post feed from cache.
1147 */
1148 public static function delete_post_feed_cache($post_id) {
1149 self::really_delete_post_feed_cache($post_id);
1150
1151 do_action('wpo_single_post_feed_cache_deleted', $post_id);
1152 }
1153
1154 /**
1155 * Really delete post feed from cache.
1156 */
1157 public static function really_delete_post_feed_cache($post_id) {
1158 if (!defined('WPO_CACHE_FILES_DIR')) return;
1159
1160 $post_url = get_permalink($post_id);
1161
1162 $path = self::get_full_path_from_url($post_url) . 'feed/';
1163
1164 do_action('wpo_delete_cache_by_url', $path, true);
1165
1166 wpo_delete_files($path, true);
1167 }
1168
1169 /**
1170 * Delete comments feed from cache.
1171 */
1172 public static function delete_comments_feed() {
1173 if (!defined('WPO_CACHE_FILES_DIR')) return;
1174
1175 $comments_feed_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/feed/';
1176
1177 $path = self::get_full_path_from_url($comments_feed_url);
1178
1179 do_action('wpo_delete_cache_by_url', $comments_feed_url, true);
1180
1181 wpo_delete_files($path, true);
1182
1183 // delete empty comments dir from the cache
1184 $comments_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/';
1185 $path = self::get_full_path_from_url($comments_url);
1186
1187 if (wpo_is_empty_dir($path)) {
1188 wpo_delete_files($path, true);
1189 }
1190 }
1191
1192 /**
1193 * Returns full path to the cache folder by url.
1194 *
1195 * @param string $url
1196 * @return string
1197 */
1198 private static function get_full_path_from_url($url) {
1199 return trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($url));
1200 }
1201
1202 /**
1203 * Admin actions
1204 *
1205 * @return void
1206 */
1207 public function admin_init() {
1208 // Maybe update the advanced cache.
1209 if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) {
1210 $this->maybe_update_advanced_cache();
1211 $this->cron_activate();
1212 }
1213 }
1214
1215 /**
1216 * Logs error messages
1217 *
1218 * @param string $message
1219 * @return null|void
1220 */
1221 public function log($message) {
1222 if (isset($this->logger)) {
1223 $this->logger->log($message, 'error');
1224 }
1225 }
1226
1227 /**
1228 * Returns an instance of the current class, creates one if it doesn't exist
1229 *
1230 * @return object
1231 */
1232 public static function instance() {
1233 if (empty(self::$instance)) {
1234 self::$instance = new self();
1235 }
1236 return self::$instance;
1237 }
1238
1239
1240 /**
1241 * Update gmt_offset and timezone_string cache config value, used with hook `update_gmt_offset_timezone_string_config`.
1242 *
1243 * @param {float|string} $old_value GMT offset as a float value or timezone value supported by PHP as a string (https://www.php.net/manual/en/timezones.php)
1244 * @param {float|string} $new_value
1245 * @param {string} $option gmt_offset|timezone_string
1246 *
1247 * @return null
1248 */
1249 public function update_gmt_offset_timezone_string_config($old_value, $new_value, $option) {
1250 if ('' == $new_value) return;
1251
1252 $current_config = $this->config->get();
1253 if ('timezone_string' == $option) {
1254 $timeZone = new DateTimeZone($new_value);
1255 $dateTime = new DateTime("now");
1256 $gmt_offset = $timeZone->getOffset($dateTime);
1257 $current_config['gmt_offset'] = round($gmt_offset/3600, 1);
1258 $current_config['timezone_string'] = $new_value;
1259 } elseif ('' !== $new_value) {
1260 $current_config['gmt_offset'] = $new_value;
1261 $current_config['timezone_string'] = '';
1262 }
1263 $this->config->update($current_config, true);
1264 }
1265
1266 /**
1267 * Update `date_format` cache config value, used with hook `update_option_date_format`.
1268 *
1269 * @param string $old_value Old date format
1270 * @param string $new_value New date format
1271 *
1272 * @return void
1273 */
1274 public function update_option_date_format($old_value, $new_value) {
1275 $current_config = $this->config->get();
1276 $current_config['date_format'] = $new_value;
1277 $this->config->update($current_config, true);
1278 }
1279
1280 /**
1281 * Update `time_format` cache config value, used with hook `update_option_time_format`.
1282 *
1283 * @param string $old_value Old time format
1284 * @param string $new_value New time format
1285 *
1286 * @return void
1287 */
1288 public function update_option_time_format($old_value, $new_value) {
1289 $current_config = $this->config->get();
1290 $current_config['time_format'] = $new_value;
1291 $this->config->update($current_config, true);
1292 }
1293
1294 /**
1295 * Adds an error to the error store
1296 *
1297 * @param string $code - The error code
1298 * @param string $message - The error's message
1299 * @param string $type - The error's type (error, warning)
1300 * @return void
1301 */
1302 public function add_error($code, $message, $type = 'error') {
1303 if (!isset($this->_errors[$type])) {
1304 $this->_errors[$type] = new WP_Error($code, $message);
1305 } else {
1306 $this->_errors[$type]->add($code, $message);
1307 }
1308 }
1309
1310 /**
1311 * Adds a warning to the error store
1312 *
1313 * @param string $code - The error code
1314 * @param string $message - The error's message
1315 * @return void
1316 */
1317 public function add_warning($code, $message) {
1318 $this->add_error($code, $message, 'warning');
1319 }
1320
1321 /**
1322 * Get all recorded errors
1323 *
1324 * @param string $type - The error type
1325 * @param boolean $get_messages_only - Whether to get only the messages, or the full WP_Error object
1326 * @return boolean|array|WP_Error
1327 */
1328 public function get_errors($type = 'error', $get_messages_only = true) {
1329 if (!$this->has_errors($type)) return false;
1330 $errors = $this->_errors[$type];
1331 if ($get_messages_only) {
1332 return $errors->get_error_messages();
1333 }
1334 return $errors;
1335 }
1336
1337 /**
1338 * Check if any errors were recorded
1339 *
1340 * @param string $type - The error type
1341 * @return boolean
1342 */
1343 public function has_errors($type = 'error') {
1344 return isset($this->_errors[$type]) && !empty($this->_errors[$type]) && $this->_errors[$type]->has_errors();
1345 }
1346
1347 /**
1348 * Check if any warnings were recorded
1349 *
1350 * @return boolean
1351 */
1352 public function has_warnings() {
1353 return $this->has_errors('warning');
1354 }
1355
1356 /**
1357 * Check the cache compatibility issues.
1358 */
1359 public function check_compatibility_issues() {
1360 if (!$this->is_enabled()) return;
1361
1362 if ($this->is_pagespeedninja_gzip_active()) add_action('admin_notices', array($this, 'show_pagespeedninja_gzip_notice'));
1363 if ($this->is_farfutureexpiration_gzip_active()) add_action('admin_notices', array($this, 'show_farfutureexpiration_gzip_notice'));
1364 }
1365
1366 /**
1367 * Check if PageSpeed Ninja is active and GZIP compression option is enabled.
1368 *
1369 * @return bool
1370 */
1371 public function is_pagespeedninja_gzip_active() {
1372 if (!class_exists('PagespeedNinja')) return false;
1373
1374 $options = get_option('pagespeedninja_config');
1375 $gzip = !empty($options) ? (bool) $options['psi_EnableGzipCompression'] && (bool) $options['html_gzip'] : false;
1376
1377 return $gzip;
1378 }
1379
1380 /**
1381 * Output PageSpeed Ninja Gzip notice.
1382 */
1383 public function show_pagespeedninja_gzip_notice() {
1384 echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in PageSpeed Ninja to prevent conflicts.', 'wp-optimize').'</p></div>';
1385 }
1386
1387 /**
1388 * Check if Far Future Expiration is active and GZIP compression option is enabled.
1389 *
1390 * @return bool
1391 */
1392 public function is_farfutureexpiration_gzip_active() {
1393 if (!class_exists('farFutureExpiration')) return false;
1394
1395 $options = get_option('far_future_expiration_settings');
1396 $gzip = !empty($options) ? (bool) $options['enable_gzip'] : false;
1397
1398 return $gzip;
1399 }
1400
1401 /**
1402 * Output Far Future Expiration Gzip notice.
1403 */
1404 public function show_farfutureexpiration_gzip_notice() {
1405 echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.__('WP-Optimize:', 'wp-optimize').'</b> '.__('Please disable the feature "Gzip compression" in Far Future Expiration to prevent conflicts.', 'wp-optimize').'</p></div>';
1406 }
1407
1408 /**
1409 * This is a notice to show users that writing `advanced-cache.php` failed
1410 */
1411 public function show_admin_notice_advanced_cache() {
1412 $message = sprintf(__('The request to write the file %s failed.', 'wp-optimize'), htmlspecialchars($this->get_advanced_cache_filename()));
1413 $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize');
1414 WP_Optimize()->include_template('notices/cache-notice.php', false, array('message' => $message));
1415 }
1416
1417 /**
1418 * Scheduler public functions to update schedulers
1419 *
1420 * @param array $schedules An array of schedules being passed.
1421 * @return array An array of schedules being returned.
1422 */
1423 public function cron_schedules($schedules) {
1424 $page_cache_length = $this->config->get_option('page_cache_length');
1425 // When the interval is less than `WP_CRON_LOCK_TIMEOUT` error messages are triggered
1426 // So, instead of `0` (now) we are making it equal to the constant value.
1427 // https://github.com/WordPress/WordPress/commit/84d19848666a81584e0007a6ab7f7ad3c990d71a
1428 if (defined('WP_CRON_LOCK_TIMEOUT') && $page_cache_length < WP_CRON_LOCK_TIMEOUT) {
1429 $page_cache_length = WP_CRON_LOCK_TIMEOUT;
1430 }
1431
1432 $schedules['wpo_purge_old_cache'] = array('interval' => false === $page_cache_length ? 86400 : $page_cache_length, 'display' => __('Every time after the cache has expired', 'wp-optimize'));
1433
1434 $interval = WP_Optimize_Page_Cache_Preloader::instance()->get_continue_preload_cron_interval();
1435 $schedules['wpo_page_cache_preload_continue_interval'] = array(
1436 'interval' => $interval,
1437 'display' => sprintf(__('%d minutes', 'wp-optimize'), round($interval / 60, 1))
1438 );
1439
1440 $schedules['wpo_use_cache_lifespan'] = array(
1441 'interval' => $page_cache_length,
1442 'display' => sprintf(__('Same as cache lifespan: %s', 'wp-optimize'), WPO_Cache_Config::instance()->get_option('page_cache_length_value').' '.WPO_Cache_Config::instance()->get_option('page_cache_length_unit'))
1443 );
1444
1445 return $schedules;
1446 }
1447
1448 /**
1449 * Update cache config file to reflect the webp images option
1450 */
1451 public function update_webp_images_option() {
1452 if ($this->is_enabled()) {
1453 $cache_settings = WPO_Cache_Config::instance()->get();
1454 $cache_settings['use_webp_images'] = WP_Optimize()->get_options()->get_option('webp_conversion');
1455 WPO_Cache_Config::instance()->update($cache_settings);
1456 }
1457 }
1458
1459 /**
1460 * May be regenerate cache config file, in case of migrations
1461 */
1462 public function maybe_regenerate_cache_config_file() {
1463 $config_file = WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename();
1464 if (!file_exists($config_file)) {
1465 $config = $this->config->get();
1466 $this->config->write($config);
1467 }
1468 }
1469 }
1470
1471 endif;
1472