| @@ -21,19 +21,10 @@ | ||
| 21 | 21 | * Directory that stores config and related files |
| 22 | 22 | */ |
| 23 | 23 | if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); |
| 24 | 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 | 25 | require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; |
| 31 | 26 | |
| 32 | -if (version_compare(PHP_VERSION, '5.3.0') >= 0) { | |
| 33 | - require_once dirname(__FILE__) . '/php-5.3-functions.php'; | |
| 34 | -} | |
| 35 | - | |
| 36 | 27 | wpo_cache_load_extensions(); |
| 37 | 28 | |
| 38 | 29 | if (!class_exists('WPO_Page_Cache')) : |
| 39 | 30 | |
| @@ -53,11 +44,18 @@ | ||
| 53 | 44 | */ |
| 54 | 45 | public $logger; |
| 55 | 46 | |
| 56 | 47 | /** |
| 48 | + * File Logger for this class | |
| 49 | + * | |
| 50 | + * @var mixed | |
| 51 | + */ | |
| 52 | + private $file_logger; | |
| 53 | + | |
| 54 | + /** | |
| 57 | 55 | * Instance of this class |
| 58 | 56 | * |
| 59 | - * @var mixed | |
| 57 | + * @var WPO_Page_Cache | null | |
| 60 | 58 | */ |
| 61 | 59 | public static $instance; |
| 62 | 60 | |
| 63 | 61 | /** |
| @@ -88,21 +86,44 @@ | ||
| 88 | 86 | * @var string |
| 89 | 87 | */ |
| 90 | 88 | private $_minimum_advanced_cache_file_version = '3.0.17'; |
| 91 | 89 | |
| 90 | + /** | |
| 91 | + * Flag to decide whether to purge or not | |
| 92 | + * | |
| 93 | + * @var bool | |
| 94 | + */ | |
| 92 | 95 | public $should_purge; |
| 93 | 96 | |
| 94 | 97 | /** |
| 98 | + * Flag to decide whether to purge or not | |
| 99 | + * | |
| 100 | + * @var bool | |
| 101 | + */ | |
| 102 | + private $files_to_ignore = array('index.php','.htaccess'); | |
| 103 | + | |
| 104 | + /** | |
| 95 | 105 | * Set everything up here |
| 96 | 106 | */ |
| 97 | 107 | public function __construct() { |
| 98 | 108 | $this->config = WPO_Cache_Config::instance(); |
| 109 | + if (empty($GLOBALS['wpo_cache_config'])) { | |
| 110 | + $config_file_path = $this->config->get_config_file_path(); | |
| 111 | + if (file_exists($config_file_path)) { | |
| 112 | + include_once($config_file_path); | |
| 113 | + } | |
| 114 | + } | |
| 115 | + | |
| 99 | 116 | WPO_Cache_Rules::instance(); |
| 117 | + WP_Optimize_Page_Cache_Preloader::instance(); | |
| 118 | + | |
| 100 | 119 | $this->logger = new Updraft_PHP_Logger(); |
| 120 | + $this->file_logger = new Updraft_File_Logger(WP_Optimize_Utils::get_log_file_path('cache')); | |
| 101 | 121 | |
| 102 | 122 | add_action('activated_plugin', array($this, 'activate_deactivate_plugin')); |
| 103 | 123 | add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin')); |
| 104 | 124 | add_action('wpo_purge_old_cache', array($this, 'purge_old')); |
| 125 | + add_action('wpo_prune_cache_logs', array($this, 'prune_cache_logs')); | |
| 105 | 126 | |
| 106 | 127 | /** |
| 107 | 128 | * Regenerate config file on cache flush. |
| 108 | 129 | */ |
| @@ -107,8 +128,9 @@ | ||
| 107 | 128 | * Regenerate config file on cache flush. |
| 108 | 129 | */ |
| 109 | 130 | add_action('wpo_cache_flush', array($this, 'update_cache_config')); |
| 110 | 131 | add_action('wpo_cache_flush', array($this, 'delete_cache_size_information')); |
| 132 | + add_action('wpo_cache_flush', array($this, 'update_cache_cleared_time')); | |
| 111 | 133 | add_action('update_option_permalink_structure', array($this, 'update_option_permalink_structure'), 10, 3); |
| 112 | 134 | |
| 113 | 135 | // Add purge cache link to admin bar. |
| 114 | 136 | add_filter('wpo_cache_admin_bar_menu_items', array($this, 'admin_bar_purge_cache'), 20, 1); |
| @@ -124,27 +146,140 @@ | ||
| 124 | 146 | add_action('update_option_time_format', array($this, 'update_option_time_format'), 10, 2); |
| 125 | 147 | |
| 126 | 148 | $this->check_compatibility_issues(); |
| 127 | 149 | |
| 150 | + $this->ensure_cron_schedules_filter_registered(); | |
| 151 | + | |
| 152 | + add_action('wpo_save_images_settings', array($this, 'update_webp_images_option')); | |
| 153 | + | |
| 154 | + add_action('wpo_preload_url', array($this, 'maybe_preload_url')); | |
| 155 | + | |
| 156 | + // Setup filters for exceptions. | |
| 157 | + add_filter('wpo_restricted_cache_page_type', 'wpo_restricted_cache_page_type'); | |
| 158 | + add_filter('wpo_url_in_conditional_tags_exceptions', 'wpo_url_in_conditional_tags_exceptions'); | |
| 159 | + } | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Ensures that the cron-related filter is registered. | |
| 163 | + * | |
| 164 | + * If `init` has already run, the filter is registered immediately. | |
| 165 | + * Otherwise, it schedules the registration to occur during `init`. | |
| 166 | + * | |
| 167 | + * @return void | |
| 168 | + */ | |
| 169 | + private function ensure_cron_schedules_filter_registered() { | |
| 170 | + if (did_action('init')) { | |
| 171 | + $this->register_cron_schedules_filter(); | |
| 172 | + } else { | |
| 173 | + add_action('init', array($this, 'register_cron_schedules_filter')); | |
| 174 | + } | |
| 175 | + } | |
| 176 | + | |
| 177 | + /** | |
| 178 | + * Registers the custom cron schedule filter for WP-Cron. | |
| 179 | + * | |
| 180 | + * This method hooks the class's `cron_schedules()` method into WordPress's | |
| 181 | + * `cron_schedules` filter, allowing the plugin to define custom cron intervals. | |
| 182 | + * | |
| 183 | + * It is recommended to call this method on or after the `init` action to ensure | |
| 184 | + * that translations and other dependencies are properly loaded before the filter runs. | |
| 185 | + * | |
| 186 | + * @return void | |
| 187 | + */ | |
| 188 | + public function register_cron_schedules_filter() { | |
| 128 | 189 | add_filter('cron_schedules', array($this, 'cron_schedules')); |
| 129 | - add_action('wpo_save_images_settings', array($this, 'update_webp_images_option')); | |
| 130 | 190 | } |
| 131 | 191 | |
| 132 | 192 | /** |
| 193 | + * Determines whether the current page should be cached. | |
| 194 | + * | |
| 195 | + * This method checks cache rules to identify if caching is possible. | |
| 196 | + * If caching is not allowed, it adds appropriate HTTP headers and debug messages. | |
| 197 | + * | |
| 198 | + * @return bool|array True if the page should be cached, false otherwise or not empty array with the reasons why the page isn't cached | |
| 199 | + */ | |
| 200 | + public function should_cache_page() { | |
| 201 | + | |
| 202 | + if (!$this->is_enabled()) return false; | |
| 203 | + | |
| 204 | + return wpo_can_serve_from_cache(); | |
| 205 | + } | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * Maybe add information about why the page is not cached to the headers and footer output | |
| 209 | + * | |
| 210 | + * @param array $no_cache_because | |
| 211 | + * @return void | |
| 212 | + */ | |
| 213 | + public function maybe_add_no_cache_because_info($no_cache_because) { | |
| 214 | + // Add http header | |
| 215 | + if (!wp_doing_cron() && !empty($no_cache_because)) { | |
| 216 | + $no_cache_because_message = join(", ", $no_cache_because); | |
| 217 | + wpo_cache_add_nocache_http_header_with_send_headers_action($no_cache_because_message); | |
| 218 | + | |
| 219 | + $not_cached_details = ""; | |
| 220 | + | |
| 221 | + // Output the reason only when the user has turned on debugging | |
| 222 | + if ((defined('WP_DEBUG') && WP_DEBUG) || !empty(TeamUpdraft\WP_Optimize\Includes\Fragments\fetch_superglobal('get', 'wpo_cache_debug'))) { | |
| 223 | + $not_cached_details = "because: ".$no_cache_because_message; | |
| 224 | + } | |
| 225 | + wpo_cache_add_footer_output(sprintf("Page not served from cache %s", $not_cached_details)); | |
| 226 | + } | |
| 227 | + } | |
| 228 | + | |
| 229 | + /** | |
| 230 | + * Handle cache settings update | |
| 231 | + * | |
| 232 | + * @param array $new_settings | |
| 233 | + * @return void | |
| 234 | + */ | |
| 235 | + public function cache_settings_updated($new_settings) { | |
| 236 | + | |
| 237 | + $this->unschedule_purge_old_cache(); | |
| 238 | + | |
| 239 | + if ($new_settings['enable_page_caching']) { | |
| 240 | + $this->schedule_purge_old_cache(); | |
| 241 | + } | |
| 242 | + } | |
| 243 | + | |
| 244 | + /** | |
| 133 | 245 | * Activate cron job when the cache is enabled for deleting expired cache files |
| 134 | 246 | */ |
| 135 | 247 | public function cron_activate() { |
| 136 | - $page_cache_length = $this->config->get_option('page_cache_length'); | |
| 137 | 248 | if ($this->is_enabled()) { |
| 138 | - if (!wp_next_scheduled('wpo_purge_old_cache')) { | |
| 139 | - wp_schedule_event(time() + (false === $page_cache_length ? '86400' : $page_cache_length), 'wpo_purge_old_cache', 'wpo_purge_old_cache'); | |
| 140 | - } | |
| 249 | + $this->schedule_purge_old_cache(); | |
| 141 | 250 | } else { |
| 142 | - wp_clear_scheduled_hook('wpo_purge_old_cache'); | |
| 251 | + $this->unschedule_purge_old_cache(); | |
| 143 | 252 | } |
| 144 | 253 | } |
| 145 | 254 | |
| 146 | 255 | /** |
| 256 | + * Schedules events to purge old cache | |
| 257 | + * | |
| 258 | + * @return void | |
| 259 | + */ | |
| 260 | + private function schedule_purge_old_cache() { | |
| 261 | + $page_cache_length = $this->config->get_option('page_cache_length'); | |
| 262 | + | |
| 263 | + if (!wp_next_scheduled('wpo_purge_old_cache')) { | |
| 264 | + wp_schedule_event(time() + (false === $page_cache_length ? 86400 : $page_cache_length), 'wpo_purge_old_cache', 'wpo_purge_old_cache'); | |
| 265 | + } | |
| 266 | + if (!wp_next_scheduled('wpo_prune_cache_logs')) { | |
| 267 | + wp_schedule_event(time(), 'weekly', 'wpo_prune_cache_logs'); | |
| 268 | + } | |
| 269 | + } | |
| 270 | + | |
| 271 | + /** | |
| 272 | + * Unschedules events to purge old cache | |
| 273 | + * | |
| 274 | + * @return void | |
| 275 | + */ | |
| 276 | + private function unschedule_purge_old_cache() { | |
| 277 | + wp_clear_scheduled_hook('wpo_purge_old_cache'); | |
| 278 | + wp_clear_scheduled_hook('wpo_prune_cache_logs'); | |
| 279 | + } | |
| 280 | + | |
| 281 | + /** | |
| 147 | 282 | * Do required actions on activate/deactivate any plugin. |
| 148 | 283 | */ |
| 149 | 284 | public function activate_deactivate_plugin() { |
| 150 | 285 | |
| @@ -151,9 +286,11 @@ | ||
| 151 | 286 | wp_clear_scheduled_hook('wpo_purge_old_cache'); |
| 152 | 287 | |
| 153 | 288 | $this->update_cache_config(); |
| 154 | 289 | |
| 155 | - $this->purge(); | |
| 290 | + $is_cache_purged = $this->purge(); | |
| 291 | + | |
| 292 | + if ($is_cache_purged) $this->file_log("Full Cache Purge triggered by: plugin activation/deactivation"); | |
| 156 | 293 | } |
| 157 | 294 | |
| 158 | 295 | /** |
| 159 | 296 | * Check if current user can purge cache. |
| @@ -161,15 +298,10 @@ | ||
| 161 | 298 | * @return bool |
| 162 | 299 | */ |
| 163 | 300 | public function can_purge_cache() { |
| 164 | 301 | if (!$this->is_enabled()) return false; |
| 165 | - $required_capability = is_multisite() ? 'manage_network_options' : 'manage_options'; | |
| 166 | 302 | |
| 167 | - if (WP_Optimize::is_premium()) { | |
| 168 | - return current_user_can($required_capability) || WP_Optimize_Premium()->can_purge_the_cache(); | |
| 169 | - } else { | |
| 170 | - return current_user_can($required_capability); | |
| 171 | - } | |
| 303 | + return WP_Optimize_Utils::current_user_can_purge_cache(); | |
| 172 | 304 | } |
| 173 | 305 | |
| 174 | 306 | /** |
| 175 | 307 | * Add Purge from cache in admin bar. |
| @@ -180,12 +312,13 @@ | ||
| 180 | 312 | public function admin_bar_purge_cache($menu_items) { |
| 181 | 313 | global $pagenow; |
| 182 | 314 | if (!$this->can_purge_cache()) return $menu_items; |
| 183 | 315 | |
| 184 | - $act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged')); | |
| 316 | + $act_url = WP_Optimize_Utils::get_url_without_cache_purge_params(); | |
| 185 | 317 | |
| 186 | 318 | $cache_size = $this->get_cache_size(); |
| 187 | 319 | $cache_size_info = '<h4>'.__('Page cache', 'wp-optimize').'</h4>'; |
| 320 | + // translators: %d is the number of files in the cache | |
| 188 | 321 | $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>'; |
| 189 | 322 | |
| 190 | 323 | $menu_items[] = array( |
| 191 | 324 | 'id' => 'wpo_cache_stats', |
| @@ -205,9 +338,9 @@ | ||
| 205 | 338 | ), |
| 206 | 339 | 'parent' => 'wpo_purge_cache', |
| 207 | 340 | ); |
| 208 | 341 | |
| 209 | - if (!is_admin() || 'post.php' == $pagenow) { | |
| 342 | + if (!is_admin() || 'post.php' === $pagenow) { | |
| 210 | 343 | $menu_items[] = array( |
| 211 | 344 | 'id' => 'wpo_purge_this_page_cache', |
| 212 | 345 | 'title' => __('Purge cache for this page', 'wp-optimize'), |
| 213 | 346 | 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url), |
| @@ -229,22 +362,38 @@ | ||
| 229 | 362 | |
| 230 | 363 | if (!$this->can_purge_cache()) return; |
| 231 | 364 | |
| 232 | 365 | if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) { |
| 366 | + // phpcs:disable | |
| 367 | + // We are not using $_GET values, just checks if the variable is set and then use hard coded string | |
| 233 | 368 | if (isset($_GET['wpo_single_page_cache_purged'])) { |
| 234 | - $notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error'; | |
| 369 | + $message = $_GET['wpo_single_page_cache_purged'] ? __('Cache purged for this page', 'wp-optimize') : __('Error purging cache for this page', 'wp-optimize'); | |
| 370 | + $type = $_GET['wpo_single_page_cache_purged'] ? 'success' : 'error'; | |
| 235 | 371 | } else { |
| 236 | - $notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error'; | |
| 372 | + $message = $_GET['wpo_all_pages_cache_purged'] ? __('Cache purged for all pages', 'wp-optimize') : __('Error purging cache for all pages', 'wp-optimize'); | |
| 373 | + $type = $_GET['wpo_all_pages_cache_purged'] ? 'success' : 'error'; | |
| 237 | 374 | } |
| 375 | + // phpcs:enable | |
| 238 | 376 | |
| 239 | - add_action('admin_notices', array($this, $notice_function)); | |
| 377 | + if (is_admin()) { | |
| 378 | + $admin_notices_hook = is_network_admin() ? 'network_admin_notices' : 'admin_notices'; | |
| 240 | 379 | |
| 380 | + add_action($admin_notices_hook, function() use ($message, $type) { | |
| 381 | + $this->show_notice($message, $type); | |
| 382 | + }); | |
| 383 | + | |
| 384 | + add_action('admin_head', array('WP_Optimize_Utils', 'script_to_remove_cache_purge_params_from_url')); | |
| 385 | + } else { | |
| 386 | + printf('<script>window.onload = function() {alert("%s");}</script>', esc_js($message)); | |
| 387 | + WP_Optimize_Utils::script_to_remove_cache_purge_params_from_url(); | |
| 388 | + } | |
| 389 | + | |
| 241 | 390 | return; |
| 242 | 391 | } |
| 243 | 392 | |
| 244 | 393 | if (!isset($_GET['_wpo_purge'])) return; |
| 245 | 394 | |
| 246 | - if (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_single_page_cache')) { | |
| 395 | + if (wp_verify_nonce(sanitize_key($_GET['_wpo_purge']), 'wpo_purge_single_page_cache')) { | |
| 247 | 396 | $success = false; |
| 248 | 397 | |
| 249 | 398 | if (is_admin()) { |
| 250 | 399 | $post = isset($_GET['post']) ? (int) $_GET['post'] : 0; |
| @@ -249,55 +398,56 @@ | ||
| 249 | 398 | if (is_admin()) { |
| 250 | 399 | $post = isset($_GET['post']) ? (int) $_GET['post'] : 0; |
| 251 | 400 | if ($post > 0) { |
| 252 | 401 | $success = self::delete_single_post_cache($post); |
| 402 | + if ($success) $this->file_log("Cache for URL: {{URL}} has been purged, triggered by: " . __METHOD__, $post); | |
| 253 | 403 | } |
| 254 | 404 | } else { |
| 255 | - $success = self::delete_cache_by_url(wpo_current_url()); | |
| 405 | + $url = wpo_current_url(); | |
| 406 | + $success = self::delete_cache_by_url($url); | |
| 407 | + if ($success) $this->file_log("Cache for URL: " . self::remove_query_params($url) . " has been purged, triggered by: " . __METHOD__); | |
| 256 | 408 | } |
| 257 | 409 | |
| 258 | - // remove nonce from url and reload page. | |
| 259 | - wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge'))); | |
| 410 | + // Remove all existing purge-related parameters and add the new one | |
| 411 | + $redirect_url = WP_Optimize_Utils::get_url_without_cache_purge_params(); | |
| 412 | + $redirect_url = add_query_arg('wpo_single_page_cache_purged', $success, $redirect_url); | |
| 413 | + | |
| 414 | + wp_redirect($redirect_url); | |
| 260 | 415 | exit; |
| 261 | 416 | |
| 262 | - } elseif (wp_verify_nonce($_GET['_wpo_purge'], 'wpo_purge_all_pages_cache')) { | |
| 417 | + } elseif (wp_verify_nonce(sanitize_key($_GET['_wpo_purge']), 'wpo_purge_all_pages_cache')) { | |
| 263 | 418 | $success = self::purge(); |
| 419 | + $this->maybe_set_preload_cron_job(); | |
| 420 | + if ($success) $this->file_log("Full Cache Purge triggered by: ". __METHOD__); | |
| 264 | 421 | |
| 265 | - // remove nonce from url and reload page. | |
| 266 | - wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge'))); | |
| 422 | + // Remove all existing purge-related parameters and add the new one | |
| 423 | + $redirect_url = WP_Optimize_Utils::get_url_without_cache_purge_params(); | |
| 424 | + $redirect_url = add_query_arg('wpo_all_pages_cache_purged', $success, $redirect_url); | |
| 425 | + | |
| 426 | + wp_redirect($redirect_url); | |
| 267 | 427 | exit; |
| 268 | 428 | } |
| 269 | 429 | } |
| 270 | 430 | |
| 271 | 431 | /** |
| 272 | - * Show notification when page cache purged successfully. | |
| 432 | + * Sets a preload cron job to run after 30 seconds | |
| 433 | + * | |
| 434 | + * As preloading may take time for larger sites, we are opting for an immediate cron job instead | |
| 435 | + * of instant preloading to prevent the current request from slowing down the page load | |
| 436 | + * | |
| 437 | + * @return void | |
| 273 | 438 | */ |
| 274 | - public function notice_purge_single_page_cache_success() { | |
| 275 | - $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); | |
| 276 | - } | |
| 439 | + private function maybe_set_preload_cron_job() { | |
| 440 | + $wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); | |
| 277 | 441 | |
| 278 | - /** | |
| 279 | - * Show notification when page cache wasn't purged. | |
| 280 | - */ | |
| 281 | - public function notice_purge_single_page_cache_error() { | |
| 282 | - $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); | |
| 442 | + if ($wpo_page_cache_preloader->is_scheduled_preload_enabled() || $this->should_auto_preload_purged_contents()) { | |
| 443 | + if (!wp_next_scheduled('wpo_page_cache_run_preload')) { | |
| 444 | + wp_schedule_single_event(time() + 30, 'wpo_page_cache_run_preload'); | |
| 445 | + } | |
| 446 | + } | |
| 283 | 447 | } |
| 284 | - | |
| 448 | + | |
| 285 | 449 | /** |
| 286 | - * Show notification when all pages cache purged successfully. | |
| 287 | - */ | |
| 288 | - public function notice_purge_all_pages_cache_success() { | |
| 289 | - $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); | |
| 290 | - } | |
| 291 | - | |
| 292 | - /** | |
| 293 | - * Show notification when all pages cache wasn't purged. | |
| 294 | - */ | |
| 295 | - public function notice_purge_all_pages_cache_error() { | |
| 296 | - $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); | |
| 297 | - } | |
| 298 | - | |
| 299 | - /** | |
| 300 | 450 | * Show notification in WordPress admin. |
| 301 | 451 | * |
| 302 | 452 | * @param string $message HTML (no further escaping is performed) |
| 303 | 453 | * @param string $type error, warning, success, or info |
| @@ -310,10 +460,10 @@ | ||
| 310 | 460 | window.addEventListener('load', function() { |
| 311 | 461 | (function(wp) { |
| 312 | 462 | if (window.wp && wp.hasOwnProperty('data') && 'function' == typeof wp.data.dispatch) { |
| 313 | 463 | wp.data.dispatch('core/notices').createNotice( |
| 314 | - '<?php echo $type; ?>', | |
| 315 | - '<?php echo $message; ?>', | |
| 464 | + '<?php echo esc_html($type); ?>', | |
| 465 | + '<?php echo wp_kses_post($message); ?>', | |
| 316 | 466 | { |
| 317 | 467 | isDismissible: true, |
| 318 | 468 | } |
| 319 | 469 | ); |
| @@ -321,10 +471,10 @@ | ||
| 321 | 471 | })(window.wp); |
| 322 | 472 | }); |
| 323 | 473 | </script> |
| 324 | 474 | <?php else : ?> |
| 325 | - <div class="notice wpo-notice notice-<?php echo $type; ?> is-dismissible"> | |
| 326 | - <p><?php echo $message; ?></p> | |
| 475 | + <div class="notice wpo-notice notice-<?php echo esc_attr($type); ?> is-dismissible"> | |
| 476 | + <p><?php echo wp_kses_post($message); ?></p> | |
| 327 | 477 | </div> |
| 328 | 478 | <?php |
| 329 | 479 | endif; |
| 330 | 480 | } |
| @@ -336,8 +486,9 @@ | ||
| 336 | 486 | * |
| 337 | 487 | * @return WP_Error|bool - true on success, error otherwise |
| 338 | 488 | */ |
| 339 | 489 | public function enable($force_enable = false) { |
| 490 | + global $is_apache; | |
| 340 | 491 | static $already_ran_enable = false; |
| 341 | 492 | |
| 342 | 493 | if ($already_ran_enable) return $already_ran_enable; |
| 343 | 494 | |
| @@ -358,11 +509,18 @@ | ||
| 358 | 509 | } |
| 359 | 510 | |
| 360 | 511 | $this->maybe_regenerate_cache_config_file(); |
| 361 | 512 | |
| 513 | + // Enable `.htaccess` rules to serve cached files | |
| 514 | + if ($is_apache && apply_filters('wpo_serve_cache_via_htaccess', false)) { | |
| 515 | + wpo_disable_cache_directories_viewing(); | |
| 516 | + wpo_allow_access_to_index_cache_files(); | |
| 517 | + $this->update_serve_cache_rules_htaccess_section(true); | |
| 518 | + } | |
| 519 | + | |
| 362 | 520 | if (!$force_enable) { |
| 363 | - $already_ran_enable = true; | |
| 364 | - return true; | |
| 521 | + $already_ran_enable = $this->update_page_cache_enabled_state(true); | |
| 522 | + return $already_ran_enable; | |
| 365 | 523 | } |
| 366 | 524 | |
| 367 | 525 | if (!$this->write_advanced_cache() && version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<')) { |
| 368 | 526 | $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename())); |
| @@ -368,8 +526,9 @@ | ||
| 368 | 526 | $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename())); |
| 369 | 527 | $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); |
| 370 | 528 | |
| 371 | 529 | if (!defined('WP_CLI') || !WP_CLI) { |
| 530 | + // translators: %s is the path to advanced-cache.php folder | |
| 372 | 531 | $message .= "\n\n1. ".sprintf(__('Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename()))); |
| 373 | 532 | $message .= "\n2. ".__('Edit or create a file with the name advanced-cache.php', 'wp-optimize'); |
| 374 | 533 | $message .= "\n3. ".__('Copy and paste the following lines into the file:', 'wp-optimize'); |
| 375 | 534 | } |
| @@ -388,19 +547,21 @@ | ||
| 388 | 547 | $already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled: \n".implode("\n- ", $errors)); |
| 389 | 548 | return $already_ran_enable; |
| 390 | 549 | } |
| 391 | 550 | |
| 392 | - $already_ran_enable = true; | |
| 393 | - | |
| 394 | - return true; | |
| 551 | + $already_ran_enable = $this->update_page_cache_enabled_state(true); | |
| 552 | + return $already_ran_enable; | |
| 395 | 553 | } |
| 396 | 554 | |
| 397 | 555 | /** |
| 398 | 556 | * Disables page cache |
| 399 | 557 | * |
| 400 | - * @return bool - true on success, false otherwise | |
| 558 | + * @param bool $keep_option_enabled - Whether to keep the option `enable_page_caching` enabled or not. This is useful when we want to disable the cache temporarily, e.g. when deactivating the plugin, but we want to keep the option enabled so that it can be re-enabled when the plugin is reactivated. | |
| 559 | + * @return bool|WP_Error - true on success or WP_Error on failure. | |
| 401 | 560 | */ |
| 402 | - public function disable() { | |
| 561 | + public function disable($keep_option_enabled = false) { | |
| 562 | + global $is_apache; | |
| 563 | + | |
| 403 | 564 | $ret = true; |
| 404 | 565 | |
| 405 | 566 | $advanced_cache_file = $this->get_advanced_cache_filename(); |
| 406 | 567 | |
| @@ -406,15 +567,8 @@ | ||
| 406 | 567 | |
| 407 | 568 | // 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. |
| 408 | 569 | $disabled_wp_config = $this->write_wp_config(false); |
| 409 | 570 | if (!$disabled_wp_config) { |
| 410 | - $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH); | |
| 411 | - $action = "deactivate_".$plugin_basename."/wp-optimize.php"; | |
| 412 | - if (current_action() === $action) { | |
| 413 | - $cache_config = WPO_Cache_Config::instance()->config; | |
| 414 | - $cache_config['enable_page_caching'] = false; | |
| 415 | - WPO_Cache_Config::instance()->update($cache_config, true); | |
| 416 | - } | |
| 417 | 571 | $this->log("Could not turn off the WP_CACHE constant in wp-config.php"); |
| 418 | 572 | $this->add_warning('error_disabling', __('Could not turn off the WP_CACHE constant in wp-config.php', 'wp-optimize')); |
| 419 | 573 | } |
| 420 | 574 | |
| @@ -421,9 +575,9 @@ | ||
| 421 | 575 | $disabled_advanced_cache = true; |
| 422 | 576 | // First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed') |
| 423 | 577 | // We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php |
| 424 | 578 | if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) { |
| 425 | - if (file_exists($advanced_cache_file) && (!unlink($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) { | |
| 579 | + if (file_exists($advanced_cache_file) && (!WP_Optimize_Utils::wp_delete_file($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) { | |
| 426 | 580 | $disabled_advanced_cache = false; |
| 427 | 581 | $this->log("The request to the filesystem to remove or empty advanced-cache.php failed"); |
| 428 | 582 | $this->add_warning('error_disabling', __('The request to the filesystem to remove or empty advanced-cache.php failed', 'wp-optimize')); |
| 429 | 583 | } |
| @@ -434,17 +588,55 @@ | ||
| 434 | 588 | $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')); |
| 435 | 589 | } |
| 436 | 590 | |
| 437 | 591 | // Delete cache to avoid stale cache on next activation |
| 438 | - $this->purge(); | |
| 592 | + $is_cache_purged = $this->purge(); | |
| 593 | + if ($is_cache_purged) $this->file_log("Full Cache Purge triggered by: ". __METHOD__); | |
| 439 | 594 | |
| 595 | + // Delete `.htaccess` rules to serve cached files | |
| 596 | + if ($is_apache && apply_filters('wpo_serve_cache_via_htaccess', false)) { | |
| 597 | + $this->update_serve_cache_rules_htaccess_section(false); | |
| 598 | + } | |
| 599 | + | |
| 440 | 600 | // Unschedule cron job to purge old cache |
| 441 | 601 | wp_clear_scheduled_hook('wpo_purge_old_cache'); |
| 442 | 602 | |
| 603 | + if (!is_wp_error($ret)) { | |
| 604 | + wp_clear_scheduled_hook('wpo_prune_cache_logs'); | |
| 605 | + | |
| 606 | + if (!$keep_option_enabled) { | |
| 607 | + $ret = $this->update_page_cache_enabled_state(false); | |
| 608 | + } | |
| 609 | + } | |
| 610 | + | |
| 611 | + if (!is_wp_error($ret)) { | |
| 612 | + do_action('wpo_page_cache_disabled'); | |
| 613 | + } | |
| 614 | + | |
| 443 | 615 | return $ret; |
| 444 | 616 | } |
| 445 | 617 | |
| 618 | + /** | |
| 619 | + * Update page cache enabled state. | |
| 620 | + * Only updates `enable_page_caching` if the option exists and the value has changed. | |
| 621 | + * | |
| 622 | + * @param bool $enabled Whether page caching should be marked as enabled. | |
| 623 | + * | |
| 624 | + * @return true|WP_Error true on success, WP_Error on failure. | |
| 625 | + */ | |
| 626 | + private function update_page_cache_enabled_state($enabled) { | |
| 627 | + $config = WPO_Cache_Config::instance(); | |
| 628 | + $cache_config = $config->get(); | |
| 446 | 629 | |
| 630 | + if (isset($cache_config['enable_page_caching']) && $cache_config['enable_page_caching'] === $enabled) { | |
| 631 | + return true; | |
| 632 | + } | |
| 633 | + | |
| 634 | + $cache_config['enable_page_caching'] = $enabled; | |
| 635 | + | |
| 636 | + return $config->update($cache_config, true); | |
| 637 | + } | |
| 638 | + | |
| 447 | 639 | /** |
| 448 | 640 | * Purges the cache |
| 449 | 641 | * |
| 450 | 642 | * @return bool - true on success, false otherwise |
| @@ -486,12 +678,12 @@ | ||
| 486 | 678 | if (0 === $page_cache_length) return $log; |
| 487 | 679 | $expires = time() - $page_cache_length; |
| 488 | 680 | $cache_folder = WPO_CACHE_FILES_DIR . '/' . str_ireplace(array('http://', 'https://'), '', get_site_url()); |
| 489 | 681 | // get all directories that are a direct child of current directory |
| 490 | - if (is_dir($cache_folder) && is_writable($cache_folder)) { | |
| 682 | + if (is_dir($cache_folder) && wp_is_writable($cache_folder)) { | |
| 491 | 683 | if ($handle = opendir($cache_folder)) { |
| 492 | 684 | while (false !== ($d = readdir($handle))) { |
| 493 | - if (0 == strcmp($d, '.') || 0 == strcmp($d, '..')) { | |
| 685 | + if (0 === strcmp($d, '.') || 0 === strcmp($d, '..')) { | |
| 494 | 686 | continue; |
| 495 | 687 | } |
| 496 | 688 | |
| 497 | 689 | if ($this->is_front_page_cache($d)) { |
| @@ -496,9 +688,9 @@ | ||
| 496 | 688 | |
| 497 | 689 | if ($this->is_front_page_cache($d)) { |
| 498 | 690 | $modified_time = (int) filemtime("$cache_folder/$d"); |
| 499 | 691 | if ($modified_time <= $expires) { |
| 500 | - unlink("$cache_folder/$d"); | |
| 692 | + wp_delete_file("$cache_folder/$d"); | |
| 501 | 693 | } |
| 502 | 694 | continue; |
| 503 | 695 | } |
| 504 | 696 | |
| @@ -510,9 +702,9 @@ | ||
| 510 | 702 | $log[] = "checking if cache has expired - $d"; |
| 511 | 703 | if ($modified_time <= $expires) { |
| 512 | 704 | $log[] = "deleting cache in $dir"; |
| 513 | 705 | wpo_delete_files($dir, true); |
| 514 | - if (file_exists($dir)) rmdir($dir); | |
| 706 | + if (file_exists($dir)) rmdir($dir); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- N/A | |
| 515 | 707 | } |
| 516 | 708 | } |
| 517 | 709 | closedir($handle); |
| 518 | 710 | } |
| @@ -546,36 +738,40 @@ | ||
| 546 | 738 | return true; |
| 547 | 739 | } |
| 548 | 740 | |
| 549 | 741 | /** |
| 550 | - * Check if cache is enabled and working | |
| 742 | + * Checks whether page caching is turned on in settings. | |
| 551 | 743 | * |
| 552 | - * @return bool - true on success, false otherwise | |
| 744 | + * @return bool true if the `enable_page_caching` option is set & environment is ready to cache, false otherwise. | |
| 553 | 745 | */ |
| 554 | 746 | public function is_enabled() { |
| 747 | + return $this->config->get_option('enable_page_caching') && $this->is_environment_functional(); | |
| 748 | + } | |
| 555 | 749 | |
| 556 | - if (!$this->config->get_option('enable_page_caching')) return false; | |
| 750 | + /** | |
| 751 | + * Checks whether the cache delivery chain is actually intact and able to serve cached pages. | |
| 752 | + * | |
| 753 | + * Verifies the WP_CACHE and WPO_ADVANCED_CACHE constants are defined and true, and that the cache config file exists on disk. | |
| 754 | + * | |
| 755 | + * @return bool True if the delivery chain is functional, false otherwise. | |
| 756 | + */ | |
| 757 | + private function is_environment_functional() { | |
| 758 | + $is_cli_or_ajax = (defined('WP_CLI') && WP_CLI) || (defined('DOING_AJAX') && DOING_AJAX); | |
| 557 | 759 | |
| 558 | - if (!defined('WP_CACHE') || !WP_CACHE) { | |
| 559 | - if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) { | |
| 560 | - $this->log("WP_CACHE constant is not present in wp-config.php"); | |
| 561 | - return false; | |
| 562 | - } | |
| 760 | + if (!$is_cli_or_ajax && (!defined('WP_CACHE') || !WP_CACHE)) { | |
| 761 | + $this->file_log("WP_CACHE constant is not present in wp-config.php"); | |
| 762 | + return false; | |
| 563 | 763 | } |
| 564 | 764 | |
| 565 | - if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { | |
| 566 | - if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) { | |
| 567 | - $this->log("WPO_ADVANCED_CACHE constant is not present in advanced-cache.php"); | |
| 568 | - return false; | |
| 569 | - } | |
| 765 | + if (!$is_cli_or_ajax && (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE)) { | |
| 766 | + $this->file_log("WPO_ADVANCED_CACHE constant is not present in advanced-cache.php"); | |
| 767 | + return false; | |
| 570 | 768 | } |
| 571 | 769 | |
| 572 | 770 | $config_file = WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename(); |
| 573 | - if (!file_exists($config_file)) { | |
| 574 | - if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) { | |
| 575 | - $this->log("Cache config file $config_file is not present"); | |
| 576 | - return false; | |
| 577 | - } | |
| 771 | + if (!$is_cli_or_ajax && !file_exists($config_file)) { | |
| 772 | + $this->file_log("Cache config file $config_file is not present"); | |
| 773 | + return false; | |
| 578 | 774 | } |
| 579 | 775 | |
| 580 | 776 | return true; |
| 581 | 777 | } |
| @@ -582,23 +778,26 @@ | ||
| 582 | 778 | |
| 583 | 779 | /** |
| 584 | 780 | * Create the folder structure needed for cache to work |
| 585 | 781 | * |
| 586 | - * @return bool - true on success, false otherwise | |
| 782 | + * @return bool | WP_Error - true on success, false otherwise | |
| 587 | 783 | */ |
| 588 | 784 | public function create_folders() { |
| 589 | 785 | $permissions_str = __('Please check your file permissions.', 'wp-optimize'); |
| 590 | 786 | |
| 591 | 787 | if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) { |
| 788 | + // translators: %s is a directory name | |
| 592 | 789 | 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); |
| 593 | 790 | } |
| 594 | 791 | |
| 595 | 792 | if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) { |
| 793 | + // translators: %s is a directory name | |
| 596 | 794 | 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); |
| 597 | 795 | } |
| 598 | 796 | |
| 599 | 797 | if (!is_dir(WPO_CACHE_FILES_DIR)) { |
| 600 | 798 | if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) { |
| 799 | + // translators: %s is a directory name | |
| 601 | 800 | 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); |
| 602 | 801 | } else { |
| 603 | 802 | wpo_disable_cache_directories_viewing(); |
| 604 | 803 | } |
| @@ -629,9 +828,9 @@ | ||
| 629 | 828 | $cache_path = '/wpo-cache'; |
| 630 | 829 | $cache_files_path = '/cache/wpo-cache'; |
| 631 | 830 | $cache_extensions_path = WPO_CACHE_EXT_DIR; |
| 632 | 831 | $wpo_version = WPO_VERSION; |
| 633 | - $wpo_home_url = trailingslashit(home_url()); | |
| 832 | + $wpo_home_url = trailingslashit(network_home_url()); | |
| 634 | 833 | $abspath = ABSPATH; |
| 635 | 834 | |
| 636 | 835 | // CS does not like heredoc |
| 637 | 836 | // phpcs:disable |
| @@ -712,15 +911,15 @@ | ||
| 712 | 911 | } |
| 713 | 912 | |
| 714 | 913 | // check if we can't write the advanced cache file |
| 715 | 914 | // case 1: the directory is read-only and the file doesn't exist |
| 716 | - if (!is_file($advanced_cache_filename) && !is_writable(dirname($advanced_cache_filename))) { | |
| 915 | + if (!is_file($advanced_cache_filename) && !wp_is_writable(dirname($advanced_cache_filename))) { | |
| 717 | 916 | $this->advanced_cache_file_writing_error = true; |
| 718 | 917 | return false; |
| 719 | 918 | } |
| 720 | 919 | |
| 721 | 920 | // case 2: the file already exists but it's read-only |
| 722 | - if (is_file($advanced_cache_filename) && !is_writable($advanced_cache_filename)) { | |
| 921 | + if (is_file($advanced_cache_filename) && !wp_is_writable($advanced_cache_filename)) { | |
| 723 | 922 | if (version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<') || $update_required) { |
| 724 | 923 | $this->advanced_cache_file_writing_error = true; |
| 725 | 924 | return false; |
| 726 | 925 | } else { |
| @@ -753,10 +952,18 @@ | ||
| 753 | 952 | |
| 754 | 953 | // from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php |
| 755 | 954 | // if the site url or folder changed we also update advanced-cache.php |
| 756 | 955 | $advanced_cache_current_version = $this->get_advanced_cache_version(); |
| 757 | - if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=') && !$this->is_the_site_url_or_folder_changed()) return; | |
| 956 | + $is_the_site_url_or_folder_changed = $this->is_the_site_url_or_folder_changed(); | |
| 758 | 957 | |
| 958 | + if ($advanced_cache_current_version && version_compare($advanced_cache_current_version, $this->_minimum_advanced_cache_file_version, '>=') && !$is_the_site_url_or_folder_changed) return; | |
| 959 | + | |
| 960 | + // Purge the cache when the site url or folder changed. | |
| 961 | + if ($is_the_site_url_or_folder_changed) { | |
| 962 | + $is_cache_purged = $this->purge(); | |
| 963 | + if ($is_cache_purged) $this->file_log("Full Cache Purge triggered by: ". __METHOD__); | |
| 964 | + } | |
| 965 | + | |
| 759 | 966 | if (!$this->write_advanced_cache()) { |
| 760 | 967 | add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error')); |
| 761 | 968 | } else { |
| 762 | 969 | $this->update_cache_config(); |
| @@ -775,11 +982,11 @@ | ||
| 775 | 982 | |
| 776 | 983 | if (false === $content) return false; |
| 777 | 984 | |
| 778 | 985 | if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\) (\(homeurl: (.+)\)) (\(abspath: (.+)\)) \(do not change/Ui', $content, $match)) { |
| 779 | - $wpo_home_url = trailingslashit(home_url()); | |
| 986 | + $wpo_home_url = trailingslashit(network_home_url()); | |
| 780 | 987 | $abspath = ABSPATH; |
| 781 | - return ($wpo_home_url != $match[3] || $abspath != $match[5]); | |
| 988 | + return ($wpo_home_url !== $match[3] || $abspath !== $match[5]); | |
| 782 | 989 | } elseif (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) { |
| 783 | 990 | return true; |
| 784 | 991 | } |
| 785 | 992 | |
| @@ -832,8 +1039,13 @@ | ||
| 832 | 1039 | if (!$config_path) { |
| 833 | 1040 | return false; |
| 834 | 1041 | } |
| 835 | 1042 | |
| 1043 | + // Bail early if wp-config.php is not writable, to avoid a PHP warning. | |
| 1044 | + if (!wp_is_writable($config_path)) { | |
| 1045 | + return false; | |
| 1046 | + } | |
| 1047 | + | |
| 836 | 1048 | $config_file_string = file_get_contents($config_path); |
| 837 | 1049 | |
| 838 | 1050 | // Config file is empty. Maybe couldn't read it? |
| 839 | 1051 | if (empty($config_file_string)) { |
| @@ -886,9 +1098,9 @@ | ||
| 886 | 1098 | } |
| 887 | 1099 | $errors = 0; |
| 888 | 1100 | |
| 889 | 1101 | // First check wp-config.php. |
| 890 | - if (!$this->_get_wp_config() && !is_writable($this->_get_wp_config())) { | |
| 1102 | + if (!$this->_get_wp_config() && !wp_is_writable($this->_get_wp_config())) { | |
| 891 | 1103 | $this->log("Unable to write to or find wp-config.php; please check file/folder permissions"); |
| 892 | 1104 | $this->add_warning('verify_cache', __("Unable to write to or find wp-config.php; please check file/folder permissions.", 'wp-optimize')); |
| 893 | 1105 | } |
| 894 | 1106 | |
| @@ -894,9 +1106,9 @@ | ||
| 894 | 1106 | |
| 895 | 1107 | $advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php'; |
| 896 | 1108 | |
| 897 | 1109 | // Now check wp-content. We need to be able to create files of the same user as this file. |
| 898 | - 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))) { | |
| 1110 | + if ((!file_exists($advanced_cache_file) || false === strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) && !wp_is_writable($advanced_cache_file) && !wp_is_writable(untrailingslashit(WP_CONTENT_DIR))) { | |
| 899 | 1111 | $this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions"); |
| 900 | 1112 | $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')); |
| 901 | 1113 | $errors++; |
| 902 | 1114 | } |
| @@ -901,16 +1113,17 @@ | ||
| 901 | 1113 | $errors++; |
| 902 | 1114 | } |
| 903 | 1115 | |
| 904 | 1116 | if (file_exists(WPO_CACHE_FILES_DIR)) { |
| 905 | - if (!is_writable(WPO_CACHE_FILES_DIR)) { | |
| 1117 | + if (!wp_is_writable(WPO_CACHE_FILES_DIR)) { | |
| 906 | 1118 | $this->log("Unable to write inside the cache files folder; please check file/folder permissions"); |
| 1119 | + // translators: %s is cache folder path | |
| 907 | 1120 | $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)); |
| 908 | 1121 | } |
| 909 | 1122 | } |
| 910 | 1123 | |
| 911 | 1124 | if (file_exists(WPO_CACHE_CONFIG_DIR)) { |
| 912 | - if (!is_writable(WPO_CACHE_CONFIG_DIR)) { | |
| 1125 | + if (!wp_is_writable(WPO_CACHE_CONFIG_DIR)) { | |
| 913 | 1126 | $this->log("Unable to write inside the cache configuration folder; please check file/folder permissions"); |
| 914 | 1127 | // If the config exists, only send a warning. Otherwise send an error. |
| 915 | 1128 | $type = 'warning'; |
| 916 | 1129 | if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename())) { |
| @@ -916,8 +1129,9 @@ | ||
| 916 | 1129 | if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename())) { |
| 917 | 1130 | $type = 'error'; |
| 918 | 1131 | $errors++; |
| 919 | 1132 | } |
| 1133 | + // translators: %s is cache config folder path | |
| 920 | 1134 | $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); |
| 921 | 1135 | } |
| 922 | 1136 | } |
| 923 | 1137 | |
| @@ -932,9 +1146,9 @@ | ||
| 932 | 1146 | * @param string $option Option name `permalink_structure` |
| 933 | 1147 | */ |
| 934 | 1148 | public function update_option_permalink_structure($old_value, $value, $option) { |
| 935 | 1149 | $current_config = $this->config->get(); |
| 936 | - if ($old_value != $value) { | |
| 1150 | + if ($old_value !== $value) { | |
| 937 | 1151 | $current_config[$option] = $value; |
| 938 | 1152 | $this->config->update($current_config, true); |
| 939 | 1153 | } |
| 940 | 1154 | } |
| @@ -941,9 +1155,9 @@ | ||
| 941 | 1155 | |
| 942 | 1156 | /** |
| 943 | 1157 | * Update cache config. Used to support 3d party plugins. |
| 944 | 1158 | * |
| 945 | - * @return {boolean|WP_Error} | |
| 1159 | + * @return bool | WP_Error | |
| 946 | 1160 | */ |
| 947 | 1161 | public function update_cache_config() { |
| 948 | 1162 | // get current cache settings. |
| 949 | 1163 | $current_config = $this->config->get(); |
| @@ -954,18 +1168,29 @@ | ||
| 954 | 1168 | /** |
| 955 | 1169 | * Delete information about cache size. |
| 956 | 1170 | */ |
| 957 | 1171 | public function delete_cache_size_information() { |
| 1172 | + //not removing delete_transient so it clear this key from option table | |
| 958 | 1173 | delete_transient('wpo_get_cache_size'); |
| 1174 | + delete_site_transient('wpo_get_cache_size'); | |
| 959 | 1175 | } |
| 960 | 1176 | |
| 961 | 1177 | /** |
| 1178 | + * Update cache cleared time | |
| 1179 | + */ | |
| 1180 | + public function update_cache_cleared_time(): void { | |
| 1181 | + $config = $this->config->get(); | |
| 1182 | + $config['last_cleared'] = time(); | |
| 1183 | + $this->config->update($config); | |
| 1184 | + } | |
| 1185 | + | |
| 1186 | + /** | |
| 962 | 1187 | * Get current cache size. |
| 963 | 1188 | * |
| 964 | 1189 | * @return array |
| 965 | 1190 | */ |
| 966 | 1191 | public function get_cache_size() { |
| 967 | - $cache_size = get_transient('wpo_get_cache_size'); | |
| 1192 | + $cache_size = get_site_transient('wpo_get_cache_size'); | |
| 968 | 1193 | |
| 969 | 1194 | if (!empty($cache_size)) return $cache_size; |
| 970 | 1195 | |
| 971 | 1196 | $infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR); |
| @@ -973,9 +1198,11 @@ | ||
| 973 | 1198 | 'size' => $infos['size'], |
| 974 | 1199 | 'file_count' => $infos['file_count'] |
| 975 | 1200 | ); |
| 976 | 1201 | |
| 977 | - set_transient('wpo_get_cache_size', $cache_size); | |
| 1202 | + $expiration = apply_filters('wpo_cache_size_expiration', DAY_IN_SECONDS); | |
| 1203 | + $expiration = is_numeric($expiration) ? (int) $expiration : DAY_IN_SECONDS; | |
| 1204 | + set_site_transient('wpo_get_cache_size', $cache_size, $expiration); | |
| 978 | 1205 | |
| 979 | 1206 | return $cache_size; |
| 980 | 1207 | } |
| 981 | 1208 | |
| @@ -985,39 +1212,12 @@ | ||
| 985 | 1212 | * @param string $dir |
| 986 | 1213 | * @return array |
| 987 | 1214 | */ |
| 988 | 1215 | private function get_dir_infos($dir) { |
| 989 | - $dir_size = 0; | |
| 990 | - $file_count = 0; | |
| 1216 | + $filtered = apply_filters('wpo_cache_size_files_to_ignore', $this->files_to_ignore); | |
| 1217 | + $this->files_to_ignore = is_array($filtered) ? $filtered : array(); | |
| 991 | 1218 | |
| 992 | - $handle = is_dir($dir) ? opendir($dir) : false; | |
| 993 | - | |
| 994 | - if (false === $handle) { | |
| 995 | - return array('size' => 0, 'file_count' => 0); | |
| 996 | - } | |
| 997 | - | |
| 998 | - $file = readdir($handle); | |
| 999 | - | |
| 1000 | - while (false !== $file) { | |
| 1001 | - | |
| 1002 | - if ('.' != $file && '..' != $file) { | |
| 1003 | - $current_file = $dir.'/'.$file; | |
| 1004 | - | |
| 1005 | - if (is_dir($current_file)) { | |
| 1006 | - $sub_dir_infos = $this->get_dir_infos($current_file); | |
| 1007 | - $dir_size += $sub_dir_infos['size']; | |
| 1008 | - $file_count += $sub_dir_infos['file_count']; | |
| 1009 | - } elseif (is_file($current_file)) { | |
| 1010 | - $dir_size += filesize($current_file); | |
| 1011 | - $file_count++; | |
| 1012 | - } | |
| 1013 | - } | |
| 1014 | - | |
| 1015 | - $file = readdir($handle); | |
| 1016 | - | |
| 1017 | - } | |
| 1018 | - | |
| 1019 | - return array('size' => $dir_size, 'file_count' => $file_count); | |
| 1219 | + return WP_Optimize_Utils::get_folder_stats($dir, $this->files_to_ignore); | |
| 1020 | 1220 | } |
| 1021 | 1221 | |
| 1022 | 1222 | /** |
| 1023 | 1223 | * Returns the path to wp-config |
| @@ -1049,11 +1249,9 @@ | ||
| 1049 | 1249 | * @param string $src |
| 1050 | 1250 | * @return boolean |
| 1051 | 1251 | */ |
| 1052 | 1252 | public static function delete($src) { |
| 1053 | - | |
| 1054 | 1253 | return wpo_delete_files($src); |
| 1055 | - | |
| 1056 | 1254 | } |
| 1057 | 1255 | |
| 1058 | 1256 | /** |
| 1059 | 1257 | * Delete cached files for specific url. |
| @@ -1063,18 +1261,49 @@ | ||
| 1063 | 1261 | * |
| 1064 | 1262 | * @return bool |
| 1065 | 1263 | */ |
| 1066 | 1264 | public static function delete_cache_by_url($url, $recursive = false) { |
| 1067 | - if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return; | |
| 1265 | + if (!defined('WPO_CACHE_FILES_DIR') || '' === $url) return false; | |
| 1068 | 1266 | |
| 1069 | 1267 | $path = self::get_full_path_from_url($url); |
| 1070 | 1268 | |
| 1071 | 1269 | do_action('wpo_delete_cache_by_url', $url, $recursive); |
| 1072 | 1270 | |
| 1271 | + do_action('wpo_preload_url', $url); | |
| 1272 | + | |
| 1073 | 1273 | return wpo_delete_files($path, $recursive); |
| 1074 | 1274 | } |
| 1075 | 1275 | |
| 1076 | 1276 | /** |
| 1277 | + * Adds the URL to the preload list and hooks the preload task to shutdown | |
| 1278 | + * | |
| 1279 | + * @param string $url | |
| 1280 | + * @return void | |
| 1281 | + */ | |
| 1282 | + public function maybe_preload_url($url) { | |
| 1283 | + if (!$this->should_auto_preload_purged_contents()) return; | |
| 1284 | + | |
| 1285 | + static $urls_preloaded = array(); | |
| 1286 | + | |
| 1287 | + // Remove the query string from the URL | |
| 1288 | + $url = preg_replace('/\?.*/', '', $url); | |
| 1289 | + | |
| 1290 | + if (!in_array($url, $urls_preloaded)) { | |
| 1291 | + $urls_preloaded[] = $url; | |
| 1292 | + | |
| 1293 | + $preloader = WP_Optimize_Page_Cache_Preloader::instance(); | |
| 1294 | + $preloader->add_url_to_preload_list($url); | |
| 1295 | + $url_task_creator = array($preloader, 'create_tasks_for_auto_preload_urls'); | |
| 1296 | + | |
| 1297 | + $preloader->maybe_dont_close_browser_connection(); | |
| 1298 | + | |
| 1299 | + if (!has_action('shutdown', $url_task_creator)) { | |
| 1300 | + add_action('shutdown', $url_task_creator); | |
| 1301 | + } | |
| 1302 | + } | |
| 1303 | + } | |
| 1304 | + | |
| 1305 | + /** | |
| 1077 | 1306 | * Delete cached files for single post. |
| 1078 | 1307 | * |
| 1079 | 1308 | * @param integer $post_id The post ID |
| 1080 | 1309 | * |
| @@ -1096,9 +1325,9 @@ | ||
| 1096 | 1325 | * @return bool |
| 1097 | 1326 | */ |
| 1098 | 1327 | public static function really_delete_single_post_cache($post_id) { |
| 1099 | 1328 | |
| 1100 | - if (!defined('WPO_CACHE_FILES_DIR')) return; | |
| 1329 | + if (!defined('WPO_CACHE_FILES_DIR')) return false; | |
| 1101 | 1330 | |
| 1102 | 1331 | $post_url = get_permalink($post_id); |
| 1103 | 1332 | |
| 1104 | 1333 | $path = self::get_full_path_from_url($post_url); |
| @@ -1108,8 +1337,10 @@ | ||
| 1108 | 1337 | $recursive = preg_match('/\<\!--nextpage--\>/', $post->post_content) ? true : false; |
| 1109 | 1338 | |
| 1110 | 1339 | do_action('wpo_delete_cache_by_url', $post_url, $recursive); |
| 1111 | 1340 | |
| 1341 | + do_action('wpo_preload_url', $post_url); | |
| 1342 | + | |
| 1112 | 1343 | return wpo_delete_files($path, $recursive); |
| 1113 | 1344 | } |
| 1114 | 1345 | |
| 1115 | 1346 | /** |
| @@ -1122,11 +1353,15 @@ | ||
| 1122 | 1353 | $homepage_url = get_home_url(get_current_blog_id()); |
| 1123 | 1354 | |
| 1124 | 1355 | $path = self::get_full_path_from_url($homepage_url); |
| 1125 | 1356 | |
| 1126 | - do_action('wpo_delete_cache_by_url', $homepage_url, false); | |
| 1357 | + $recursive = false; | |
| 1127 | 1358 | |
| 1128 | - wpo_delete_files($path, false); | |
| 1359 | + do_action('wpo_delete_cache_by_url', $homepage_url, $recursive); | |
| 1360 | + | |
| 1361 | + do_action('wpo_preload_url', $homepage_url); | |
| 1362 | + | |
| 1363 | + wpo_delete_files($path, $recursive); | |
| 1129 | 1364 | } |
| 1130 | 1365 | |
| 1131 | 1366 | /** |
| 1132 | 1367 | * Delete feed from cache. |
| @@ -1144,8 +1379,10 @@ | ||
| 1144 | 1379 | } |
| 1145 | 1380 | |
| 1146 | 1381 | /** |
| 1147 | 1382 | * Delete post feed from cache. |
| 1383 | + * | |
| 1384 | + * @param int $post_id Post ID | |
| 1148 | 1385 | */ |
| 1149 | 1386 | public static function delete_post_feed_cache($post_id) { |
| 1150 | 1387 | self::really_delete_post_feed_cache($post_id); |
| 1151 | 1388 | |
| @@ -1153,8 +1390,10 @@ | ||
| 1153 | 1390 | } |
| 1154 | 1391 | |
| 1155 | 1392 | /** |
| 1156 | 1393 | * Really delete post feed from cache. |
| 1394 | + * | |
| 1395 | + * @param int $post_id Post ID | |
| 1157 | 1396 | */ |
| 1158 | 1397 | public static function really_delete_post_feed_cache($post_id) { |
| 1159 | 1398 | if (!defined('WPO_CACHE_FILES_DIR')) return; |
| 1160 | 1399 | |
| @@ -1183,9 +1422,9 @@ | ||
| 1183 | 1422 | |
| 1184 | 1423 | // delete empty comments dir from the cache |
| 1185 | 1424 | $comments_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/'; |
| 1186 | 1425 | $path = self::get_full_path_from_url($comments_url); |
| 1187 | - | |
| 1426 | + | |
| 1188 | 1427 | if (wpo_is_empty_dir($path)) { |
| 1189 | 1428 | wpo_delete_files($path, true); |
| 1190 | 1429 | } |
| 1191 | 1430 | } |
| @@ -1206,9 +1445,9 @@ | ||
| 1206 | 1445 | * @return void |
| 1207 | 1446 | */ |
| 1208 | 1447 | public function admin_init() { |
| 1209 | 1448 | // Maybe update the advanced cache. |
| 1210 | - if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) { | |
| 1449 | + if ((!defined('DOING_AJAX') || !DOING_AJAX) && WP_Optimize()->current_user_can('update_plugins')) { | |
| 1211 | 1450 | $this->maybe_update_advanced_cache(); |
| 1212 | 1451 | $this->cron_activate(); |
| 1213 | 1452 | } |
| 1214 | 1453 | } |
| @@ -1227,9 +1466,9 @@ | ||
| 1227 | 1466 | |
| 1228 | 1467 | /** |
| 1229 | 1468 | * Returns an instance of the current class, creates one if it doesn't exist |
| 1230 | 1469 | * |
| 1231 | - * @return object | |
| 1470 | + * @return self | |
| 1232 | 1471 | */ |
| 1233 | 1472 | public static function instance() { |
| 1234 | 1473 | if (empty(self::$instance)) { |
| 1235 | 1474 | self::$instance = new self(); |
| @@ -1240,19 +1479,19 @@ | ||
| 1240 | 1479 | |
| 1241 | 1480 | /** |
| 1242 | 1481 | * Update gmt_offset and timezone_string cache config value, used with hook `update_gmt_offset_timezone_string_config`. |
| 1243 | 1482 | * |
| 1244 | - * @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) | |
| 1245 | - * @param {float|string} $new_value | |
| 1246 | - * @param {string} $option gmt_offset|timezone_string | |
| 1483 | + * @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) | |
| 1484 | + * @param float | string $new_value | |
| 1485 | + * @param string $option gmt_offset|timezone_string | |
| 1247 | 1486 | * |
| 1248 | 1487 | * @return null |
| 1249 | 1488 | */ |
| 1250 | 1489 | public function update_gmt_offset_timezone_string_config($old_value, $new_value, $option) { |
| 1251 | - if ('' == $new_value) return; | |
| 1490 | + if ('' === $new_value) return; | |
| 1252 | 1491 | |
| 1253 | 1492 | $current_config = $this->config->get(); |
| 1254 | - if ('timezone_string' == $option) { | |
| 1493 | + if ('timezone_string' === $option) { | |
| 1255 | 1494 | $timeZone = new DateTimeZone($new_value); |
| 1256 | 1495 | $dateTime = new DateTime("now"); |
| 1257 | 1496 | $gmt_offset = $timeZone->getOffset($dateTime); |
| 1258 | 1497 | $current_config['gmt_offset'] = round($gmt_offset/3600, 1); |
| @@ -1372,9 +1611,9 @@ | ||
| 1372 | 1611 | public function is_pagespeedninja_gzip_active() { |
| 1373 | 1612 | if (!class_exists('PagespeedNinja')) return false; |
| 1374 | 1613 | |
| 1375 | 1614 | $options = get_option('pagespeedninja_config'); |
| 1376 | - $gzip = !empty($options) ? (bool) $options['psi_EnableGzipCompression'] && (bool) $options['html_gzip'] : false; | |
| 1615 | + $gzip = isset($options['psi_EnableGzipCompression']) && isset($options['html_gzip']) && (bool) $options['psi_EnableGzipCompression'] && (bool) $options['html_gzip']; | |
| 1377 | 1616 | |
| 1378 | 1617 | return $gzip; |
| 1379 | 1618 | } |
| 1380 | 1619 | |
| @@ -1381,9 +1620,9 @@ | ||
| 1381 | 1620 | /** |
| 1382 | 1621 | * Output PageSpeed Ninja Gzip notice. |
| 1383 | 1622 | */ |
| 1384 | 1623 | public function show_pagespeedninja_gzip_notice() { |
| 1385 | - 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>'; | |
| 1624 | + echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.esc_html__('WP-Optimize:', 'wp-optimize').'</b> '.esc_html__('Please disable the feature "Gzip compression" in PageSpeed Ninja to prevent conflicts.', 'wp-optimize').'</p></div>'; | |
| 1386 | 1625 | } |
| 1387 | 1626 | |
| 1388 | 1627 | /** |
| 1389 | 1628 | * Check if Far Future Expiration is active and GZIP compression option is enabled. |
| @@ -1393,9 +1632,9 @@ | ||
| 1393 | 1632 | public function is_farfutureexpiration_gzip_active() { |
| 1394 | 1633 | if (!class_exists('farFutureExpiration')) return false; |
| 1395 | 1634 | |
| 1396 | 1635 | $options = get_option('far_future_expiration_settings'); |
| 1397 | - $gzip = !empty($options) ? (bool) $options['enable_gzip'] : false; | |
| 1636 | + $gzip = !empty($options) && $options['enable_gzip']; | |
| 1398 | 1637 | |
| 1399 | 1638 | return $gzip; |
| 1400 | 1639 | } |
| 1401 | 1640 | |
| @@ -1402,9 +1641,9 @@ | ||
| 1402 | 1641 | /** |
| 1403 | 1642 | * Output Far Future Expiration Gzip notice. |
| 1404 | 1643 | */ |
| 1405 | 1644 | public function show_farfutureexpiration_gzip_notice() { |
| 1406 | - 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>'; | |
| 1645 | + echo '<div id="wp-optimize-pagespeedninja-gzip-notice" class="error wpo-notice"><p><b>'.esc_html__('WP-Optimize:', 'wp-optimize').'</b> '.esc_html__('Please disable the feature "Gzip compression" in Far Future Expiration to prevent conflicts.', 'wp-optimize').'</p></div>'; | |
| 1407 | 1646 | } |
| 1408 | 1647 | |
| 1409 | 1648 | /** |
| 1410 | 1649 | * This is a notice to show users that writing `advanced-cache.php` failed |
| @@ -1409,8 +1648,9 @@ | ||
| 1409 | 1648 | /** |
| 1410 | 1649 | * This is a notice to show users that writing `advanced-cache.php` failed |
| 1411 | 1650 | */ |
| 1412 | 1651 | public function show_admin_notice_advanced_cache() { |
| 1652 | + // translators: %s is advanced-cache.php file path | |
| 1413 | 1653 | $message = sprintf(__('The request to write the file %s failed.', 'wp-optimize'), htmlspecialchars($this->get_advanced_cache_filename())); |
| 1414 | 1654 | $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); |
| 1415 | 1655 | WP_Optimize()->include_template('notices/cache-notice.php', false, array('message' => $message)); |
| 1416 | 1656 | } |
| @@ -1434,13 +1674,15 @@ | ||
| 1434 | 1674 | |
| 1435 | 1675 | $interval = WP_Optimize_Page_Cache_Preloader::instance()->get_continue_preload_cron_interval(); |
| 1436 | 1676 | $schedules['wpo_page_cache_preload_continue_interval'] = array( |
| 1437 | 1677 | 'interval' => $interval, |
| 1678 | + // translators: %d is the number of minutes | |
| 1438 | 1679 | 'display' => sprintf(__('%d minutes', 'wp-optimize'), round($interval / 60, 1)) |
| 1439 | 1680 | ); |
| 1440 | 1681 | |
| 1441 | 1682 | $schedules['wpo_use_cache_lifespan'] = array( |
| 1442 | 1683 | 'interval' => $page_cache_length, |
| 1684 | + // translators: %s is the cache lifespan | |
| 1443 | 1685 | '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')) |
| 1444 | 1686 | ); |
| 1445 | 1687 | |
| 1446 | 1688 | return $schedules; |
| @@ -1457,9 +1699,9 @@ | ||
| 1457 | 1699 | } |
| 1458 | 1700 | } |
| 1459 | 1701 | |
| 1460 | 1702 | /** |
| 1461 | - * May be regenerate cache config file, in case of migrations | |
| 1703 | + * Maybe regenerate cache config file, in case of migrations | |
| 1462 | 1704 | */ |
| 1463 | 1705 | public function maybe_regenerate_cache_config_file() { |
| 1464 | 1706 | $config_file = WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename(); |
| 1465 | 1707 | if (!file_exists($config_file)) { |
| @@ -1478,9 +1720,9 @@ | ||
| 1478 | 1720 | if (!is_dir($path)) return true; |
| 1479 | 1721 | |
| 1480 | 1722 | if ($handle = opendir($path)) { |
| 1481 | 1723 | while (false !== ($entry = readdir($handle))) { |
| 1482 | - if ("." == $entry || ".." == $entry) { | |
| 1724 | + if ("." === $entry || ".." === $entry) { | |
| 1483 | 1725 | continue; |
| 1484 | 1726 | } |
| 1485 | 1727 | |
| 1486 | 1728 | $full_path = $path . '/' . $entry; |
| @@ -1492,8 +1734,136 @@ | ||
| 1492 | 1734 | closedir($handle); |
| 1493 | 1735 | return true; |
| 1494 | 1736 | } |
| 1495 | 1737 | return true; |
| 1738 | + } | |
| 1739 | + | |
| 1740 | + /** | |
| 1741 | + * Remove query params from request url | |
| 1742 | + * | |
| 1743 | + * @param string $url The request url. | |
| 1744 | + * @return string Returns url without query params. | |
| 1745 | + */ | |
| 1746 | + private static function remove_query_params($url) { | |
| 1747 | + $parsed_url = wp_parse_url($url); | |
| 1748 | + if (!$parsed_url) return ''; | |
| 1749 | + return $parsed_url['scheme'] . '://' . $parsed_url['host'] . $parsed_url['path']; | |
| 1750 | + } | |
| 1751 | + | |
| 1752 | + /** | |
| 1753 | + * Check configuration for auto preloading after cache deletion | |
| 1754 | + * | |
| 1755 | + * @return bool | |
| 1756 | + */ | |
| 1757 | + public function should_auto_preload_purged_contents() { | |
| 1758 | + | |
| 1759 | + if (!$this->is_enabled()) return false; // as Page Cache is not enabled we should not auto preload purged content. | |
| 1760 | + | |
| 1761 | + $wpo_cache = WP_Optimize()->get_page_cache(); | |
| 1762 | + $wpo_cache_options = $wpo_cache->config->get(); | |
| 1763 | + | |
| 1764 | + return $wpo_cache_options['auto_preload_purged_contents']; | |
| 1765 | + } | |
| 1766 | + | |
| 1767 | + /** | |
| 1768 | + * Logging of interesting messages related to Cache Purging | |
| 1769 | + * | |
| 1770 | + * @param string $message | |
| 1771 | + * @param int $post_id | |
| 1772 | + */ | |
| 1773 | + public function file_log($message, $post_id = 0) { | |
| 1774 | + if (!empty($post_id)) { | |
| 1775 | + if (false !== strpos($message, '{{URL}}')) { | |
| 1776 | + $message = str_replace('{{URL}}', get_permalink($post_id), $message); | |
| 1777 | + } | |
| 1778 | + if (false !== strpos($message, '{{title}}')) { | |
| 1779 | + $message = str_replace('{{title}}', '"' . get_the_title($post_id) . '"', $message); | |
| 1780 | + } | |
| 1781 | + } | |
| 1782 | + $this->file_logger->info($message); | |
| 1783 | + } | |
| 1784 | + | |
| 1785 | + /** | |
| 1786 | + * Prunes the log file | |
| 1787 | + */ | |
| 1788 | + public function prune_cache_logs() { | |
| 1789 | + $this->file_log("Pruning the Cache log file"); | |
| 1790 | + $this->file_logger->prune_logs(); | |
| 1791 | + } | |
| 1792 | + | |
| 1793 | + /** | |
| 1794 | + * Update .htaccess file to serve cached files directly. | |
| 1795 | + * | |
| 1796 | + * @param bool $enable | |
| 1797 | + */ | |
| 1798 | + public function update_serve_cache_rules_htaccess_section($enable) { | |
| 1799 | + $htaccess = new WP_Optimize_Htaccess(); | |
| 1800 | + | |
| 1801 | + $section_title = 'WP-Optimize rules to serve cached files'; | |
| 1802 | + | |
| 1803 | + if ($enable) { | |
| 1804 | + if (!$htaccess->is_commented_section_exists($section_title)) { | |
| 1805 | + $htaccess->update_commented_section($this->prepare_apache_cache_handle_section(), $section_title, true); | |
| 1806 | + $htaccess->write_file(); | |
| 1807 | + } | |
| 1808 | + } elseif ($htaccess->is_commented_section_exists($section_title)) { | |
| 1809 | + $htaccess->remove_commented_section($section_title); | |
| 1810 | + $htaccess->write_file(); | |
| 1811 | + } | |
| 1812 | + | |
| 1813 | + } | |
| 1814 | + | |
| 1815 | + /** | |
| 1816 | + * Get the .htaccess section with rules to serve cached files | |
| 1817 | + * | |
| 1818 | + * @return array | |
| 1819 | + */ | |
| 1820 | + private function prepare_apache_cache_handle_section() { | |
| 1821 | + | |
| 1822 | + $site_root = $this->get_site_root_path(); | |
| 1823 | + | |
| 1824 | + return array( | |
| 1825 | + array( | |
| 1826 | + '<IfModule mod_rewrite.c>', | |
| 1827 | + 'RewriteEngine On', | |
| 1828 | + 'RewriteCond %{REQUEST_METHOD} GET|HEAD', | |
| 1829 | + 'RewriteCond %{QUERY_STRING} =""', | |
| 1830 | + 'RewriteCond %{HTTP:Cookie} =""', | |
| 1831 | + 'RewriteCond %{REQUEST_URI} !^/(wp-(?:admin|login|register|comments-post|cron|json))/ [NC]', | |
| 1832 | + 'RewriteCond %{HTTP_USER_AGENT} !(android|blackberry|ipad|iphone|ipod|windows.phone|iEMobile|opera.mini|opera.mobile|webos|symbian|windows.mobile|kindle|googlebot.mobile) [NC]', | |
| 1833 | + 'RewriteCond %{DOCUMENT_ROOT}'.$site_root.'wp-content/cache/wpo-cache/%{HTTP_HOST}%{REQUEST_URI}index.html -f', | |
| 1834 | + 'RewriteRule ^(.*)$ '.$site_root.'wp-content/cache/wpo-cache/%{HTTP_HOST}%{REQUEST_URI}index.html [L]', | |
| 1835 | + array( | |
| 1836 | + '<IfModule mod_setenvif.c>', | |
| 1837 | + 'SetEnvIf Request_URI "/wp-content/cache/wpo-cache/" FROM_CACHE=1', | |
| 1838 | + '</IfModule>', | |
| 1839 | + ), | |
| 1840 | + array( | |
| 1841 | + '<IfModule mod_headers.c>', | |
| 1842 | + 'Header always set X-WP-Optimize-Cache-Header "Loaded from WP-Optimize cache" env=FROM_CACHE', | |
| 1843 | + '</IfModule>', | |
| 1844 | + ), | |
| 1845 | + '</IfModule>', | |
| 1846 | + ), | |
| 1847 | + ); | |
| 1848 | + } | |
| 1849 | + | |
| 1850 | + /** | |
| 1851 | + * Get relative site root path, if site is placed in the subdirectory then it returns /subdirectory otherwise / | |
| 1852 | + * | |
| 1853 | + * @param string $default | |
| 1854 | + * | |
| 1855 | + * @return string | |
| 1856 | + */ | |
| 1857 | + private function get_site_root_path($default = '/') { | |
| 1858 | + $site_root = wp_parse_url(site_url()); | |
| 1859 | + if (isset($site_root['path'])) { | |
| 1860 | + $site_root = trailingslashit($site_root['path']); | |
| 1861 | + } else { | |
| 1862 | + $site_root = $default; | |
| 1863 | + } | |
| 1864 | + | |
| 1865 | + return $site_root; | |
| 1496 | 1866 | } |
| 1497 | 1867 | } |
| 1498 | 1868 | |
| 1499 | 1869 | endif; |