D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
everqlsh
/
www
/
wp-admin
/
user
/
577040
/
Filename :
cache.zip
back
Copy
PK ��}\���j~ ~ file-based-page-cache.phpnu �[��� <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * File based page cache drop in */ require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php'); if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache'); /** * Load extensions. */ wpo_cache_load_extensions(); /** * Action triggered when the cache extensions are all loaded. Allows to execute code depending on an other extension, without knowing the order in which the files are loaded. */ do_action('wpo_cache_extensions_loaded'); if (true === wpo_can_serve_from_cache()) { wpo_serve_cache(); } PK ��}\��=� � class-wpo-load-url-task.phpnu �[��� <?php if (!defined('ABSPATH')) die('Access denied.'); if (!class_exists('Updraft_Task_1_2')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php'); class WP_Optimize_Load_Url_Task extends Updraft_Task_1_2 { /** * Default options. */ public function get_default_options() { return array(); } /** * Run preload http requests with different user-agent values to cache pages for different devices. * * @return bool */ public function run() { $url = $this->get_option('url'); if (empty($url)) return; $cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); // load pages with different user-agents values. $cache_preloader->preload_desktop($url); $cache_preloader->preload_mobile($url); $cache_preloader->preload_amp($url); if (defined('WP_CLI') && WP_CLI) { WP_CLI::log($url); } /** * Action triggered after preloading a single url * * @param string $url The url to preload * @param object $cache_preloader Cache preloader instance */ do_action('wpoptimize_after_preload_url', $url, $cache_preloader); /** * Allows to change the delay between each URL preload, to reduce server load. * * @param integer $preload_delay The delay between each request in microseconds (1000000 = 1 second). */ usleep(apply_filters('wpoptimize_preload_delay', 500000)); return true; } } PK ��}\Q� �}\ }\ * class-wp-optimize-page-cache-preloader.phpnu �[��� <?php if (!defined('ABSPATH')) die('No direct access allowed'); if (!class_exists('WP_Optimize_Load_Url_Task')) { require_once(WPO_PLUGIN_MAIN_PATH . 'cache/class-wpo-load-url-task.php'); } class WP_Optimize_Page_Cache_Preloader extends WP_Optimize_Preloader { protected $preload_type = 'page_cache'; protected $task_type = 'load-url-task'; static protected $_instance = null; /** * List of URLs for which a task will be created to preload them into cache * * @var array */ private $url_preload_list = array(); /** * WP_Optimize_Page_Cache_Preloader constructor. */ public function __construct() { parent::__construct(); add_action('wpo_page_cache_schedule_preload', array($this, 'run_scheduled_cache_preload')); add_action('wpo_page_cache_run_preload', array($this, 'run_preload_cron_job')); add_filter('wpo_preload_headers', array($this, 'preload_headers')); } /** * Check if cache is active. * * @return bool */ public function is_option_active() { return WP_Optimize()->get_page_cache()->is_enabled(); } /** * Schedule or delete automatic preload action on cache settings update. * * @param array $new_settings The new settings * @param array $previous_settings Settings before saving */ public function cache_settings_updated($new_settings, $previous_settings) { if (!$new_settings['enable_page_caching']) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); wp_clear_scheduled_hook('wpo_page_cache_run_preload'); $this->delete_preload_continue_action(); return; } if (!empty($new_settings['enable_schedule_preload'])) { $last_schedule_type = $previous_settings['preload_schedule_type']; $last_use_nighttime = $this->options->get_option('page_cache_schedule_preload_nighttime'); // By default, we schedule preload events to the nighttime. $use_nighttime = apply_filters('wpo_page_cache_schedule_preload_use_nighttime', 1); $this->options->update_option('page_cache_schedule_preload_nighttime', $use_nighttime); if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { // if already scheduled this schedule type if ($new_settings['preload_schedule_type'] == $last_schedule_type && ($last_use_nighttime === $use_nighttime)) { // If the schedule type is cache lifespan, check if the cache lifespan changed. if ('wpo_use_cache_lifespan' == $new_settings['preload_schedule_type']) { // Else, if the settings cache lifespan settings haven't changed, returns if ($new_settings['page_cache_length_value'] == $previous_settings['page_cache_length_value'] && $new_settings['page_cache_length_unit'] == $previous_settings['page_cache_length_unit']) { return; } } else { return; } } // clear currently scheduled preload action. wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action. $timestamp = time() + $this->get_schedule_interval($new_settings['preload_schedule_type']); if ($use_nighttime) { $timestamp = $this->make_nighttime($timestamp); } wp_schedule_event($timestamp, $new_settings['preload_schedule_type'], 'wpo_page_cache_schedule_preload'); } else { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } } /** * Clear active preload tasks, reschedule preload action. */ public function reschedule_preload() { // clear scheduled action. if (wp_next_scheduled('wpo_page_cache_schedule_preload')) { wp_clear_scheduled_hook('wpo_page_cache_schedule_preload'); } // schedule preload action if need. if ($this->is_scheduled_preload_enabled()) { $preload_schedule_type = $this->get_cache_config('preload_schedule_type'); // By default, we schedule preload events to the nighttime. $use_nighttime = apply_filters('wpo_page_cache_schedule_preload_use_nighttime', 1); $timestamp = time() + $this->get_schedule_interval($preload_schedule_type); if ($use_nighttime) { $timestamp = $this->make_nighttime($timestamp); } wp_schedule_event($timestamp, $preload_schedule_type, 'wpo_page_cache_schedule_preload'); } } /** * Check if scheduled preload enabled. * * @return bool */ public function is_scheduled_preload_enabled() { $enable_schedule_preload = $this->get_cache_config('enable_schedule_preload'); return !empty($enable_schedule_preload); } /** * Check if we need run cache preload and run it. */ public function run_scheduled_cache_preload() { $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); if (!$schedule_type) return; // Don't run preload if cache lifespan option enabled and cache not expired yet. if ('wpo_use_cache_lifespan' == $schedule_type) { /** * Filters the allowed time difference between the cache exiry and the current time, in seconds. * If the cache expires in less than $allowed_time_difference, preload. Otherwise leave it. * * @param integer $allowed_time_difference The time difference, in seconds (default is same as changed time limit) */ $time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800; $allowed_time_difference = apply_filters('wpo_preload_allowed_time_difference', $time_limit); $page_cache_lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length', 0); $last_preload_time = $this->options->get_option('wpo_last_page_cache_preload', 0); $time_since_last_preload = time() - $last_preload_time; $minimum_time_to_next_schedule_preload = $page_cache_lifespan - $allowed_time_difference; // Skip this if the last preload is not as old as the cache lifespan minus $allowed_time_difference if ($page_cache_lifespan > 0 && $time_since_last_preload < $minimum_time_to_next_schedule_preload) return; } $this->run(); } /** * Runs manual cache preload and reschedules if scheduled preload is enabled * * @return void */ public function run_preload_cron_job() { $wpo_page_cache = WP_Optimize()->get_page_cache(); if ($this->is_scheduled_preload_enabled()) { $this->cancel_preload(); $this->reschedule_preload(); $this->run('scheduled', null, true); } elseif ($wpo_page_cache->should_auto_preload_purged_contents()) { $this->run('manual', null, true); } } /** * Get cache config option value. * * @return mixed */ public function get_cache_config($option) { static $config = null; if (null === $config) $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists($option, $config)) { return $config[$option]; } return false; } /** * Create tasks (WP_Optimize_Load_Url_Task) for preload all urls from site. * * @param string $type The preload type (currently: scheduled, manual) * @return void */ public function create_tasks_for_preload_site_urls($type) { $urls = $this->get_site_urls(); if (!empty($urls)) { $this->log(__('Creating tasks for preload site urls.', 'wp-optimize')); foreach ($urls as $url) { if (wpo_url_in_exceptions($url)) continue; if ($this->url_is_already_cached($url, $type)) { continue; } // this description is being used for internal purposes. $description = 'Preload - '.$url; $options = array('url' => $url, 'preload_type' => $type, 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI)); WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task'); } $this->log(__('Tasks for preload site urls created.', 'wp-optimize')); } } /** * Preload mobile version from $url. * * @param string $url * * @return void */ public function preload_mobile($url) { static $is_mobile_caching_enabled; if (!isset($is_mobile_caching_enabled)) { $is_mobile_caching_enabled = $this->get_cache_config('enable_mobile_caching'); } // Only run if option is active if (!$is_mobile_caching_enabled) return; $mobile_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1', 'timeout' => 10, 'headers' => apply_filters('wpo_preload_headers', array()), ); $mobile_args = apply_filters('wpo_page_cache_preloader_mobile_args', $mobile_args, $url); $this->log('preload_mobile - ' . $url); wp_remote_get($url, $mobile_args); } /** * Preload amp version from $url. * * @param string $url * * @return void */ public function preload_amp($url) { if (!apply_filters('wpo_should_preload_amp', false, $url)) return; $amp_args = array( 'httpversion' => '1.1', 'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36', 'timeout' => 10, 'headers' => array( 'X-WP-Optimize-Cache-Preload' => 'Yes', ), ); $url = untrailingslashit($url) . '/amp/'; $amp_args = apply_filters('wpo_page_cache_preloader_amp_args', $amp_args, $url); $this->log('preload_amp - ' . $url); wp_remote_get($url, $amp_args); } /** * Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls. * * @return array */ public function get_site_urls() { $urls = $this->get_sitemap_urls(); if (!empty($urls)) { $this->options->update_option('wpo_last_page_cache_preload_type', 'sitemap'); } else { $urls = $this->get_post_urls(); $this->options->update_option('wpo_last_page_cache_preload_type', 'posts'); } // translators: %d: Number of URLs found $this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls))); /** * Filter the URLs which will be preloaded * * @param array $urls * @return array */ return apply_filters('wpo_preload_get_site_urls', $urls); } /** * Loads sitemap file and returns list of urls. * * @param string $sitemap_url * * @return array|bool */ public function get_sitemap_urls($sitemap_url = '') { $urls = array(); // if sitemap url is empty then use main sitemap file name. $sitemap_url = ('' === $sitemap_url) ? site_url('/'.$this->get_sitemap_filename()) : $sitemap_url; // if simplexml_load_string not available then we don't load sitemap. if (!function_exists('simplexml_load_string')) { return $urls; } // load sitemap file. $response = wp_remote_get($sitemap_url, array('timeout' => 30)); // if we get error then // sometimes returns error due to timeout if (is_wp_error($response)) { $response = @file_get_contents($sitemap_url); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress warnings when there is network error // if response is empty then try load from file. if (empty($response) && '' == $sitemap_url) { $sitemap_file = $this->get_local_sitemap_file(); if (is_file($sitemap_file)) { $response = file_get_contents($sitemap_file); } } if (empty($response)) return $urls; $xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress warnings when error found in XML data } else { // parse xml answer. $xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress warnings when error found in XML data } // xml file has not valid xml content then return false. if (false === $xml) return false; // if exists urls then return them. if (isset($xml->url)) { foreach ($xml->url as $element) { if (!isset($element->loc)) continue; $urls[] = (string) $element->loc; } } elseif (isset($xml->sitemap)) { // if has links to other sitemap files then get urls from them. foreach ($xml->sitemap as $element) { if (!isset($element->loc)) continue; $sitemap_urls = $this->get_sitemap_urls($element->loc); if (is_array($sitemap_urls)) { $urls = array_merge($urls, $sitemap_urls); } } } return $urls; } /** * Get all posts of any post type and returns urls for them. * * @return array */ public function get_post_urls() { global $post; $offset = 0; $posts_per_page = 1000; $urls = array(); $urls[] = site_url('/'); do { $query = new WP_Query(array( 'post_type' => 'any', 'post_status' => 'publish', 'posts_per_page' => $posts_per_page, 'offset' => $offset, 'orderby' => 'ID', 'order' => 'ASC', 'cache_results' => false, // disable cache to avoid memory error. )); $posts_loaded = $query->post_count; while ($query->have_posts()) { $query->the_post(); $permalink = get_permalink(); $urls[] = $permalink; // check page separators in the post content preg_match_all('/\<\!--nextpage--\>/', $post->post_content, $matches); // if there any separators add urls for each page if (count($matches[0])) { $prefix = strpos($permalink, '?') ? '&page=' : ''; for ($page = 0; $page < count($matches[0]); $page++) { if ('' != $prefix) { $urls[] = $permalink . $prefix . ($page+2); } else { $urls[] = trailingslashit($permalink) . ($page+2); } } } } $offset += $posts_loaded; } while ($posts_loaded > 0); /** * If domain mapping enabled then replace domains in urls. */ if ($this->is_domain_mapping_enabled()) { $blog_id = get_current_blog_id(); $mapped_domain = $this->get_mapped_domain($blog_id); $blog_details = get_blog_details($blog_id); if ($mapped_domain) { foreach ($urls as $i => $url) { $urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1); } } } wp_reset_postdata(); return $urls; } /** * Check if domain mapping enabled. * * @return bool */ public function is_domain_mapping_enabled() { // SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin. $enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE); /** * Filters if Multisite Domain mapping is enabled. * Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use. * Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option. */ return apply_filters('wpo_is_domain_mapping_enabled', $enabled); } /** * Return mapped domain by $blog_id. * * @param int $blog_id * * @return string */ public function get_mapped_domain($blog_id) { global $wpdb; $domain = ''; $multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping'; // Check if table exists if ($wpdb->get_var("SHOW TABLES LIKE '" . esc_sql($multisite_plugin_table_name) . "'") != $multisite_plugin_table_name) { // This table created in WordPress MU Domain Mapping plugin. $row = $wpdb->get_row($wpdb->prepare("SELECT `domain` FROM " .esc_sql($multisite_plugin_table_name) . " WHERE `blog_id` = %d AND `active` = %d", $blog_id, 1), ARRAY_A); if (!empty($row)) { $domain = $row['domain']; } } else { // When using the WP Core method, the site url option contains the mapped domain. $domain = get_site_url($blog_id); } /** * Filters the mapped domain name * * @param string $domain The domain name * @param integer $blog_id The blog ID */ return apply_filters('wpo_get_mapped_domain', $domain, $blog_id); } /** * Actually add the URLs to be preloaded into cache during `shutdown` hook * * @return void */ public function create_tasks_for_auto_preload_urls() { foreach ($this->url_preload_list as $url) { if (wpo_url_in_exceptions($url)) continue; $description = 'Preload - '.$url; $options = array('url' => $url, 'preload_type' => 'manual', 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI)); WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task'); } $this->run('manual', null, true); } /** * Prepare the URL list that will need to be tasked to be preloaded * * @param string $url The URL to be preloaded * @return void */ public function add_url_to_preload_list($url) { $this->url_preload_list[] = $url; } /** * Captures and logs any interesting messages * * @param String $message - the error message * @param String $error_type - the error type */ public function log($message, $error_type = 'info') { if (isset($this->loggers)) { foreach ($this->loggers as $logger) { $logger->log($message, $error_type); } } } /** * Instance of WP_Optimize_Page_Cache_Preloader. * * @return WP_Optimize_Page_Cache_Preloader */ public static function instance() { if (empty(self::$_instance)) { self::$_instance = new WP_Optimize_Page_Cache_Preloader(); } return self::$_instance; } /** * Check if the URL is already cached, or needs to be preloaded * * @param string $url The preloaded url * @param string $preload_type The preload type (manual | scheduled) * @return boolean */ private function url_is_already_cached($url, $preload_type) { static $files = array(); $regenerate_count = 0; $folder = trailingslashit(WPO_CACHE_FILES_DIR) . wpo_get_url_path($url); // If the folder does not exist, consider the URL as cleared if (!is_dir($folder)) return false; if (empty($files)) { // Check only the base files $files[] = 'index.html'; if (WPO_Cache_Config::instance()->get_option('enable_mobile_caching')) { $files[] = 'mobile.index.html'; } $files = apply_filters('wpo_maybe_clear_files_list', $files); } foreach ($files as $file) { $file_path = trailingslashit($folder).$file; if (!file_exists($file_path)) { // The file does not exist, count it as "deleted" $regenerate_count++; continue; } if ($this->should_regenerate_file($file_path, $preload_type)) { // delete the expired cache file wp_delete_file($file_path); $regenerate_count++; } } // if 0 == $regenerate_count, nothing all the expected files exist, and none were deleted. return 0 == $regenerate_count; } /** * Determine if a file should be regenerated * * @param string $path The file to check * @param string $preload_type The preload type (manual | scheduled) * * @return boolean */ private function should_regenerate_file($path, $preload_type) { // Store the variables, as they'll be used for each file and each file static $is_preloader_scheduled = null; static $lifespan = null; static $schedule_type = null; static $schedule_interval = null; static $lifespan_expiry_threshold = null; static $always_regenerate_file_if_preload_is_manual = null; static $always_regenerate_file_if_preload_is_scheduled = null; static $regenerate_file_when_no_expiry_date = null; // Sets the variables once per request: if (null === $is_preloader_scheduled) { $is_preloader_scheduled = WPO_Cache_Config::instance()->get_option('enable_schedule_preload'); $schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type'); $lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length'); $schedule_interval = $this->get_schedule_interval($schedule_type); /** * Expiry threshold: the current file will be considered stale if within the threshold. Default: 600s (10min) */ $lifespan_expiry_threshold = apply_filters('wpo_lifespan_expiry_threshold', 600); /** * Filters if a cache should systematically be regenerated when running a manual preload. Default: false */ $always_regenerate_file_if_preload_is_manual = apply_filters('wpo_always_regenerate_file_if_preload_is_manual', false); /** * Filters if a cache should systematically be regenerated when running a scheduled preload. Default: false */ $always_regenerate_file_if_preload_is_scheduled = apply_filters('wpo_always_regenerate_file_if_preload_is_scheduled', false); /** * Filters if a cache should systematically be regenerated when running a preload and no schedule is set, and cache does not expire. Default: true */ $regenerate_file_when_no_expiry_date = apply_filters('wpo_regenerate_file_when_no_expiry_date', true); } if (($always_regenerate_file_if_preload_is_manual && 'manual' == $preload_type) || ($always_regenerate_file_if_preload_is_scheduled && 'scheduled' == $preload_type)) { $result = true; } else { $modified_time = (int) filemtime($path); // cache lifespan is set. if (0 != $lifespan) { $expiry_time = $modified_time + $lifespan - $lifespan_expiry_threshold; $result = time() > $expiry_time; } elseif ($is_preloader_scheduled) { $expiry_time = $modified_time + $schedule_interval - $lifespan_expiry_threshold; $result = time() > $expiry_time; } else { $result = $regenerate_file_when_no_expiry_date; } } return apply_filters('wpo_preloader_should_regenerate_file', $result, $path, $preload_type); } /** * Add preloader headers */ public function preload_headers($headers) { $headers['X-WP-Optimize-Cache-Preload'] = 'Yes'; return $headers; } /** * Option disabled error message * * @return array */ protected function get_option_disabled_error() { return array( 'success' => false, 'error' => __('Page cache is disabled.', 'wp-optimize') ); } /** * Get preload already running error message * * @return array */ protected function get_preload_already_running_error() { return array( 'success' => false, 'error' => __('Probably page cache preload is running already.', 'wp-optimize') ); } protected function get_preload_data() { return WP_Optimize()->get_page_cache()->get_cache_size(); } protected function get_preloading_message($cache_size) { return array( 'done' => false, 'message' => __('Loading URLs...', 'wp-optimize'), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } protected function get_last_preload_message($cache_size, $last_preload_time_str) { return array( 'done' => true, // translators: %s is the last preload time 'message' => sprintf(__('Last preload finished at %s', 'wp-optimize'), $last_preload_time_str), 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } protected function get_preload_success_message($cache_size) { return array( 'done' => true, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'] ); } protected function get_preload_progress_message($cache_size, $preloaded_message, $preload_resuming_in) { return array( 'done' => false, 'message' => $preloaded_message, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], 'resume_in' => $preload_resuming_in ); } /** * Shifts the given timestamp to nighttime. * * @param int $time * * @return int */ private function make_nighttime($time) { $gmt_offset = WP_Optimize_Utils::get_gmt_offset(); // Set time to random time from 1 a.m. to 4:59 a.m. $random_time = sprintf('%02d:%02d', wp_rand(1, 4), wp_rand(0, 59)); $nighttime = strtotime(gmdate("Y-m-d {$random_time}:00", $time)) - $gmt_offset; if ($nighttime < time()) $nighttime += 24 * 3600; return $nighttime; } } PK ��}\��< * class-wp-optimize-detect-cache-plugins.phpnu �[��� <?php if (!defined('ABSPATH')) die('No direct access allowed'); class WP_Optimize_Detect_Cache_Plugins { private static $instance; /** * WP_Optimize_Detect_Cache_Plugins constructor. */ protected function __construct() { } /** * Detect list of active most popular WordPress cache plugins. * * @return array */ public function get_active_cache_plugins() { // The index is the plugin's slug $active_cache_plugins = array(); foreach ($this->get_plugins() as $plugin_slug => $plugin_title) { $function_name = 'is_'.str_replace('-', '_', $plugin_slug).'_plugin_active'; if (is_callable(array($this, $function_name))) { if (call_user_func(array($this, $function_name))) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } else { if ($this->is_plugin_active($plugin_slug)) { $active_cache_plugins[$plugin_slug] = $plugin_title; } } } return $active_cache_plugins; } /** * Get the plugins list * * @return array */ protected function get_plugins() { return array( 'w3-total-cache' => 'W3 Total Cache', 'wp-super-cache' => 'WP Super Cache', 'wp-rocket' => 'WP Rocket', 'wp-fastest-cache' => 'WP Fastest Cache', 'litespeed-cache' => 'LiteSpeed Cache', 'cache-enabler' => 'Cache Enabler', 'comet-cache' => 'Comet Cache', 'hummingbird-performance' => 'Hummingbird', 'hyper-cache' => 'Hyper Cache', ); } /** * Check if W3 Total Cache active. * * @return bool */ public function is_w3_total_cache_plugin_active() { return defined('W3TC_VERSION') || $this->is_plugin_active('w3-total-cache'); } /** * Check if WP Rocket active. * * @return bool */ public function is_wp_rocket_plugin_active() { return defined('WP_ROCKET_VERSION') || $this->is_plugin_active('wp-rocket'); } /** * Check if $plugin is active. * * @param string $plugin - plugin slug * * @return bool */ private function is_plugin_active($plugin) { $status = WP_Optimize()->get_db_info()->get_plugin_status($plugin); return $status['active']; } /** * Instance of WP_Optimize_Detect_Cache_Plugins. * * @return WP_Optimize_Detect_Cache_Plugins */ static public function instance() { static $instance; if (empty($instance)) { $instance = new self(); } return $instance; } } PK ��}\��/B /B class-wpo-cache-rules.phpnu �[��� <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Page caching rules and exceptions */ require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; if (!class_exists('WPO_Cache_Rules')) : class WPO_Cache_Rules { /** * Cache config object * * @var mixed */ public $config; /** * Instance of this class * * @var mixed */ public static $instance; public function __construct() { $this->config = WPO_Cache_Config::instance()->get(); $this->setup_hooks(); } /** * Setup hooks/filters */ public function setup_hooks() { add_action('save_post', array($this, 'purge_post_on_update'), 10, 1); add_action('save_post', array($this, 'purge_archive_pages_on_post_update'), 10, 1); add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1); add_action('comment_post', array($this, 'purge_post_on_comment'), 10, 3); add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 1); add_action('edit_terms', array($this, 'purge_related_elements_on_term_updated'), 10, 2); add_action('set_object_terms', array($this, 'purge_related_elements_on_post_terms_change'), 10, 6); add_action('wpo_cache_config_updated', array($this, 'cache_config_updated'), 10, 1); add_action('wp_insert_comment', array($this, 'comment_inserted'), 10, 2); add_action('import_start', array($this, 'remove_wp_insert_comment')); add_action('update_option_page_on_front', array($this, 'purge_cache_on_homepage_change')); add_action('update_option_page_for_posts', array($this, 'purge_cache_on_blog_page_change'), 10, 2); add_action('update_option_show_avatars', array($this, 'purge_cache_on_avatars_change'), 10, 2); add_action('woocommerce_variation_set_stock', array($this, 'purge_product_page'), 10, 1); add_action('woocommerce_product_set_stock', array($this, 'purge_product_page'), 10, 1); /** * List of hooks for which when executed, the cache will be purged * * @param array $actions The actions */ $actions = array( 'after_switch_theme', 'wp_update_nav_menu', 'customize_save_after', array('wp_ajax_save-widget', 0), array('wp_ajax_update-widget', 0), 'autoptimize_action_cachepurged', 'upgrader_overwrote_package', 'wpo_active_plugin_or_theme_updated', 'fusion_cache_reset_after', 'update_option_permalink_structure', 'update_option_posts_per_page', 'wpml_st_add_string_translation', ); $purge_on_action = apply_filters('wpo_purge_cache_hooks', $actions); foreach ($purge_on_action as $action) { if (is_array($action)) { add_action($action[0], array($this, 'purge_cache'), $action[1]); } else { add_action($action, array($this, 'purge_cache')); } } } /** * Purge post cache when there is a new approved comment * * @param int $comment_id Comment ID. * @param int|string $approved Comment approved status. can be 0, 1 or 'spam'. * @param array $commentdata Comment data array. Always sent be WP core, but a plugin was found that does not send it - https://wordpress.org/support/topic/critical-problems-with-version-3-0-10/ */ public function purge_post_on_comment($comment_id, $approved, $commentdata = array()) { if (1 !== $approved) { return; } if (!empty($this->config['enable_page_caching']) && !empty($commentdata['comment_post_ID'])) { $post_id = $commentdata['comment_post_ID']; WPO_Page_Cache::delete_single_post_cache($post_id); WPO_Page_Cache::delete_comments_feed(); WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $post_id); } } /** * Every time a comment's status changes, purge it's parent posts cache * * @param int $comment_id Comment ID. */ public function purge_post_on_comment_status_change($comment_id) { if (!empty($this->config['enable_page_caching'])) { $comment = get_comment($comment_id); if (is_object($comment) && !empty($comment->comment_post_ID)) { WPO_Page_Cache::delete_single_post_cache($comment->comment_post_ID); WPO_Page_Cache::delete_comments_feed(); WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $comment->comment_post_ID); } } } /** * Action when a comment is inserted * * @param integer $comment_id - The comment ID * @param boolean|WP_Comment $comment - The comment object (from WP 4.4) * @return void */ public function comment_inserted($comment_id, $comment = false) { if ($comment && is_a($comment, 'WP_Comment')) { /** * Filters whether to add a cookie when a comment is posted, in order to exclude the page from caching. * Regular comments have the property comment_type set to '' or 'comment'. So by default, only add the cookie in those cases. * * @param boolean $add_cookie * @param WP_Comment $comment * @return boolean */ $add_cookie = apply_filters('wpo_add_commented_post_cookie', '' == $comment->comment_type || 'comment' == $comment->comment_type, $comment); if (!$add_cookie) return; $url = get_permalink($comment->comment_post_ID); $url_info = wp_parse_url($url); setcookie('wpo_commented_post', 1, time() + WEEK_IN_SECONDS, isset($url_info['path']) ? $url_info['path'] : '/'); } } /** * Comment posted cookie is not needed for imports. So remove the action */ public function remove_wp_insert_comment() { remove_action('wp_insert_comment', array($this, 'comment_inserted'), 10); } /** * Automatically purge all file based page cache on post changes * We want the whole cache purged here as different parts * of the site could potentially change on post updates * * @param Integer $post_id - WP post id */ public function purge_post_on_update($post_id) { $post_type = get_post_type($post_id); $post_type_object = get_post_type_object($post_type); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || null === $post_type_object || !$post_type_object->public) { return; } /** * Purge the whole cache if set to true, only the edited post otherwise. Default is false. * * @param boolean $purge_all_cache The default filter value * @param integer $post_id The saved post ID */ if (apply_filters('wpo_purge_all_cache_on_update', false, $post_id)) { $this->purge_cache(); } else { if (apply_filters('wpo_delete_cached_homepage_on_post_update', true, $post_id)) WPO_Page_Cache::delete_homepage_cache(); WPO_Page_Cache::delete_feed_cache(); WPO_Page_Cache::delete_single_post_cache($post_id); WPO_Page_Cache::delete_post_feed_cache($post_id); WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $post_id); } } /** * Purge archive pages on post update. * * @param integer $post_id */ public function purge_archive_pages_on_post_update($post_id) { $post_type = get_post_type($post_id); if (false === $post_type) return; if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) { return; } $post_obj = get_post_type_object($post_type); if (null === $post_obj) return; if ('post' == $post_type) { // delete blog page cache $blog_post_id = get_option('page_for_posts'); if ($blog_post_id) { WPO_Page_Cache::delete_cache_by_url(get_permalink($blog_post_id), true); WPO_Page_Cache::instance()->file_log("Cache for blog post has been purged due to updates to post with Title: {{title}} and URL: {{URL}}, triggered by action: " . current_filter(), $post_id); } // delete next and previous posts cache. $globals_post = isset($GLOBALS['post']) ? $GLOBALS['post'] : false; $GLOBALS['post'] = get_post($post_id); $previous_post = function_exists('get_previous_post') ? get_previous_post() : false; $next_post = function_exists('get_next_post') ? get_next_post() : false; if ($globals_post) $GLOBALS['post'] = $globals_post; if ($previous_post) { WPO_Page_Cache::delete_cache_by_url(get_permalink($previous_post), true); WPO_Page_Cache::instance()->file_log("Cache for previous post (with URL: {{URL}}) adjacent to post with id: " . $post_id . " has been purged, triggered by action: " . current_filter(), $previous_post->ID); } if ($next_post) { WPO_Page_Cache::delete_cache_by_url(get_permalink($next_post), true); WPO_Page_Cache::instance()->file_log("Cache for next post (with URL: {{URL}}) adjacent to post with id: " . $post_id . " has been purged, triggered by action: " . current_filter(), $next_post->ID); } // delete all archive pages for post. $post_date = get_post_time('Y-m-j', false, $post_id); list($year, $month, $day) = $post_date; $archive_links = array( get_year_link($year), get_month_link($year, $month), get_day_link($year, $month, $day), ); foreach ($archive_links as $link) { WPO_Page_Cache::delete_cache_by_url($link, true); } WPO_Page_Cache::instance()->file_log("Cache for all archives page associated with post_type: " . $post_type . " and Title: {{title}} have been purged, triggered by action: " . current_filter(), $post_id); } elseif ($post_obj->has_archive) { // delete archive page for custom post type. WPO_Page_Cache::delete_cache_by_url(get_post_type_archive_link($post_type), true); WPO_Page_Cache::instance()->file_log("Cache for archive page associated with post_type: " . $post_type . " and Title: {{title}} has been purged, triggered by action: " . current_filter(), $post_id); } } /** * We use it with edit_terms action filter to purge cached elements related * to updated term when term updated. * * @param int $term_id Term taxonomy ID. * @param string $taxonomy Taxonomy slug. */ public function purge_related_elements_on_term_updated($term_id, $taxonomy) { if ('nav_menu' === $taxonomy) return; // purge cached page for term. $term = get_term($term_id, $taxonomy, ARRAY_A); if (is_array($term)) { $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { WPO_Page_Cache::delete_cache_by_url($term_permalink, true); WPO_Page_Cache::instance()->file_log("Cache for term page with URL: " . $term_permalink . " have been purged, triggered by action: " . current_filter()); } } // get posts which belongs to updated term. $posts = get_posts(array( 'numberposts' => -1, 'post_type' => 'any', 'fields' => 'ids', 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- because we can't use `get_objects_in_term` for `OR` relationships 'relation' => 'OR', array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $term_id, ) ), )); if (!empty($posts)) { foreach ($posts as $post_id) { WPO_Page_Cache::delete_single_post_cache($post_id); } $term_permalink = get_term_link($term_id); WPO_Page_Cache::instance()->file_log("Cache for associated posts for term with URL: " . $term_permalink. " have been purged, triggered by action: " . current_filter()); } } /** * Triggered by set_object_terms action. Used to clear all the terms archives a post belongs to or belonged to before being saved. * * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. */ public function purge_related_elements_on_post_terms_change($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) { $post_type = get_post_type($object_id); if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || 'product_type' === $taxonomy || 'action-group' === $taxonomy) { return; } /** * Adds a way to exit the purge of terms permalink using the provided parameters. * * @param bool $purge The value filtered, whether or not to purge the related elements * @param int $object_id Object ID. * @param array $terms An array of object terms. * @param array $tt_ids An array of term taxonomy IDs. * @param string $taxonomy Taxonomy slug. * @param bool $append Whether to append new terms to the old terms. * @param array $old_tt_ids Old array of term taxonomy IDs. * @default true * @return boolean */ if (!apply_filters('wpo_cache_purge_related_elements_on_post_terms_change', true, $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids)) return; // get all affected terms. $affected_terms_ids = array_unique(array_merge($tt_ids, $old_tt_ids)); if (!empty($affected_terms_ids)) { // walk through all changed terms and purge cached pages for them. $is_cache_purged = false; foreach ($affected_terms_ids as $tt_id) { $term = get_term($tt_id, $taxonomy, ARRAY_A); if (!is_array($term)) continue; $term_permalink = get_term_link($term['term_id']); if (!is_wp_error($term_permalink)) { $url = wp_parse_url($term_permalink); // Check if the permalink contains a valid path, to avoid deleting the whole cache. if (!isset($url['path']) || '/' === $url['path']) return; WPO_Page_Cache::delete_cache_by_url($term_permalink, true); $is_cache_purged = true; } } if ($is_cache_purged) WPO_Page_Cache::instance()->file_log("Cache for multiple term taxonomy have been purged due to post terms update, triggered by action: " . current_filter()); } } /** * Purge product page upon stock update */ public function purge_product_page($product_with_stock) { if (!empty($product_with_stock->get_id())) { WPO_Page_Cache::delete_single_post_cache($product_with_stock->get_id()); WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $product_with_stock->get_id()); } } /** * Purges relevant caches when the "Homepage" option is changed. * * This method is also triggered when the "Homepage displays" option is changed * from a static page to latest posts. In this scenario, the "Homepage" option value * becomes zero. Since the cache for the front-page is already purged here, there's no need * to purge the cache using the`update_option_show_on_front` hook. * * @param string $old_value The old value of the "Homepage" option. */ public function purge_cache_on_homepage_change($old_value) { if ($old_value) { WPO_Page_Cache::delete_cache_by_url(get_permalink($old_value)); } WPO_Page_Cache::delete_homepage_cache(); WPO_Page_Cache::instance()->file_log("Cache for homepage has been purged due to change in the Homepage displays options, triggered by action: " . current_filter()); } /** * Purges relevant caches when the "Posts page" option is changed. * * @param string $old_value The old value of the "Posts page" option. * @param string $value The new value of the "Posts page" option. */ public function purge_cache_on_blog_page_change($old_value, $value) { if ($old_value) { WPO_Page_Cache::delete_cache_by_url(get_permalink($old_value)); } if ($value) { WPO_Page_Cache::delete_cache_by_url(get_permalink($value)); } WPO_Page_Cache::instance()->file_log("Cache for homepage has been purged due to changes in the Posts page options, triggered by action: " . current_filter()); } /** * Purges cache if the avatars option is changed * * @param boolean $old_value * @param boolean $value */ public function purge_cache_on_avatars_change(bool $old_value, ?bool $value): void { if ($old_value !== $value) { $this->purge_cache(); } } /** * Clears the cache. */ public function purge_cache() { if (!empty($this->config['enable_page_caching'])) { wpo_cache_flush(); WPO_Page_Cache::instance()->file_log("Full Cache Purge triggered by action: " . current_filter()); } } /** * Triggered by wpo_cache_config_updated. * * @param array $config */ public function cache_config_updated($config) { // delete front page form cache if defined in the settings if (is_array($config['cache_exception_urls']) && in_array('/', $config['cache_exception_urls'])) { WPO_Page_Cache::delete_cache_by_url(home_url()); WPO_Page_Cache::instance()->file_log("Cache for homepage has been purged due to changes in the cache configurations, triggered by action: " . current_filter()); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } } endif; PK ��}\��!��� �� class-wpo-page-cache.phpnu �[��� <?php /** * Page caching functionality * * Acknowledgement: The page cache functionality was loosely based on the simple cache plugin - https://github.com/tlovett1/simple-cache */ if (!defined('ABSPATH')) die('No direct access allowed'); /** * Base cache directory, everything else goes under here */ if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR).'/wpo-cache'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Directory that stores config and related files */ if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); /** * Directory that stores the cache, including gzipped files and mobile specific cache */ if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', untrailingslashit(WP_CONTENT_DIR).'/cache/wpo-cache'); require_once dirname(__FILE__) . '/file-based-page-cache-functions.php'; wpo_cache_load_extensions(); if (!class_exists('WPO_Page_Cache')) : class WPO_Page_Cache { /** * Cache config object * * @var mixed */ public $config; /** * Logger for this class * * @var mixed */ public $logger; /** * File Logger for this class * * @var mixed */ private $file_logger; /** * Instance of this class * * @var mixed */ public static $instance; /** * Store last advanced cache file writing status * If true then last writing finished with error * * @var bool */ public $advanced_cache_file_writing_error; /** * Store errors * * @var array */ private $_errors = array(); /** * Last advanced cache file content * * @var string */ public $advanced_cache_file_content; /** * Store the latest advanced-cache.php version required * * @var string */ private $_minimum_advanced_cache_file_version = '3.0.17'; public $should_purge; /** * Set everything up here */ public function __construct() { $this->config = WPO_Cache_Config::instance(); if (empty($GLOBALS['wpo_cache_config'])) { $config_file_path = $this->config->get_config_file_path(); if (file_exists($config_file_path)) { include_once($config_file_path); } } WPO_Cache_Rules::instance(); WP_Optimize_Page_Cache_Preloader::instance(); $this->logger = new Updraft_PHP_Logger(); $this->file_logger = new Updraft_File_Logger(WP_Optimize_Utils::get_log_file_path('cache')); add_action('activated_plugin', array($this, 'activate_deactivate_plugin')); add_action('deactivate_plugin', array($this, 'activate_deactivate_plugin')); add_action('wpo_purge_old_cache', array($this, 'purge_old')); add_action('wpo_prune_cache_logs', array($this, 'prune_cache_logs')); /** * Regenerate config file on cache flush. */ add_action('wpo_cache_flush', array($this, 'update_cache_config')); add_action('wpo_cache_flush', array($this, 'delete_cache_size_information')); add_action('update_option_permalink_structure', array($this, 'update_option_permalink_structure'), 10, 3); // Add purge cache link to admin bar. add_filter('wpo_cache_admin_bar_menu_items', array($this, 'admin_bar_purge_cache'), 20, 1); // Handle single page purge. add_action('wp_loaded', array($this, 'handle_purge_single_page_cache')); add_action('admin_init', array($this, 'admin_init')); add_action('update_option_gmt_offset', array($this, 'update_gmt_offset_timezone_string_config'), 10, 3); add_action('update_option_timezone_string', array($this, 'update_gmt_offset_timezone_string_config'), 10, 3); add_action('update_option_date_format', array($this, 'update_option_date_format'), 10, 2); add_action('update_option_time_format', array($this, 'update_option_time_format'), 10, 2); $this->check_compatibility_issues(); add_filter('cron_schedules', array($this, 'cron_schedules')); add_action('wpo_save_images_settings', array($this, 'update_webp_images_option')); add_action('wpo_preload_url', array($this, 'maybe_preload_url')); // Setup filters for exceptions. add_filter('wpo_restricted_cache_page_type', 'wpo_restricted_cache_page_type'); add_filter('wpo_url_in_conditional_tags_exceptions', 'wpo_url_in_conditional_tags_exceptions'); } /** * Determines whether the current page should be cached. * * This method checks cache rules to identify if caching is possible. * If caching is not allowed, it adds appropriate HTTP headers and debug messages. * * @return bool True if the page should be cached, false otherwise. */ public function should_cache_page(): bool { if (!$this->is_enabled()) return false; $no_cache_because = array(); // Check serve cache rules, to identify if we need to cache the page. $can_serve_from_cache = wpo_can_serve_from_cache(); if (false === $can_serve_from_cache) return false; if (is_array($can_serve_from_cache)) $no_cache_because = $can_serve_from_cache; if (!empty($no_cache_because)) { // Add http header if (!wp_doing_cron()) { $no_cache_because_message = join(", ", $no_cache_because); wpo_cache_add_nocache_http_header_with_send_headers_action($no_cache_because_message); $not_cached_details = ""; // Output the reason only when the user has turned on debugging if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug']))) { $not_cached_details = "because: ".$no_cache_because_message; } wpo_cache_add_footer_output(sprintf("Page not served from cache %s", $not_cached_details)); } return false; } return true; } /** * Activate cron job when the cache is enabled for deleting expired cache files */ public function cron_activate() { $page_cache_length = $this->config->get_option('page_cache_length'); if ($this->is_enabled()) { if (!wp_next_scheduled('wpo_purge_old_cache')) { wp_schedule_event(time() + (false === $page_cache_length ? '86400' : $page_cache_length), 'wpo_purge_old_cache', 'wpo_purge_old_cache'); } if (!wp_next_scheduled('wpo_prune_cache_logs')) { wp_schedule_event(time(), 'weekly', 'wpo_prune_cache_logs'); } } else { wp_clear_scheduled_hook('wpo_purge_old_cache'); wp_clear_scheduled_hook('wpo_prune_cache_logs'); } } /** * Do required actions on activate/deactivate any plugin. */ public function activate_deactivate_plugin() { wp_clear_scheduled_hook('wpo_purge_old_cache'); $this->update_cache_config(); $is_cache_purged = $this->purge(); if ($is_cache_purged) $this->file_log("Full Cache Purge triggered by: plugin activation/deactivation"); } /** * Check if current user can purge cache. * * @return bool */ public function can_purge_cache() { if (!$this->is_enabled()) return false; $required_capability = is_multisite() ? 'manage_network_options' : 'manage_options'; if (WP_Optimize::is_premium()) { return current_user_can($required_capability) || WP_Optimize_Premium()->can_purge_the_cache(); } else { return current_user_can($required_capability); } } /** * Add Purge from cache in admin bar. * * @param array $menu_items * @return array */ public function admin_bar_purge_cache($menu_items) { global $pagenow; if (!$this->can_purge_cache()) return $menu_items; $act_url = remove_query_arg(array('wpo_single_page_cache_purged', 'wpo_all_pages_cache_purged')); $cache_size = $this->get_cache_size(); $cache_size_info = '<h4>'.__('Page cache', 'wp-optimize').'</h4>'; // translators: %d is the number of files in the cache $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>'; $menu_items[] = array( 'id' => 'wpo_cache_stats', 'title' => $cache_size_info, 'meta' => array( 'class' => 'wpo-cache-stats', ), 'parent' => 'wpo_purge_cache', ); $menu_items[] = array( 'id' => 'wpo_purge_all_pages_cache', 'title' => __('Purge cache for all pages', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_all_pages_cache'), $act_url), 'meta' => array( 'title' => __('Purge cache for all pages', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', ); if (!is_admin() || 'post.php' == $pagenow) { $menu_items[] = array( 'id' => 'wpo_purge_this_page_cache', 'title' => __('Purge cache for this page', 'wp-optimize'), 'href' => add_query_arg('_wpo_purge', wp_create_nonce('wpo_purge_single_page_cache'), $act_url), 'meta' => array( 'title' => __('Purge cache for this page', 'wp-optimize'), ), 'parent' => 'wpo_purge_cache', ); } return $menu_items; } /** * Check if purge single page action sent and purge cache. */ public function handle_purge_single_page_cache() { if (!$this->can_purge_cache()) return; if (isset($_GET['wpo_single_page_cache_purged']) || isset($_GET['wpo_all_pages_cache_purged'])) { // phpcs:disable // We are not using $_GET values, just checks if the variable is set and then use hard coded string if (isset($_GET['wpo_single_page_cache_purged'])) { $notice_function = $_GET['wpo_single_page_cache_purged'] ? 'notice_purge_single_page_cache_success' : 'notice_purge_single_page_cache_error'; } else { $notice_function = $_GET['wpo_all_pages_cache_purged'] ? 'notice_purge_all_pages_cache_success' : 'notice_purge_all_pages_cache_error'; } // phpcs:enable add_action('admin_notices', array($this, $notice_function)); return; } if (!isset($_GET['_wpo_purge'])) return; if (wp_verify_nonce(sanitize_key($_GET['_wpo_purge']), 'wpo_purge_single_page_cache')) { $success = false; if (is_admin()) { $post = isset($_GET['post']) ? (int) $_GET['post'] : 0; if ($post > 0) { $success = self::delete_single_post_cache($post); if ($success) $this->file_log("Cache for URL: {{URL}} has been purged, triggered by: " . __METHOD__, $post); } } else { $url = wpo_current_url(); $success = self::delete_cache_by_url($url); if ($success) $this->file_log("Cache for URL: " . self::remove_query_params($url) . " has been purged, triggered by: " . __METHOD__); } // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_single_page_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } elseif (wp_verify_nonce(sanitize_key($_GET['_wpo_purge']), 'wpo_purge_all_pages_cache')) { $success = self::purge(); $this->maybe_set_preload_cron_job(); if ($success) $this->file_log("Full Cache Purge triggered by: ". __METHOD__); // remove nonce from url and reload page. wp_redirect(add_query_arg('wpo_all_pages_cache_purged', $success, remove_query_arg('_wpo_purge'))); exit; } } /** * Sets a preload cron job to run after 30 seconds * * As preloading may take time for larger sites, we are opting for an immediate cron job instead * of instant preloading to prevent the current request from slowing down the page load * * @return void */ private function maybe_set_preload_cron_job() { $wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); if ($wpo_page_cache_preloader->is_scheduled_preload_enabled() || $this->should_auto_preload_purged_contents()) { if (!wp_next_scheduled('wpo_page_cache_run_preload')) { wp_schedule_single_event(time() + 30, 'wpo_page_cache_run_preload'); } } } /** * Show notification when page cache purged successfully. */ public function notice_purge_single_page_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when page cache wasn't purged. */ public function notice_purge_single_page_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification when all pages cache purged successfully. */ public function notice_purge_all_pages_cache_success() { $this->show_notice(__('The page cache was successfully purged.', 'wp-optimize'), 'success'); } /** * Show notification when all pages cache wasn't purged. */ public function notice_purge_all_pages_cache_error() { $this->show_notice(__('The page cache was not purged.', 'wp-optimize'), 'error'); } /** * Show notification in WordPress admin. * * @param string $message HTML (no further escaping is performed) * @param string $type error, warning, success, or info */ public function show_notice($message, $type) { global $current_screen; if ($current_screen && is_callable(array($current_screen, 'is_block_editor')) && $current_screen->is_block_editor()) : ?> <script> window.addEventListener('load', function() { (function(wp) { if (window.wp && wp.hasOwnProperty('data') && 'function' == typeof wp.data.dispatch) { wp.data.dispatch('core/notices').createNotice( '<?php echo esc_html($type); ?>', '<?php echo wp_kses_post($message); ?>', { isDismissible: true, } ); } })(window.wp); }); </script> <?php else : ?> <div class="notice wpo-notice notice-<?php echo esc_attr($type); ?> is-dismissible"> <p><?php echo wp_kses_post($message); ?></p> </div> <?php endif; } /** * Enables page cache * * @param bool $force_enable - Force regenerating everything. E.g. we want to do that when saving the settings * * @return WP_Error|bool - true on success, error otherwise */ public function enable($force_enable = false) { global $is_apache; static $already_ran_enable = false; if ($already_ran_enable) return $already_ran_enable; $folders_created = $this->create_folders(); if (is_wp_error($folders_created)) { $already_ran_enable = $folders_created; return $already_ran_enable; } if (!file_exists($this->config->get_config_file_path())) { $result = $this->update_cache_config(); if (is_wp_error($result)) return $result; } // if WPO_ADVANCED_CACHE isn't set, or environment doesn't contain the right constant, force regeneration if (!defined('WPO_ADVANCED_CACHE') || !defined('WP_CACHE')) { $force_enable = true; } $this->maybe_regenerate_cache_config_file(); // Enable `.htaccess` rules to serve cached files if ($is_apache && apply_filters('wpo_serve_cache_via_htaccess', false)) { wpo_disable_cache_directories_viewing(); wpo_allow_access_to_index_cache_files(); $this->update_serve_cache_rules_htaccess_section(true); } if (!$force_enable) { $already_ran_enable = true; return true; } if (!$this->write_advanced_cache() && version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<')) { $message = sprintf("The request to write the file %s failed. ", htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); if (!defined('WP_CLI') || !WP_CLI) { // translators: %s is the path to advanced-cache.php folder $message .= "\n\n1. ".sprintf(__('Please navigate, via FTP, to the folder - %s', 'wp-optimize'), htmlspecialchars(dirname($this->get_advanced_cache_filename()))); $message .= "\n2. ".__('Edit or create a file with the name advanced-cache.php', 'wp-optimize'); $message .= "\n3. ".__('Copy and paste the following lines into the file:', 'wp-optimize'); } $already_ran_enable = new WP_Error("write_advanced_cache", $message); return $already_ran_enable; } if (!$this->write_wp_config(true)) { $already_ran_enable = new WP_Error("write_wp_config", "Could not turn on the WP_CACHE constant in wp-config.php. Check your permissions."); return $already_ran_enable; } if (!$this->verify_cache()) { $errors = $this->get_errors(); $already_ran_enable = new WP_Error("verify_cache", "Could not verify if the cache was enabled: \n".implode("\n- ", $errors)); return $already_ran_enable; } $already_ran_enable = true; return true; } /** * Disables page cache * * @return bool - true on success, false otherwise */ public function disable() { global $is_apache; $ret = true; $advanced_cache_file = $this->get_advanced_cache_filename(); // 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. $disabled_wp_config = $this->write_wp_config(false); if (!$disabled_wp_config) { $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH); $action = "deactivate_".$plugin_basename."/wp-optimize.php"; if (current_action() === $action) { $cache_config = WPO_Cache_Config::instance()->config; $cache_config['enable_page_caching'] = false; WPO_Cache_Config::instance()->update($cache_config, true); } $this->log("Could not turn off the WP_CACHE constant in wp-config.php"); $this->add_warning('error_disabling', __('Could not turn off the WP_CACHE constant in wp-config.php', 'wp-optimize')); } $disabled_advanced_cache = true; // First try to remove (so that it doesn't look to any other plugin like the file is already 'claimed') // We only touch advanched-cache.php and wp-config.php if it appears that we were in control of advanced-cache.php if (!file_exists($advanced_cache_file) || false !== strpos(file_get_contents($advanced_cache_file), 'WP-Optimize advanced-cache.php')) { if (file_exists($advanced_cache_file) && (!wp_delete_file($advanced_cache_file) && false === file_put_contents($advanced_cache_file, "<?php\n// WP-Optimize: page cache disabled"))) { $disabled_advanced_cache = false; $this->log("The request to the filesystem to remove or empty advanced-cache.php failed"); $this->add_warning('error_disabling', __('The request to the filesystem to remove or empty advanced-cache.php failed', 'wp-optimize')); } } // If both actions failed, the cache wasn't disabled. So we send an error. If only one succeeds, it will still be disabled. if (!$disabled_wp_config && !$disabled_advanced_cache) { $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')); } // Delete cache to avoid stale cache on next activation $is_cache_purged = $this->purge(); if ($is_cache_purged) $this->file_log("Full Cache Purge triggered by: ". __METHOD__); // Delete `.htaccess` rules to serve cached files if ($is_apache && apply_filters('wpo_serve_cache_via_htaccess', false)) { $this->update_serve_cache_rules_htaccess_section(false); } // Unschedule cron job to purge old cache wp_clear_scheduled_hook('wpo_purge_old_cache'); if (!is_wp_error($ret)) wp_clear_scheduled_hook('wpo_prune_cache_logs'); return $ret; } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function purge() { /** * Filters whether activating / deactivating a plugin will purge the cache. */ $this->should_purge = apply_filters('wpo_purge_page_cache_on_activate_deactivate_plugin', true); $purge_actions = array( 'deactivate_' . plugin_basename(WPO_PLUGIN_MAIN_PATH . 'wp-optimize.php'), 'deactivate_plugin', 'activated_plugin', ); $is_deactivation_action = in_array(current_action(), $purge_actions, true); if ($is_deactivation_action && !$this->should_purge) return false; if (!self::delete(WPO_CACHE_FILES_DIR)) { $this->log("The request to the filesystem to delete the cache failed"); return false; } /** * Fires after purging the cache */ do_action('wpo_cache_flush'); return true; } /** * Purge cache files older than cache life span * * @return array Log messages. */ public function purge_old() { $log = array(); $page_cache_length = $this->config->get_option('page_cache_length'); if (0 === $page_cache_length) return $log; $expires = time() - $page_cache_length; $cache_folder = WPO_CACHE_FILES_DIR . '/' . str_ireplace(array('http://', 'https://'), '', get_site_url()); // get all directories that are a direct child of current directory if (is_dir($cache_folder) && wp_is_writable($cache_folder)) { if ($handle = opendir($cache_folder)) { while (false !== ($d = readdir($handle))) { if (0 == strcmp($d, '.') || 0 == strcmp($d, '..')) { continue; } if ($this->is_front_page_cache($d)) { $modified_time = (int) filemtime("$cache_folder/$d"); if ($modified_time <= $expires) { wp_delete_file("$cache_folder/$d"); } continue; } $dir = $cache_folder.'/'.$d; if (!is_dir($dir)) continue; $stat = stat($dir); $modified_time = $stat['mtime']; $log[] = "checking if cache has expired - $d"; if ($modified_time <= $expires) { $log[] = "deleting cache in $dir"; wpo_delete_files($dir, true); if (file_exists($dir)) rmdir($dir); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- N/A } } closedir($handle); } } return $log; } /** * Finds out given cache file is of front page or not * * @return bool */ private function is_front_page_cache($d) { return in_array($d, array('index.html', 'index.html.gz')); } /** * Purges the cache * * @return bool - true on success, false otherwise */ public function clean_up() { $this->disable(); if (!self::delete(WPO_CACHE_DIR, true)) { $this->log("The request to the filesystem to clean up the cache failed"); return false; } return true; } /** * Check if cache is enabled and working * * @return bool - true on success, false otherwise */ public function is_enabled() { if (!$this->config->get_option('enable_page_caching')) return false; if (!defined('WP_CACHE') || !WP_CACHE) { if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) { $this->log("WP_CACHE constant is not present in wp-config.php"); return false; } } if (!defined('WPO_ADVANCED_CACHE') || !WPO_ADVANCED_CACHE) { if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) { $this->log("WPO_ADVANCED_CACHE constant is not present in advanced-cache.php"); return false; } } $config_file = WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename(); if (!file_exists($config_file)) { if ((!(defined('WP_CLI') && WP_CLI)) && (!defined('DOING_AJAX') || !DOING_AJAX)) { $this->log("Cache config file $config_file is not present"); return false; } } return true; } /** * Create the folder structure needed for cache to work * * @return bool - true on success, false otherwise */ public function create_folders() { $permissions_str = __('Please check your file permissions.', 'wp-optimize'); if (!is_dir(WPO_CACHE_DIR) && !wp_mkdir_p(WPO_CACHE_DIR)) { // translators: %s is a directory name 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); } if (!is_dir(WPO_CACHE_CONFIG_DIR) && !wp_mkdir_p(WPO_CACHE_CONFIG_DIR)) { // translators: %s is a directory name 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); } if (!is_dir(WPO_CACHE_FILES_DIR)) { if (!wp_mkdir_p(WPO_CACHE_FILES_DIR)) { // translators: %s is a directory name 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); } else { wpo_disable_cache_directories_viewing(); } } return true; } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_advanced_cache_filename() { return untrailingslashit(WP_CONTENT_DIR) . '/advanced-cache.php'; } /** * Writes advanced-cache.php * * @param boolean $update_required - Whether the update is required or not. * @return bool */ private function write_advanced_cache($update_required = false) { $config_file_basename = $this->config->get_cache_config_filename(); $cache_file_basename = untrailingslashit(plugin_dir_path(__FILE__)); $plugin_basename = basename(WPO_PLUGIN_MAIN_PATH); $cache_path = '/wpo-cache'; $cache_files_path = '/cache/wpo-cache'; $cache_extensions_path = WPO_CACHE_EXT_DIR; $wpo_version = WPO_VERSION; $wpo_home_url = trailingslashit(home_url()); $abspath = ABSPATH; // CS does not like heredoc // phpcs:disable $this->advanced_cache_file_content = <<<EOF <?php if (!defined('ABSPATH')) die('No direct access allowed'); // WP-Optimize advanced-cache.php (written by version: $wpo_version) (homeurl: $wpo_home_url) (abspath: $abspath) (do not change this line, it is used for correctness checks) if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); \$possible_plugin_locations = array( defined('WP_PLUGIN_DIR') ? WP_PLUGIN_DIR.'/$plugin_basename/cache' : false, defined('WP_CONTENT_DIR') ? WP_CONTENT_DIR.'/plugins/$plugin_basename/cache' : false, dirname(__FILE__).'/plugins/$plugin_basename/cache', '$cache_file_basename', ); \$plugin_location = false; foreach (\$possible_plugin_locations as \$possible_location) { if (false !== \$possible_location && @file_exists(\$possible_location.'/file-based-page-cache.php')) { \$plugin_location = \$possible_location; break; } } if (false === \$plugin_location) { if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', true); \$protocol = \$_SERVER['REQUEST_SCHEME']; \$host = \$_SERVER['HTTP_HOST']; \$request_uri = \$_SERVER['REQUEST_URI']; if (strcasecmp('$wpo_home_url', \$protocol . '://' . \$host . \$request_uri) === 0) { error_log('WP-Optimize: No caching took place, because the plugin location could not be found'); } } else { if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND')) define('WPO_PLUGIN_LOCATION_NOT_FOUND', false); } if (is_admin()) { return; } if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', WP_CONTENT_DIR.'$cache_path'); if (!defined('WPO_CACHE_CONFIG_DIR')) define('WPO_CACHE_CONFIG_DIR', WPO_CACHE_DIR.'/config'); if (!defined('WPO_CACHE_FILES_DIR')) define('WPO_CACHE_FILES_DIR', WP_CONTENT_DIR.'$cache_files_path'); if (false !== \$plugin_location) { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', \$plugin_location.'/extensions'); } else { if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', '$cache_extensions_path'); } if (!@file_exists(WPO_CACHE_CONFIG_DIR . '/$config_file_basename')) { return; } \$GLOBALS['wpo_cache_config'] = @json_decode(file_get_contents(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'), true); if (empty(\$GLOBALS['wpo_cache_config'])) { include_once(WPO_CACHE_CONFIG_DIR . '/$config_file_basename'); } if (empty(\$GLOBALS['wpo_cache_config'])) { error_log('WP-Optimize: Caching failed because the configuration data could not be loaded from the config file.'); return; } if (empty(\$GLOBALS['wpo_cache_config']['enable_page_caching'])) { return; } if (false !== \$plugin_location) { include_once(\$plugin_location.'/file-based-page-cache.php'); } EOF; // phpcs:enable $advanced_cache_filename = $this->get_advanced_cache_filename(); // If the file content is already up to date, success if (is_file($advanced_cache_filename) && file_get_contents($advanced_cache_filename) === $this->advanced_cache_file_content) { $this->advanced_cache_file_writing_error = false; return true; } // check if we can't write the advanced cache file // case 1: the directory is read-only and the file doesn't exist if (!is_file($advanced_cache_filename) && !wp_is_writable(dirname($advanced_cache_filename))) { $this->advanced_cache_file_writing_error = true; return false; } // case 2: the file already exists but it's read-only if (is_file($advanced_cache_filename) && !wp_is_writable($advanced_cache_filename)) { if (version_compare($this->get_advanced_cache_version(), $this->_minimum_advanced_cache_file_version, '<') || $update_required) { $this->advanced_cache_file_writing_error = true; return false; } else { $this->advanced_cache_file_writing_error = false; return true; } } if (!file_put_contents($this->get_advanced_cache_filename(), $this->advanced_cache_file_content)) { $this->advanced_cache_file_writing_error = true; return false; } $this->advanced_cache_file_writing_error = false; return true; } /** * Update advanced cache version if needed. */ public function maybe_update_advanced_cache() { if (!$this->is_enabled()) return; if (!defined('WPO_PLUGIN_LOCATION_NOT_FOUND') || (defined('WPO_PLUGIN_LOCATION_NOT_FOUND') && true === WPO_PLUGIN_LOCATION_NOT_FOUND)) { if (!$this->write_advanced_cache(true)) { add_action('admin_notices', array($this, 'show_admin_notice_advanced_cache')); } } // from 3.0.17 we use more secure way to store cache config files and need update advanced-cache.php // if the site url or folder changed we also update advanced-cache.php $advanced_cache_current_version = $this->get_advanced_cache_version(); $is_the_site_url_or_folder_changed = $this->is_the_site_url_or_folder_changed(); 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; // Purge the cache when the site url or folder changed. if ($is_the_site_url_or_folder_changed) { $is_cache_purged = $this->purge(); if ($is_cache_purged) $this->file_log("Full Cache Purge triggered by: ". __METHOD__); } if (!$this->write_advanced_cache()) { add_action('admin_notices', array($this, 'notice_advanced_cache_autoupdate_error')); } else { $this->update_cache_config(); } } /** * Check if the site url or folder doesn't equal to values from advanced-cache.php * * @return bool */ private function is_the_site_url_or_folder_changed() { if (!is_file($this->get_advanced_cache_filename())) return false; $content = file_get_contents($this->get_advanced_cache_filename()); if (false === $content) return false; if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\) (\(homeurl: (.+)\)) (\(abspath: (.+)\)) \(do not change/Ui', $content, $match)) { $wpo_home_url = trailingslashit(home_url()); $abspath = ABSPATH; return ($wpo_home_url != $match[3] || $abspath != $match[5]); } elseif (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) { return true; } return false; } /** * Show notification when advanced-cache.php could not be updated. */ public function notice_advanced_cache_autoupdate_error() { $this->show_notice(__('The file advanced-cache.php needs to be updated, but the automatic process failed.', 'wp-optimize'). ' <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'); } /** * Get WPO version number from advanced-cache.php file. * * @return bool|mixed */ public function get_advanced_cache_version() { if (!is_file($this->get_advanced_cache_filename())) return false; $version = false; $content = file_get_contents($this->get_advanced_cache_filename()); if (preg_match('/WP\-Optimize advanced\-cache\.php \(written by version\: (.+)\)/Ui', $content, $match)) { $version = $match[1]; } return $version; } /** * Set WP_CACHE on or off in wp-config.php * * @param boolean $status value of WP_CACHE. * @return boolean true if the value was set, false otherwise */ private function write_wp_config($status = true) { // If we changed the value in wp-config, save it, in case we need to change it again in the same run. static $changed = false; if (defined('WP_CACHE') && WP_CACHE === $status && !$changed) { return true; } $config_path = $this->_get_wp_config(); // Couldn't find wp-config.php. if (!$config_path) { return false; } $config_file_string = file_get_contents($config_path); // Config file is empty. Maybe couldn't read it? if (empty($config_file_string)) { return false; } $config_file = preg_split("#(\n|\r\n)#", $config_file_string); $line_key = false; foreach ($config_file as $key => $line) { if (!preg_match('/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/i', $line, $match)) { continue; } if ('WP_CACHE' === $match[2]) { $line_key = $key; } } if (false !== $line_key) { unset($config_file[$line_key]); } if ($status) { array_shift($config_file); array_unshift($config_file, '<?php', "define('WP_CACHE', true); // WP-Optimize Cache"); } foreach ($config_file as $key => $line) { if ('' === $line) { unset($config_file[$key]); } } if (!file_put_contents($config_path, implode(PHP_EOL, $config_file))) { return false; } $changed = true; return true; } /** * Verify we can write to the file system * * @return boolean */ private function verify_cache() { if (function_exists('clearstatcache')) { clearstatcache(); } $errors = 0; // First check wp-config.php. if (!$this->_get_wp_config() && !wp_is_writable($this->_get_wp_config())) { $this->log("Unable to write to or find wp-config.php; please check file/folder permissions"); $this->add_warning('verify_cache', __("Unable to write to or find wp-config.php; please check file/folder permissions.", 'wp-optimize')); } $advanced_cache_file = untrailingslashit(WP_CONTENT_DIR).'/advanced-cache.php'; // Now check wp-content. We need to be able to create files of the same user as this file. 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))) { $this->log("Unable to write the file advanced-cache.php inside the wp-content folder; please check file/folder permissions"); $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')); $errors++; } if (file_exists(WPO_CACHE_FILES_DIR)) { if (!wp_is_writable(WPO_CACHE_FILES_DIR)) { $this->log("Unable to write inside the cache files folder; please check file/folder permissions"); // translators: %s is cache folder path $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)); } } if (file_exists(WPO_CACHE_CONFIG_DIR)) { if (!wp_is_writable(WPO_CACHE_CONFIG_DIR)) { $this->log("Unable to write inside the cache configuration folder; please check file/folder permissions"); // If the config exists, only send a warning. Otherwise send an error. $type = 'warning'; if (!file_exists(WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename())) { $type = 'error'; $errors++; } // translators: %s is cache config folder path $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); } } return !$errors; } /** * Update permalink structure in cache config * * @param string $old_value Old value of permalink_structure option * @param string $value New value of permalink_structure option * @param string $option Option name `permalink_structure` */ public function update_option_permalink_structure($old_value, $value, $option) { $current_config = $this->config->get(); if ($old_value != $value) { $current_config[$option] = $value; $this->config->update($current_config, true); } } /** * Update cache config. Used to support 3d party plugins. * * @return {boolean|WP_Error} */ public function update_cache_config() { // get current cache settings. $current_config = $this->config->get(); // and call update to change if need cookies and query variable names. return $this->config->update($current_config); } /** * Delete information about cache size. */ public function delete_cache_size_information() { delete_transient('wpo_get_cache_size'); } /** * Get current cache size. * * @return array */ public function get_cache_size() { $cache_size = get_transient('wpo_get_cache_size'); if (!empty($cache_size)) return $cache_size; $infos = $this->get_dir_infos(WPO_CACHE_FILES_DIR); $cache_size = array( 'size' => $infos['size'], 'file_count' => $infos['file_count'] ); set_transient('wpo_get_cache_size', $cache_size); return $cache_size; } /** * Fetch directory information. * * @param string $dir * @return array */ private function get_dir_infos($dir) { $dir_size = 0; $file_count = 0; $handle = is_dir($dir) ? opendir($dir) : false; if (false === $handle) { return array('size' => 0, 'file_count' => 0); } $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file) { $current_file = $dir.'/'.$file; if (is_dir($current_file)) { $sub_dir_infos = $this->get_dir_infos($current_file); $dir_size += $sub_dir_infos['size']; $file_count += $sub_dir_infos['file_count']; } elseif (is_file($current_file)) { $dir_size += filesize($current_file); $file_count++; } } $file = readdir($handle); } return array('size' => $dir_size, 'file_count' => $file_count); } /** * Returns the path to wp-config * * @return string|boolean wp-config.php path. */ private function _get_wp_config() { $config_path = false; foreach (get_included_files() as $filename) { if (preg_match('/(\\\\|\/)wp-config\.php$/i', $filename)) { $config_path = $filename; break; } } // WP-CLI doesn't include wp-config.php that's why we use function from WP-CLI to locate config file. if (!$config_path && is_callable('wpo_wp_cli_locate_wp_config')) { $config_path = wpo_wp_cli_locate_wp_config(); } return $config_path; } /** * Util to delete folders and/or files * * @param string $src * @return boolean */ public static function delete($src) { return wpo_delete_files($src); } /** * Delete cached files for specific url. * * @param string $url * @param bool $recursive If true child elements will deleted too * * @return bool */ public static function delete_cache_by_url($url, $recursive = false) { if (!defined('WPO_CACHE_FILES_DIR') || '' == $url) return; $path = self::get_full_path_from_url($url); do_action('wpo_delete_cache_by_url', $url, $recursive); do_action('wpo_preload_url', $url); return wpo_delete_files($path, $recursive); } /** * Adds the URL to the preload list and hooks the preload task to shutdown * * @param string $url * @return void */ public function maybe_preload_url($url) { if (!$this->should_auto_preload_purged_contents()) return; static $urls_preloaded = array(); // Remove the query string from the URL $url = preg_replace('/\?.*/', '', $url); if (!in_array($url, $urls_preloaded)) { $urls_preloaded[] = $url; $preloader = WP_Optimize_Page_Cache_Preloader::instance(); $preloader->add_url_to_preload_list($url); $url_task_creator = array($preloader, 'create_tasks_for_auto_preload_urls'); if (!has_action('shutdown', $url_task_creator)) { add_action('shutdown', $url_task_creator); } } } /** * Delete cached files for single post. * * @param integer $post_id The post ID * * @return bool */ public static function delete_single_post_cache($post_id) { $is_cache_deleted = self::really_delete_single_post_cache($post_id); do_action('wpo_single_post_cache_deleted', $post_id); return $is_cache_deleted; } /** * Really delete cached files for single post. * * @param integer $post_id The post ID * * @return bool */ public static function really_delete_single_post_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $post_url = get_permalink($post_id); $path = self::get_full_path_from_url($post_url); // for posts with pagination run purging cache recursively. $post = get_post($post_id); $recursive = preg_match('/\<\!--nextpage--\>/', $post->post_content) ? true : false; do_action('wpo_delete_cache_by_url', $post_url, $recursive); do_action('wpo_preload_url', $post_url); return wpo_delete_files($path, $recursive); } /** * Delete cached home page files. */ public static function delete_homepage_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = self::get_full_path_from_url($homepage_url); $recursive = false; do_action('wpo_delete_cache_by_url', $homepage_url, $recursive); do_action('wpo_preload_url', $homepage_url); wpo_delete_files($path, $recursive); } /** * Delete feed from cache. */ public static function delete_feed_cache() { if (!defined('WPO_CACHE_FILES_DIR')) return; $homepage_url = get_home_url(get_current_blog_id()); $path = self::get_full_path_from_url($homepage_url) . 'feed/'; do_action('wpo_delete_cache_by_url', $path, true); wpo_delete_files($path, true); } /** * Delete post feed from cache. */ public static function delete_post_feed_cache($post_id) { self::really_delete_post_feed_cache($post_id); do_action('wpo_single_post_feed_cache_deleted', $post_id); } /** * Really delete post feed from cache. */ public static function really_delete_post_feed_cache($post_id) { if (!defined('WPO_CACHE_FILES_DIR')) return; $post_url = get_permalink($post_id); $path = self::get_full_path_from_url($post_url) . 'feed/'; do_action('wpo_delete_cache_by_url', $path, true); wpo_delete_files($path, true); } /** * Delete comments feed from cache. */ public static function delete_comments_feed() { if (!defined('WPO_CACHE_FILES_DIR')) return; $comments_feed_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/feed/'; $path = self::get_full_path_from_url($comments_feed_url); do_action('wpo_delete_cache_by_url', $comments_feed_url, true); wpo_delete_files($path, true); // delete empty comments dir from the cache $comments_url = trailingslashit(get_home_url(get_current_blog_id())) . 'comments/'; $path = self::get_full_path_from_url($comments_url); if (wpo_is_empty_dir($path)) { wpo_delete_files($path, true); } } /** * Returns full path to the cache folder by url. * * @param string $url * @return string */ public static function get_full_path_from_url($url) { return trailingslashit(WPO_CACHE_FILES_DIR) . trailingslashit(wpo_get_url_path($url)); } /** * Admin actions * * @return void */ public function admin_init() { // Maybe update the advanced cache. if ((!defined('DOING_AJAX') || !DOING_AJAX) && current_user_can('update_plugins')) { $this->maybe_update_advanced_cache(); $this->cron_activate(); } } /** * Logs error messages * * @param string $message * @return null|void */ public function log($message) { if (isset($this->logger)) { $this->logger->log($message, 'error'); } } /** * Returns an instance of the current class, creates one if it doesn't exist * * @return object */ public static function instance() { if (empty(self::$instance)) { self::$instance = new self(); } return self::$instance; } /** * Update gmt_offset and timezone_string cache config value, used with hook `update_gmt_offset_timezone_string_config`. * * @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) * @param {float|string} $new_value * @param {string} $option gmt_offset|timezone_string * * @return null */ public function update_gmt_offset_timezone_string_config($old_value, $new_value, $option) { if ('' == $new_value) return; $current_config = $this->config->get(); if ('timezone_string' == $option) { $timeZone = new DateTimeZone($new_value); $dateTime = new DateTime("now"); $gmt_offset = $timeZone->getOffset($dateTime); $current_config['gmt_offset'] = round($gmt_offset/3600, 1); $current_config['timezone_string'] = $new_value; } elseif ('' !== $new_value) { $current_config['gmt_offset'] = $new_value; $current_config['timezone_string'] = ''; } $this->config->update($current_config, true); } /** * Update `date_format` cache config value, used with hook `update_option_date_format`. * * @param string $old_value Old date format * @param string $new_value New date format * * @return void */ public function update_option_date_format($old_value, $new_value) { $current_config = $this->config->get(); $current_config['date_format'] = $new_value; $this->config->update($current_config, true); } /** * Update `time_format` cache config value, used with hook `update_option_time_format`. * * @param string $old_value Old time format * @param string $new_value New time format * * @return void */ public function update_option_time_format($old_value, $new_value) { $current_config = $this->config->get(); $current_config['time_format'] = $new_value; $this->config->update($current_config, true); } /** * Adds an error to the error store * * @param string $code - The error code * @param string $message - The error's message * @param string $type - The error's type (error, warning) * @return void */ public function add_error($code, $message, $type = 'error') { if (!isset($this->_errors[$type])) { $this->_errors[$type] = new WP_Error($code, $message); } else { $this->_errors[$type]->add($code, $message); } } /** * Adds a warning to the error store * * @param string $code - The error code * @param string $message - The error's message * @return void */ public function add_warning($code, $message) { $this->add_error($code, $message, 'warning'); } /** * Get all recorded errors * * @param string $type - The error type * @param boolean $get_messages_only - Whether to get only the messages, or the full WP_Error object * @return boolean|array|WP_Error */ public function get_errors($type = 'error', $get_messages_only = true) { if (!$this->has_errors($type)) return false; $errors = $this->_errors[$type]; if ($get_messages_only) { return $errors->get_error_messages(); } return $errors; } /** * Check if any errors were recorded * * @param string $type - The error type * @return boolean */ public function has_errors($type = 'error') { return isset($this->_errors[$type]) && !empty($this->_errors[$type]) && $this->_errors[$type]->has_errors(); } /** * Check if any warnings were recorded * * @return boolean */ public function has_warnings() { return $this->has_errors('warning'); } /** * Check the cache compatibility issues. */ public function check_compatibility_issues() { if (!$this->is_enabled()) return; if ($this->is_pagespeedninja_gzip_active()) add_action('admin_notices', array($this, 'show_pagespeedninja_gzip_notice')); if ($this->is_farfutureexpiration_gzip_active()) add_action('admin_notices', array($this, 'show_farfutureexpiration_gzip_notice')); } /** * Check if PageSpeed Ninja is active and GZIP compression option is enabled. * * @return bool */ public function is_pagespeedninja_gzip_active(): bool { if (!class_exists('PagespeedNinja')) return false; $options = get_option('pagespeedninja_config'); $gzip = isset($options['psi_EnableGzipCompression']) && isset($options['html_gzip']) && (bool) $options['psi_EnableGzipCompression'] && (bool) $options['html_gzip']; return $gzip; } /** * Output PageSpeed Ninja Gzip notice. */ public function show_pagespeedninja_gzip_notice() { 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>'; } /** * Check if Far Future Expiration is active and GZIP compression option is enabled. * * @return bool */ public function is_farfutureexpiration_gzip_active() { if (!class_exists('farFutureExpiration')) return false; $options = get_option('far_future_expiration_settings'); $gzip = !empty($options) ? (bool) $options['enable_gzip'] : false; return $gzip; } /** * Output Far Future Expiration Gzip notice. */ public function show_farfutureexpiration_gzip_notice() { 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>'; } /** * This is a notice to show users that writing `advanced-cache.php` failed */ public function show_admin_notice_advanced_cache() { // translators: %s is advanced-cache.php file path $message = sprintf(__('The request to write the file %s failed.', 'wp-optimize'), htmlspecialchars($this->get_advanced_cache_filename())); $message .= ' '.__('Please check file and directory permissions on the file paths up to this point, and your PHP error log.', 'wp-optimize'); WP_Optimize()->include_template('notices/cache-notice.php', false, array('message' => $message)); } /** * Scheduler public functions to update schedulers * * @param array $schedules An array of schedules being passed. * @return array An array of schedules being returned. */ public function cron_schedules($schedules) { $page_cache_length = $this->config->get_option('page_cache_length'); // When the interval is less than `WP_CRON_LOCK_TIMEOUT` error messages are triggered // So, instead of `0` (now) we are making it equal to the constant value. // https://github.com/WordPress/WordPress/commit/84d19848666a81584e0007a6ab7f7ad3c990d71a if (defined('WP_CRON_LOCK_TIMEOUT') && $page_cache_length < WP_CRON_LOCK_TIMEOUT) { $page_cache_length = WP_CRON_LOCK_TIMEOUT; } $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')); $interval = WP_Optimize_Page_Cache_Preloader::instance()->get_continue_preload_cron_interval(); $schedules['wpo_page_cache_preload_continue_interval'] = array( 'interval' => $interval, // translators: %d is the number of minutes 'display' => sprintf(__('%d minutes', 'wp-optimize'), round($interval / 60, 1)) ); $schedules['wpo_use_cache_lifespan'] = array( 'interval' => $page_cache_length, // translators: %s is the cache lifespan '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')) ); return $schedules; } /** * Update cache config file to reflect the webp images option */ public function update_webp_images_option() { if ($this->is_enabled()) { $cache_settings = WPO_Cache_Config::instance()->get(); $cache_settings['use_webp_images'] = WP_Optimize()->get_options()->get_option('webp_conversion'); WPO_Cache_Config::instance()->update($cache_settings); } } /** * May be regenerate cache config file, in case of migrations */ public function maybe_regenerate_cache_config_file() { $config_file = WPO_CACHE_CONFIG_DIR . '/'.$this->config->get_cache_config_filename(); if (!file_exists($config_file)) { $config = $this->config->get(); $this->config->write($config); } } /** * Checks if the given cache directory is empty * * @param string $path The path to the cache directory. * @return bool Returns true if the cache directory is empty, false otherwise. */ public static function is_cache_empty($path) { if (!is_dir($path)) return true; if ($handle = opendir($path)) { while (false !== ($entry = readdir($handle))) { if ("." == $entry || ".." == $entry) { continue; } $full_path = $path . '/' . $entry; if (is_file($full_path)) { closedir($handle); return false; } } closedir($handle); return true; } return true; } /** * Remove query params from request url * * @param string $url The request url. * @return string Returns url without query params. */ private static function remove_query_params($url) { $parsed_url = wp_parse_url($url); if (!$parsed_url) return ''; return $parsed_url['scheme'] . '://' . $parsed_url['host'] . $parsed_url['path']; } /** * Check configuration for auto preloading after cache deletion * * @return bool */ public function should_auto_preload_purged_contents() { $wpo_cache = WP_Optimize()->get_page_cache(); $wpo_cache_options = $wpo_cache->config->get(); return $wpo_cache_options['auto_preload_purged_contents']; } /** * Logging of interesting messages related to Cache Purging * * @param string $message * @param int $post_id */ public function file_log($message, $post_id = 0) { if (!empty($post_id)) { if (false !== strpos($message, '{{URL}}')) { $message = str_replace('{{URL}}', get_permalink($post_id), $message); } if (false !== strpos($message, '{{title}}')) { $message = str_replace('{{title}}', '"' . get_the_title($post_id) . '"', $message); } } $this->file_logger->info($message); } /** * Prunes the log file */ public function prune_cache_logs() { $this->file_log("Pruning the Cache log file"); $this->file_logger->prune_logs(); } /** * Update .htaccess file to serve cached files directly. * * @param bool $enable */ public function update_serve_cache_rules_htaccess_section($enable) { $htaccess = new WP_Optimize_Htaccess(); $section_title = 'WP-Optimize rules to serve cached files'; if ($enable) { if (!$htaccess->is_commented_section_exists($section_title)) { $htaccess->update_commented_section($this->prepare_apache_cache_handle_section(), $section_title, true); $htaccess->write_file(); } } elseif ($htaccess->is_commented_section_exists($section_title)) { $htaccess->remove_commented_section($section_title); $htaccess->write_file(); } } /** * Get the .htaccess section with rules to serve cached files * * @return array */ private function prepare_apache_cache_handle_section() { $site_root = $this->get_site_root_path(); return array( array( '<IfModule mod_rewrite.c>', 'RewriteEngine On', 'RewriteCond %{REQUEST_METHOD} GET|HEAD', 'RewriteCond %{QUERY_STRING} =""', 'RewriteCond %{HTTP:Cookie} =""', 'RewriteCond %{REQUEST_URI} !^/(wp-(?:admin|login|register|comments-post|cron|json))/ [NC]', 'RewriteCond %{HTTP_USER_AGENT} !(android|blackberry|ipad|iphone|ipod|windows.phone|iEMobile|opera.mini|opera.mobile|webos|symbian|windows.mobile|kindle|googlebot.mobile) [NC]', 'RewriteCond %{DOCUMENT_ROOT}'.$site_root.'wp-content/cache/wpo-cache/%{HTTP_HOST}%{REQUEST_URI}index.html -f', 'RewriteRule ^(.*)$ '.$site_root.'wp-content/cache/wpo-cache/%{HTTP_HOST}%{REQUEST_URI}index.html [L]', array( '<IfModule mod_headers.c>', 'Header always set X-WP-Optimize-Cache-Header "Loaded from WP-Optimize cache" env=REDIRECT_STATUS', '</IfModule>', ), '</IfModule>', ), ); } /** * Get relative site root path, if site is placed in the subdirectory then it returns /subdirectory otherwise / * * @return string */ private function get_site_root_path($default = '/') { $site_root = wp_parse_url(site_url()); if (isset($site_root['path'])) { $site_root = trailingslashit($site_root['path']); } else { $site_root = $default; } return $site_root; } } endif; PK ��}\��P�� �� # file-based-page-cache-functions.phpnu �[��� <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Extensions directory. */ if (!defined('WPO_CACHE_EXT_DIR')) define('WPO_CACHE_EXT_DIR', dirname(__FILE__).'/extensions'); /** * Holds utility functions used by file based cache */ /** * Cache output before it goes to the browser. If moving/renaming this function, then also change the check above. * * @param String $buffer Page HTML. * @param Int $flags OB flags to be passed through. * * @return String */ if (!function_exists('wpo_cache')) : function wpo_cache($buffer, $flags) { // This case appears to happen for unclear reasons without WP being fully loaded, e.g. https://wordpress.org/support/topic/fatal-error-since-wp-5-8-update/ . It is simplest just to short-circuit it. if ('' === $buffer) return ''; // This array records reasons why no caching took place. Be careful not to allow actions to proceed that should not - i.e. take note of its state appropriately. $no_cache_because = array(); if (strlen($buffer) < 255) { // translators: %s is the number of bytes $no_cache_because[] = sprintf(__('Output is too small (less than %d bytes) to be worth caching', 'wp-optimize'), 255); } $restricted_page_type_cache = apply_filters('wpo_restricted_cache_page_type', false); if ($restricted_page_type_cache) { $no_cache_because[] = $restricted_page_type_cache; } $conditional_tag_exceptions = apply_filters('wpo_url_in_conditional_tags_exceptions', false); if ($conditional_tag_exceptions) { $no_cache_because[] = $conditional_tag_exceptions; } // Don't cache pages for logged in users. if (!function_exists('is_user_logged_in') || (function_exists('wp_get_current_user') && is_user_logged_in())) { if (!wpo_cache_loggedin_users()) { $no_cache_because[] = __('User is logged in', 'wp-optimize'); } elseif (!empty($GLOBALS['wpo_cache_config']['enable_user_caching'])) { // Will only run when "Serve cached pages to logged in users" is checked $no_cache_because[] = __('User is logged in, this works only when the cache is preloaded', 'wp-optimize'); } } // No root cache folder, so short-circuit here if (!file_exists(WPO_CACHE_DIR)) { $no_cache_because[] = __('WP-O cache parent directory was not found', 'wp-optimize').' ('.WPO_CACHE_DIR.')'; } elseif (!file_exists(WPO_CACHE_FILES_DIR)) { // Try creating a folder for cached files, if it was flushed recently if (!mkdir(WPO_CACHE_FILES_DIR)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir -- wp_mkdir_p not available this early $no_cache_because[] = __('WP-O cache directory was not found', 'wp-optimize').' ('.WPO_CACHE_FILES_DIR.')'; } else { wpo_disable_cache_directories_viewing(); } } // If comments are opened and the user has saved his information. if (function_exists('comments_open') && function_exists('get_post') && get_post() && comments_open()) { $commenter = wp_get_current_commenter(); // if any of the fields contain something, do not save to cache if ('' != $commenter['comment_author'] || '' != $commenter['comment_author_email'] || '' != $commenter['comment_author_url']) { $no_cache_because[] = __('Comments are opened and the visitor saved his information.', 'wp-optimize'); } } $can_cache_page = true; if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) { $can_cache_page = false; } /** * Defines if the page can be cached or not * * @param boolean $can_cache_page */ $can_cache_page_filter = apply_filters('wpo_can_cache_page', $can_cache_page); if (!$can_cache_page_filter) { if ($can_cache_page) { $can_cache_page = false; $no_cache_because[] = __('wpo_can_cache_page filter forbade it', 'wp-optimize'); } else { $no_cache_because[] = __('DONOTCACHEPAGE constant forbade it and wpo_can_cache_page filter did not over-ride it', 'wp-optimize'); } } if (defined('REST_REQUEST') && REST_REQUEST) { $no_cache_because[] = __('This is a REST API request (identified by REST_REQUEST constant)', 'wp-optimize'); } // Don't cache with fatal error pages. $last_error = error_get_last(); if (is_array($last_error) && E_ERROR == $last_error['type']) { $no_cache_because[] = __('This page has a fatal error', 'wp-optimize'); } if (http_response_code() >= 500) { // translators: %s is the HTTP response code for critical errors $no_cache_because[] = sprintf(__('This page has a critical error (HTTP code %s)', 'wp-optimize'), http_response_code()); } elseif (http_response_code() >= 400) { // translators: %s is the HTTP response code for unauthorised access $no_cache_because[] = sprintf(__('This page returned an HTTP unauthorised response code (%s)', 'wp-optimize'), http_response_code()); } if (empty($no_cache_because)) { $buffer = apply_filters('wpo_pre_cache_buffer', $buffer, $flags); $url_path = wpo_get_url_path(); $dirs = explode('/', $url_path); $path = WPO_CACHE_FILES_DIR; foreach ($dirs as $dir) { if (!empty($dir)) { $path .= '/' . $dir; if (!file_exists($path)) { if (!mkdir($path)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir -- wp_mkdir_p not available this early $no_cache_because[] = __('Attempt to create subfolder within cache directory failed', 'wp-optimize')." ($path)"; break; } } } } } if (!empty($no_cache_because)) { $message = implode(', ', $no_cache_because); // Add http headers wpo_cache_add_nocache_http_header($message); if ((!defined('DOING_CRON') || !DOING_CRON) && (!defined('REST_REQUEST') || !REST_REQUEST)) { $not_cached_details = ""; // Output the reason only when the user has turned on debugging if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug']))) { $not_cached_details = "because: ".htmlspecialchars($message) . " "; } $buffer .= sprintf("\n<!-- WP Optimize page cache - https://getwpo.com - page NOT cached %s-->\n", $not_cached_details); } return $buffer; } else { // Prevent mixed content when there's an http request but the site URL uses https. $home_url = get_home_url(); if (!is_ssl() && 'https' === strtolower(parse_url($home_url, PHP_URL_SCHEME))) { // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- wp_parse_url not available this early $https_home_url = $home_url; $http_home_url = str_ireplace('https://', 'http://', $https_home_url); $buffer = str_replace(esc_url($http_home_url), esc_url($https_home_url), $buffer); } $modified_time = time(); // Take this as soon before writing as possible $timezone_string = ''; $utc = isset($GLOBALS['wpo_cache_config']['gmt_offset']) ? (float) $GLOBALS['wpo_cache_config']['gmt_offset'] : 0; $modified_time += $utc * 3600; if (!empty($GLOBALS['wpo_cache_config']['timezone_string'])) { $timezone_string = 'UTC' !== $GLOBALS['wpo_cache_config']['timezone_string'] ? $GLOBALS['wpo_cache_config']['timezone_string'] : ''; } if (!empty($timezone_string)) { $timezone_postfix = "(".$timezone_string." UTC:". $utc .")"; } else { $timezone_postfix = "(UTC:" . $utc . ")"; } $add_to_footer = ''; /** * Filter whether to display the html comment <!-- Cached by WP-Optimize ... --> * * @param boolean $show - Whether to display the html comment * @return boolean */ if (preg_match('#</html>#i', $buffer) && (apply_filters('wpo_cache_show_cached_by_comment', true) || (defined('WP_DEBUG') && WP_DEBUG))) { $date_time_format = 'F j, Y g:i a'; if (!empty($GLOBALS['wpo_cache_config']['date_format']) && !empty($GLOBALS['wpo_cache_config']['time_format'])) { $date_time_format = $GLOBALS['wpo_cache_config']['date_format'] . ' ' . $GLOBALS['wpo_cache_config']['time_format']; } if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching']) && wpo_is_mobile()) { $add_to_footer .= "\n<!-- Cached by WP-Optimize - for mobile devices - https://getwpo.com - Last modified: " . gmdate($date_time_format, $modified_time) . " " . $timezone_postfix . " -->\n"; } else { $add_to_footer .= "\n<!-- Cached by WP-Optimize - https://getwpo.com - Last modified: " . gmdate($date_time_format, $modified_time) . " " . $timezone_postfix . " -->\n"; } } // Create an empty index.php file in the cache directory for disable directory viewing. if (!is_file($path . '/index.php')) file_put_contents($path . '/index.php', ''); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem not available this early /** * Save $buffer into cache file. */ $file_ext = '.html'; if (wpo_feeds_caching_enabled()) { if (is_feed()) { $file_ext = '.rss-xml'; } } $cache_filename = wpo_cache_filename($file_ext); $cache_file = $path . '/' .$cache_filename; if (defined('WPO_CACHE_FILENAME_DEBUG') && WPO_CACHE_FILENAME_DEBUG) { $add_to_footer .= "\n<!-- WP Optimize page cache debug information -->\n"; if (!empty($GLOBALS['wpo_cache_filename_debug']) && is_array($GLOBALS['wpo_cache_filename_debug'])) { $add_to_footer .= "<!-- \n" . join("\n", array_map('htmlspecialchars', $GLOBALS['wpo_cache_filename_debug'])) . "\n --->"; } } // if we can then cache gzipped content in .gz file. if (function_exists('gzencode') && apply_filters('wpo_allow_cache_gzip_files', true)) { // Only replace inside the addition, not inside the main buffer (e.g. post content) file_put_contents($cache_file . '.gz', gzencode($buffer.str_replace('by WP-Optimize', 'by WP-Optimize (gzip)', $add_to_footer), apply_filters('wpo_cache_gzip_level', 6))); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem not available this early } file_put_contents($cache_file, $buffer.$add_to_footer); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem not available this early if (is_callable('WP_Optimize')) { // delete cached information about cache size. WP_Optimize()->get_page_cache()->delete_cache_size_information(); } else { // If the shutdown occurs before plugins are loaded, // then this will trigger a fatal error, so, we check first if (!doing_action('shutdown')) { error_log('[WPO_CACHE] WP_Optimize() is not callable.'); $message = 'Please report this to WP-O support: '; if (function_exists('wp_debug_backtrace_summary')) { $message .= wp_debug_backtrace_summary(); } else { $message .= wpo_debug_backtrace_summary(); } error_log($message); } } header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary. header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header('WPO-Cache-Status: saving to cache'); if (wpo_cache_can_output_gzip_content()) { if (!wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip')) { header('Content-Encoding: gzip'); } // Disable php gzip to avoid double compression. ini_set('zlib.output_compression', 'Off'); return ob_gzhandler($buffer, $flags); } else { return $buffer; } } } endif; /** * Load files for support plugins. */ if (!function_exists('wpo_cache_load_extensions')) : function wpo_cache_load_extensions() { $extensions = glob(WPO_CACHE_EXT_DIR . '/*.php'); // Add external extensions if (defined('WPO_CACHE_CUSTOM_EXT_DIR') && is_dir(WPO_CACHE_CUSTOM_EXT_DIR)) { $extensions = array_merge($extensions, glob(WPO_CACHE_CUSTOM_EXT_DIR . '/*.php')); } if (empty($extensions)) return; foreach ($extensions as $extension) { if (is_file($extension)) require_once $extension; } } endif; if (!function_exists('wpo_restricted_cache_page_type')) { function wpo_restricted_cache_page_type($restricted) { global $post; // Don't cache search or password protected. if ((function_exists('is_search') && is_search()) || (function_exists('is_404') && is_404()) || !empty($post->post_password)) { $restricted = __('Page type is not cacheable (search, 404 or password-protected)', 'wp-optimize'); } // Don't cache the front page if option is set. if (in_array('/', wpo_get_url_exceptions()) && function_exists('is_front_page') && is_front_page()) { $restricted = __('In the settings, caching is disabled for the front page', 'wp-optimize'); } // Don't cache htacesss. Remember to properly escape any output to prevent injection. if (strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) { $restricted = 'The file path is unsuitable for caching ('.$_SERVER['REQUEST_URI'].')'; } // Don't cache feeds. if (function_exists('is_feed') && is_feed() && !wpo_feeds_caching_enabled()) { $restricted = __('We don\'t cache RSS feeds', 'wp-optimize'); } return $restricted; } } /** * Returns true if we need cache content for loggedin users. * * @return bool */ if (!function_exists('wpo_cache_loggedin_users')) : function wpo_cache_loggedin_users() { return !empty($GLOBALS['wpo_cache_config']['enable_user_caching']) || !empty($GLOBALS['wpo_cache_config']['enable_user_specific_cache']) || (function_exists('wpo_we_cache_per_role') && wpo_we_cache_per_role()); } endif; /** * Get filename for store cache, depending on gzip, mobile and cookie settings. * * @param string $ext * @return string */ if (!function_exists('wpo_cache_filename')) : function wpo_cache_filename($ext = '.html') { $wpo_cache_filename_debug = array(); $filename = 'index'; if (wpo_cache_mobile_caching_enabled() && wpo_is_mobile()) { $filename = 'mobile.' . $filename; } if (wpo_webp_images_enabled() && !wpo_is_using_webp_images_redirection() && wpo_is_using_alter_html()) { $filename = $filename . '.webp'; } $cookies = wpo_cache_cookies(); $cache_key = ''; /** * Add cookie values to filename if need. * This section was inspired by things learned from WP-Rocket. */ if (!empty($cookies)) { foreach ($cookies as $key => $cookie_name) { if (is_array($cookie_name) && isset($_COOKIE[$key])) { foreach ($cookie_name as $cookie_key) { if (isset($_COOKIE[$key][$cookie_key]) && '' !== $_COOKIE[$key][$cookie_key]) { $_cache_key = $cookie_key.'='.$_COOKIE[$key][$cookie_key]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'Cookie: name: ' . $key . '[' . $cookie_key . '], value: *** , cache_key:' . $_cache_key; } } continue; } if (isset($_COOKIE[$cookie_name]) && '' !== $_COOKIE[$cookie_name]) { $_cache_key = $cookie_name.'='.$_COOKIE[$cookie_name]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'Cookie: name: ' . $cookie_name . ', value: *** , cache_key:' . $_cache_key; } } } $query_variables = wpo_cache_query_variables(); /** * Add GET variables to cache file name if need. */ if (!empty($query_variables)) { foreach ($query_variables as $variable) { if (isset($_GET[$variable]) && !empty($_GET[$variable])) { $_cache_key = $variable.'='.$_GET[$variable]; $_cache_key = preg_replace('/[^a-z0-9_\-\=]/i', '-', $_cache_key); $cache_key .= '-' . $_cache_key; $wpo_cache_filename_debug[] = 'GET parameter: name: ' . $variable . ', value:' . htmlentities($_GET[$variable]) . ', cache_key:' . $_cache_key; } } } // Adding cache key with queried cookies and variables to the cache file name. if ('' !== $cache_key) { // Add human-readable cache key to the filename $filename .= str_replace('--', '-', '-'.$cache_key); } $filename = apply_filters('wpo_cache_filename', $filename); // Trimming filename if it exceeds 240 characters due to filesystem limitations if (strlen($filename) > 240) { $filename = substr($filename, 0, 199) . '-' . sha1($filename); } $wpo_cache_filename_debug[] = 'Extension: ' . $ext; $wpo_cache_filename_debug[] = 'Filename: ' . $filename.$ext; $GLOBALS['wpo_cache_filename_debug'] = $wpo_cache_filename_debug; return $filename . $ext; } endif; /** * Returns site url from site_url() function or if it is not available from cache configuration. */ if (!function_exists('wpo_site_url')) : function wpo_site_url() { if (is_callable('site_url')) return site_url('/'); $site_url = empty($GLOBALS['wpo_cache_config']['site_url']) ? '' : $GLOBALS['wpo_cache_config']['site_url']; return $site_url; } endif; /** * Get cookie names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_cookies')) : function wpo_cache_cookies() { $cookies = empty($GLOBALS['wpo_cache_config']['wpo_cache_cookies']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_cookies']; return $cookies; } endif; /** * Get GET variable names which impact on cache file name. * * @return array */ if (!function_exists('wpo_cache_query_variables')) : function wpo_cache_query_variables() { if (defined('WPO_CACHE_URL_PARAMS') && WPO_CACHE_URL_PARAMS) { $variables = array_keys($_GET); } else { $variables = empty($GLOBALS['wpo_cache_config']['wpo_cache_query_variables']) ? array() : $GLOBALS['wpo_cache_config']['wpo_cache_query_variables']; } if (!empty($variables)) { sort($variables); } return wpo_cache_maybe_ignore_query_variables($variables); } endif; /** * Get list of all received HTTP headers. * * @return array */ if (!function_exists('wpo_get_http_headers')) : function wpo_get_http_headers() { static $headers; if (!empty($headers)) return $headers; $headers = array(); // if is apache server then use get allheaders() function. if (function_exists('getallheaders')) { $headers = getallheaders(); } else { // https://www.php.net/manual/en/function.getallheaders.php foreach ($_SERVER as $key => $value) { $key = strtolower($key); if ('HTTP_' == substr($key, 0, 5)) { $headers[str_replace(' ', '-', ucwords(str_replace('_', ' ', substr($key, 5))))] = $value; } elseif ('content_type' == $key) { $headers["Content-Type"] = $value; } elseif ('content_length' == $key) { $headers["Content-Length"] = $value; } } } return $headers; } endif; /** * Check if requested Accept-Encoding headers has gzip value. * * @return bool */ if (!function_exists('wpo_cache_gzip_accepted')) : function wpo_cache_gzip_accepted() { $headers = wpo_get_http_headers(); if (isset($headers['Accept-Encoding']) && preg_match('/gzip/i', $headers['Accept-Encoding'])) return true; return false; } endif; /** * Check if we can output gzip content in current answer, i.e. check Accept-Encoding headers has gzip value * and function ob_gzhandler is available. * * @return bool */ if (!function_exists('wpo_cache_can_output_gzip_content')) : function wpo_cache_can_output_gzip_content() { return wpo_cache_gzip_accepted() && function_exists('ob_gzhandler'); } endif; /** * Check if header with certain name exists in already prepared headers and has value comparable with $header_value. * * @param string $header_name header name * @param string $header_value header value as regexp. * * @return bool */ if (!function_exists('wpo_cache_is_in_response_headers_list')) : function wpo_cache_is_in_response_headers_list($header_name, $header_value) { $headers_list = headers_list(); if (!empty($headers_list)) { $header_name = strtolower($header_name); foreach ($headers_list as $value) { $value = explode(':', $value); if (strtolower($value[0]) == $header_name) { if (preg_match('/'.$header_value.'/', $value[1])) { return true; } else { return false; } } } } return false; } endif; /** * Check if mobile cache is enabled and current request is from moblile device. * * @return bool */ if (!function_exists('wpo_cache_mobile_caching_enabled')) : function wpo_cache_mobile_caching_enabled() { if (!empty($GLOBALS['wpo_cache_config']['enable_mobile_caching'])) return true; return false; } endif; /** * Check if webp images enabled * * @return bool */ if (!function_exists('wpo_webp_images_enabled')) : function wpo_webp_images_enabled() { if (!empty($GLOBALS['wpo_cache_config']['use_webp_images'])) return true; return false; } endif; /** * Check whether webp images using alter html method or not * * @return bool */ if (!function_exists('wpo_is_using_alter_html')) : function wpo_is_using_alter_html() { return (isset($_SERVER['HTTP_ACCEPT']) && false !== strpos($_SERVER['HTTP_ACCEPT'], 'image/webp')); } endif; /** * Check whether webp images are served using redirect * * @return bool */ if (!function_exists('wpo_is_using_webp_images_redirection')) : function wpo_is_using_webp_images_redirection() { if (empty($GLOBALS['wpo_cache_config']['uploads'])) return false; $uploads_dir = $GLOBALS['wpo_cache_config']['uploads']; $htaccess_file = $uploads_dir . '/.htaccess'; if (!file_exists($htaccess_file)) return false; $htaccess_content = file_get_contents($htaccess_file); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- WP_Filesystem not available this early $comment_sections = array('Register webp mime type', 'WP-Optimize WebP Rules'); if (function_exists('str_contains')) { return str_contains($htaccess_content, $comment_sections[0]) && str_contains($htaccess_content, $comment_sections[1]); } else { return strpos($htaccess_content, $comment_sections[0]) && strpos($htaccess_content, $comment_sections[1]); } } endif; /** * Verify if the current request is related to the Activity Stream * * @return bool */ if (!function_exists('wpo_is_activity_stream_requested')) : function wpo_is_activity_stream_requested() { return (isset($_SERVER['HTTP_ACCEPT']) && preg_match('/(application\/(ld\+json|activity\+json|json))/i', $_SERVER['HTTP_ACCEPT'] )); } endif; /** * Verify if the current request is robots.txt */ if (!function_exists('wpo_is_robots_txt_requested')) : function wpo_is_robots_txt_requested() { return (isset($_SERVER['REQUEST_URI']) && 'robots.txt' === basename($_SERVER['REQUEST_URI'])); } endif; /** * Serves the cache and exits */ if (!function_exists('wpo_serve_cache')) : function wpo_serve_cache() { // Do not serve cache for cron requests. if (defined('DOING_CRON') && DOING_CRON) return; $file_name = wpo_cache_filename(); $file_name_rss_xml = wpo_cache_filename('.rss-xml'); $send_as_feed = false; $path_dir = WPO_CACHE_FILES_DIR . '/' . wpo_get_url_path() . '/'; $path = $path_dir . $file_name; if (wpo_feeds_caching_enabled()) { // check for .xml cache file if .html cache file doesn't exist if (!file_exists($path_dir . $file_name) && file_exists($path_dir . $file_name_rss_xml)) { $path = $path_dir . $file_name_rss_xml; $send_as_feed = true; } } $use_gzip = false; // if we can use gzip and gzipped file exist in cache we use it. // if headers already sent we don't use gzipped file content. if (!headers_sent() && wpo_cache_gzip_accepted() && file_exists($path . '.gz')) { $path .= '.gz'; $use_gzip = true; } $modified_time = file_exists($path) ? (int) filemtime($path) : time(); // Cache has expired, purge and exit. if (!empty($GLOBALS['wpo_cache_config']['page_cache_length'])) { if (time() > ($GLOBALS['wpo_cache_config']['page_cache_length'] + $modified_time)) { wpo_delete_files($path); return; } } if ($use_gzip) { // Disable zlib output compression to avoid double content compression ini_set('zlib.output_compression', 'Off'); } $gzip_header_already_sent = wpo_cache_is_in_response_headers_list('Content-Encoding', 'gzip'); header('Cache-Control: no-cache'); // Check back later if (!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) { if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } if ($send_as_feed) { header('Content-type: application/rss+xml'); } header('WPO-Cache-Status: cached'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304); exit; } if (file_exists($path) && is_readable($path)) { if (wpo_is_canonical_redirection_needed()) return; if ($use_gzip && !$gzip_header_already_sent) { header('Content-Encoding: gzip'); } // send correct headers for xml and txt files $filename = basename(dirname($path)); if (preg_match('/\.xml$/i', $filename)) { header('Content-type: text/xml'); } if (preg_match('/\.txt$/i', $filename)) { header('Content-type: text/plain'); } if ($send_as_feed) { header('Content-type: application/rss+xml'); } header('WPO-Cache-Status: cached'); if (!empty($modified_time)) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'); } readfile($path); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- If we use `get_contents` we need to echo it, it will result in not escaped error exit; } } endif; /** * Check if all requirements needed to serve the cache are met. * * @return bool|array returns false or an array with messages if one of the requirements is not met */ if (!function_exists('wpo_can_serve_from_cache')) : function wpo_can_serve_from_cache() { $no_cache_because = array(); if (wpo_is_robots_txt_requested()) { return false; } if (wpo_is_activity_stream_requested()) { return false; } // Fix for compatibility issue with Jetpack's infinity scroll feature if (isset($_GET['infinity']) && 'scrolling' === $_GET['infinity']) { return false; } // check in not disabled current user agent if (!empty($_SERVER['HTTP_USER_AGENT']) && false === wpo_is_accepted_user_agent($_SERVER['HTTP_USER_AGENT'])) { $no_cache_because[] = "In the settings, caching is disabled for matches for this request's user agent"; } $is_cache_page_forced = function_exists('apply_filters') ? apply_filters('wpo_cache_page_force', false) : false; $is_get_request = isset($_SERVER['REQUEST_METHOD']) && 'GET' === $_SERVER['REQUEST_METHOD']; // Don't cache non-GET requests. if (!$is_cache_page_forced && !$is_get_request) { $no_cache_because[] = 'The request method was not GET ('.(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '-').')'; } // Don't cache if logged in. if (!empty($_COOKIE)) { $wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_'); if (!wpo_cache_loggedin_users()) { foreach ($_COOKIE as $key => $value) { foreach ($wp_cookies as $cookie) { if (false !== strpos($key, $cookie)) { $no_cache_because[] = 'WordPress login cookies were detected'; break(2); } } } } if (!empty($_COOKIE['wpo_commented_post'])) { $no_cache_because[] = 'The user has commented on a post (comment cookie set)'; } // get cookie exceptions from options. $cache_exception_cookies = empty($GLOBALS['wpo_cache_config']['cache_exception_cookies']) ? array() : $GLOBALS['wpo_cache_config']['cache_exception_cookies']; // check if any cookie exists from exception list. if (!empty($cache_exception_cookies)) { foreach ($_COOKIE as $key => $value) { foreach ($cache_exception_cookies as $cookie) { if ('' != trim($cookie) && false !== strpos($key, $cookie)) { $no_cache_because[] = 'An excepted cookie was set ('.$key.')'; break 2; } } } } } // Deal with optional cache exceptions. if (wpo_url_in_exceptions(wpo_current_url())) { $no_cache_because[] = 'In the settings, caching is disabled for matches for the current URL'; } if (!empty($_GET)) { $get_variable_names = wpo_cache_query_variables(); $get_variables = wpo_cache_maybe_ignore_query_variables(array_keys($_GET)); // if GET variables include one or more undefined variable names then we don't cache. $get_variables_diff = array_diff($get_variables, $get_variable_names); if (!empty($get_variables_diff)) { $no_cache_because[] = "In the settings, caching is disabled for matches for one of the current request's GET parameters"; } } $file_extension = $_SERVER['REQUEST_URI']; $file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension); $file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension)); // Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc. if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && preg_match('#sitemap([a-zA-Z0-9_-]+)?\.xml$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) { $no_cache_because[] = 'The request extension is not suitable for caching'; } if (!empty($no_cache_because)) return $no_cache_because; return true; } endif; /** * Checks and does redirection, if needed * * @return bool */ if (!function_exists('wpo_is_canonical_redirection_needed')) : function wpo_is_canonical_redirection_needed() { $permalink_structure = isset($GLOBALS['wpo_cache_config']['permalink_structure']) ? $GLOBALS['wpo_cache_config']['permalink_structure'] : ''; $site_url = wpo_site_url(); // Exit if server variables are not available. if (!isset($_SERVER['HTTP_HOST'])) return false; $schema = isset($_SERVER['HTTPS']) && 'on' === $_SERVER['HTTPS'] ? "https" : "http"; $url_part = "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; $requested_url = $schema . $url_part; $url_parts = parse_url($requested_url); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- wp_parse_url not available this early $extension = pathinfo($url_parts['path'], PATHINFO_EXTENSION); if (!empty($permalink_structure) && $requested_url != $site_url && ((isset($url_parts['path']) && '/' !== $url_parts['path']) || isset($url_parts['query']))) { $request_uri = rtrim($_SERVER['REQUEST_URI'], '?'); if ('/' == substr($permalink_structure, -1) && empty($extension) && empty($url_parts['query']) && empty($url_parts['fragment'])) { $url = preg_replace('/(.+?)([\/]*)(\[\?\#][^\/]+|$)/', '$1/$3', $request_uri); if (0 !== strcmp($request_uri, $url)) return true; } else { $url = rtrim($request_uri, '/'); if (0 !== strcmp($request_uri, $url)) return true; } } return false; } endif; /** * Clears the cache */ if (!function_exists('wpo_cache_flush')) : function wpo_cache_flush() { if (defined('WPO_CACHE_FILES_DIR') && '' != WPO_CACHE_FILES_DIR) wpo_delete_files(WPO_CACHE_FILES_DIR); if (function_exists('wp_cache_flush')) { wp_cache_flush(); } do_action('wpo_cache_flush'); } endif; /** * Get URL path for caching * * @since 1.0 * @return string */ if (!function_exists('wpo_get_url_path')) : function wpo_get_url_path($url = '') { $url = '' == $url ? wpo_current_url() : $url; $url_parts = parse_url($url); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- wp_parse_url not available this early if (isset($url_parts['path']) && false !== stripos($url_parts['path'], '/index.php')) { $url_parts['path'] = preg_replace('/(.*?)index\.php(\/.+)/i', '$1index-php$2', $url_parts['path']); } /* * Convert the hexadecimal digits within the percent-encoded triplet to uppercase, to ensure that the path remains * consistent. For instance, "example.com/%e0%a6" will be converted to "example.com/%E0%A6". */ if (isset($url_parts['path'])) { $url_parts['path'] = preg_replace_callback('/%[0-9A-F]{2}/i', function($matches) { return strtoupper($matches[0]); }, $url_parts['path']); } if (!isset($url_parts['host'])) $url_parts['host'] = ''; if (!isset($url_parts['path'])) $url_parts['path'] = ''; return $url_parts['host'].$url_parts['path']; } endif; /** * Get requested url. * * @return string */ if (!function_exists('wpo_current_url')) : function wpo_current_url() { // Note: We use `static $url` to save the first value we retrieve, as some plugins change $_SERVER later on in the process (e.g. Weglot). // Otherwise this function would return a different URL at the beginning and end of the cache process. static $url = ''; if ('' != $url) return $url; $http_host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ''; $url = rtrim('http' . ((isset($_SERVER['HTTPS']) && ('on' == $_SERVER['HTTPS'] || 1 == $_SERVER['HTTPS']) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO']) ? 's' : '' ) . '://' . $http_host.$_SERVER['REQUEST_URI'], '/'); return $url; } endif; /** * Return list of conditional tag exceptions. * * @return array */ if (!function_exists('wpo_get_conditional_tags_exceptions')) : function wpo_get_conditional_tags_exceptions() { static $exceptions = null; if (null !== $exceptions) return $exceptions; if (!empty($GLOBALS['wpo_cache_config'])) { if (empty($GLOBALS['wpo_cache_config']['cache_exception_conditional_tags'])) { $exceptions = array(); } else { $exceptions = $GLOBALS['wpo_cache_config']['cache_exception_conditional_tags']; } } elseif (class_exists('WPO_Page_Cache')) { $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists('cache_exception_conditional_tags', $config)) { $exceptions = $config['cache_exception_conditional_tags']; } else { $exceptions = array(); } $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r|\r\n)#', $exceptions); $exceptions = array_filter($exceptions, 'trim'); } else { $exceptions = array(); } return $exceptions; } endif; /** * Return list of url exceptions. * * @return array */ if (!function_exists('wpo_get_url_exceptions')) : function wpo_get_url_exceptions() { static $exceptions = null; if (null !== $exceptions) return $exceptions; // if called from file-based-page-cache.php when WP loading // and cache settings exists then use it otherwise get settings from database. if (!empty($GLOBALS['wpo_cache_config'])) { if (empty($GLOBALS['wpo_cache_config']['cache_exception_urls'])) { $exceptions = array(); } else { $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_urls']) ? $GLOBALS['wpo_cache_config']['cache_exception_urls'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_urls']); } } elseif (class_exists('WPO_Page_Cache')) { $config = WPO_Page_Cache::instance()->config->get(); if (is_array($config) && array_key_exists('cache_exception_urls', $config)) { $exceptions = $config['cache_exception_urls']; } else { $exceptions = array(); } $exceptions = is_array($exceptions) ? $exceptions : preg_split('#(\n|\r)#', $exceptions); $exceptions = array_filter($exceptions, 'trim'); } else { $exceptions = array(); } return apply_filters('wpo_get_url_exceptions', $exceptions); } endif; /** * Return true of exception url matches current url * * @param string $exception Exceptions to check URL against. * @param bool $regex Whether to check with regex or not. * @return bool true if matched, false otherwise */ if (!function_exists('wpo_current_url_exception_match')) : function wpo_current_url_exception_match($exception) { return wpo_url_exception_match(wpo_current_url(), $exception); } endif; /** * Check if url in conditional tags exceptions list. * * @return string */ if (!function_exists('wpo_url_in_conditional_tags_exceptions')) : function wpo_url_in_conditional_tags_exceptions() { $exceptions = wpo_get_conditional_tags_exceptions(); $restricted = ''; $allowed_functions = array('is_single', 'is_page', 'is_front_page', 'is_home', 'is_archive', 'is_tag', 'is_category', 'is_feed', 'is_search', 'is_author', 'is_woocommerce', 'is_shop', 'is_product', 'is_account_page', 'is_product_category', 'is_product_tag', 'is_wc_endpoint_url', 'is_bbpress', 'bbp_is_forum_archive', 'bbp_is_topic_archive', 'bbp_is_topic_tag', 'bbp_is_single_forum', 'bbp_is_single_topic', 'bbp_is_single_view', 'bbp_is_single_user', 'bbp_is_user_home', 'bbp_is_search'); //Filter for add more conditional tags to whitelist in the exceptions list. $allowed_functions = apply_filters('wpo_allowed_conditional_tags_exceptions', $allowed_functions); if (!empty($exceptions)) { foreach ($exceptions as $exception) { if (false !== strpos($exception, 'is_')) { $exception_function = $exception; if ('()' == substr($exception, -2)) { $exception_function = substr($exception, 0, -2); } if (in_array($exception_function, $allowed_functions) && function_exists($exception_function) && call_user_func($exception_function)) { // translators: %s is the function name for conditional tag $restricted = sprintf(__('In the settings, caching is disabled for %s', 'wp-optimize'), $exception_function); } } } } return $restricted; } endif; /** * Check if url in exceptions list. * * @param string $url * * @return bool */ if (!function_exists('wpo_url_in_exceptions')) : function wpo_url_in_exceptions($url) { $exceptions = wpo_get_url_exceptions(); if (!empty($exceptions)) { foreach ($exceptions as $exception) { // don't check / - front page using regexp, we handle it in wpo_restricted_cache_page_type() if ('/' == $exception) continue; if (wpo_url_exception_match($url, $exception)) { // Exception match. return true; } } } return false; } endif; /** * Checks if an URL matches against listed exceptions. * * @param string $url - complete url string i.e. http(s)://domain/path * @param string $exception - complete url or absolute path, can contain (.*) wildcards; Sometimes can be urlencoded * * @return bool */ if (!function_exists('wpo_url_exception_match')) : function wpo_url_exception_match($url, $exception) { if (preg_match('#^[\s]*$#', $exception)) { return false; } $exception = str_replace('*', '.*', $exception); $exception = trim($exception); // Used to test websites placed in subdirectories. $sub_dir = ''; // If exception defined from root i.e. /page1 then remove domain part in url. if (preg_match('/^\//', $exception)) { // get site sub directory. $sub_dir = preg_replace('#^(http|https):\/\/.*\/#Ui', '', wpo_site_url()); // add prefix slash and remove slash. $sub_dir = ('' == $sub_dir) ? '' : '/' . rtrim($sub_dir, '/'); // get relative path $url = preg_replace('#^(http|https):\/\/.*\/#Ui', '/', $url); } $url = urldecode(rtrim($url, '/')) . '/'; $exception = rtrim($exception, '/'); // if we have no wildcard in the end of exception then add slash. if (!preg_match('#\(\.\*\)$#', $exception)) $exception .= '/'; $exception = preg_quote($exception); // fix - unescape some possibly escaped mask characters $search = array( '\\.\\*', '\\-', ); $replace = array( '.*', '-', ); $exception = urldecode(str_replace($search, $replace, $exception)); return (preg_match('#^'.$exception.'$#i', $url) || preg_match('#^'.$sub_dir.$exception.'$#i', $url)); } endif; /** * Checks if its a mobile device * * @see https://developer.wordpress.org/reference/functions/wp_is_mobile/ */ if (!function_exists('wpo_is_mobile')) : function wpo_is_mobile() { if (empty($_SERVER['HTTP_USER_AGENT'])) { $is_mobile = false; // many mobile devices (all iPhone, iPad, etc.) } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false ) { $is_mobile = true; } else { $is_mobile = false; } return $is_mobile; } endif; /** * Check if current browser agent is not disabled in options. * * @return bool */ if (!function_exists('wpo_is_accepted_user_agent')) : function wpo_is_accepted_user_agent($user_agent) { if (empty($GLOBALS['wpo_cache_config'])) return true; $exceptions = is_array($GLOBALS['wpo_cache_config']['cache_exception_browser_agents']) ? $GLOBALS['wpo_cache_config']['cache_exception_browser_agents'] : preg_split('#(\n|\r)#', $GLOBALS['wpo_cache_config']['cache_exception_browser_agents']); if (!empty($exceptions)) { foreach ($exceptions as $exception) { if ('' == trim($exception)) continue; if (preg_match('#'.$exception.'#i', $user_agent)) return false; } } return true; } endif; if (!function_exists('wpo_delete_files')) : /** * Deletes a specified source file or directory. * * If $src is a file, only that file will be deleted. If $src is a directory, the behavior depends on the * $recursive parameter. When $recursive is true, the directory and its contents (including files and subdirectories) * will be deleted. When $recursive is false, only the files in the top-level directory(eg. $src directory) will be deleted, * while the $src directory itself and its subdirectories will remain untouched. * * @param string $src The path to the source file or directory to delete. * @param bool $recursive (Optional) When set to true, the directory and its contents (including files and subdirectories) * will be deleted. If false, only the files in the top-level directory will be deleted while * its subdirectories will be preserved. Defaults to true. * * @return bool Returns true if the specified file or all files within the specified directory (and its subdirectories, * when $recursive is true) are successfully deleted. Returns false if any file(s) could not be deleted * due to file permissions or other reasons. */ function wpo_delete_files($src, $recursive = true) { // If the source doesn't exist, consider it deleted and return true if (!file_exists($src)) { return true; } /* * If the source is a file, delete it and return the result. * If `unlink()` fails, we also verify if the file still exists before returning the result, as another * PHP process may have already deleted the file between the execution of `is_file()` and `unlink()` operations. */ if (is_file($src)) { // phpcs:disable // Generic.PHP.NoSilencedErrors.Discouraged -- suppress PHP warning in case of failure // WordPress.WP.AlternativeFunctions.unlink_unlink -- wp_delete_file may not be available this early if (!@unlink($src) && file_exists($src)) { return false; } // phpcs:enable return true; } $success = true; // If recursive is false, delete only the top-level files and return the result if (!$recursive) { $dir_handle = @opendir($src); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress PHP warning in case of failure /* * If opendir() is successful, process directory contents. If not, check if the directory exists. * If it exists, return false (failure). Otherwise, assume it's already deleted and return true (success). */ if (false !== $dir_handle) { while (false !== ($file = readdir($dir_handle))) { if ('.' == $file || '..' == $file) { continue; } $full_path = $src . '/' . $file; // If it's a file, delete it if (is_file($full_path)) { if (!wpo_delete_files($full_path)) { $success = false; } } } closedir($dir_handle); } else { if (file_exists($src)) { $success = false; } } return $success; } // If recursive is true, delete all files and directories recursively $dir_handle = @opendir($src); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- suppress PHP warning in case of failure /* * If opendir() is successful, process directory contents. If not, check if the directory exists. * If it exists, return false (failure). Otherwise, assume it's already deleted and return true (success). */ if (false !== $dir_handle) { while (false !== ($file = readdir($dir_handle))) { if ('.' == $file || '..' == $file) { continue; } $full_path = $src . '/' . $file; if (!wpo_delete_files($full_path)) { $success = false; } } closedir($dir_handle); } else { if (file_exists($src)) { $success = false; } } /* * Delete the source directory itself. * Success of `rmdir` operation is not recorded; we only ultimately care about emptying, not removing * entirely (empty folders in our context are harmless) */ if ($success) { // phpcs:disable // WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- WP_Filesystem not available this early // Generic.PHP.NoSilencedErrors.Discouraged -- suppress errors from displaying @rmdir($src); // phpcs:enable } // Delete cached information about cache size WP_Optimize()->get_page_cache()->delete_cache_size_information(); return $success; } endif; if (!function_exists('wpo_is_empty_dir')) : /** * Check if selected directory is empty or has only index.php which we added for security reasons. * * @param string $dir * * @return bool */ function wpo_is_empty_dir($dir) { if (!file_exists($dir) || !is_dir($dir)) return false; $handle = opendir($dir); if (false === $handle) return false; $is_empty = true; $file = readdir($handle); while (false !== $file) { if ('.' != $file && '..' != $file && 'index.php' != $file) { $is_empty = false; break; } $file = readdir($handle); } closedir($handle); return $is_empty; } endif; /** * Either store for later output, or output now. Only the most-recent call will be effective. * * @param String|Null $output - if not null, then the string to use when called by the shutdown action. */ if (!function_exists('wpo_cache_add_footer_output')) : function wpo_cache_add_footer_output($output = null) { static $buffered = null; if (null === $buffered) { add_action('shutdown', 'wpo_cache_add_footer_output', 11); $buffered = $output; } elseif ('shutdown' == current_filter()) { // Only add the line if it was a page, not something else (e.g. REST response) if (did_action('wp_footer') && !preg_match('/\/wp\-json\//', $_SERVER['REQUEST_URI']) && apply_filters('wpo_cache_show_cached_by_comment', true)) { echo "\n<!-- WP Optimize page cache - https://getwpo.com - ".esc_html($buffered)." -->\n"; } elseif (defined('WPO_CACHE_DEBUG') && WPO_CACHE_DEBUG && (!defined('REST_REQUEST') || !REST_REQUEST)) { error_log('[CACHE DEBUG] '.wpo_current_url() . ' - ' . $buffered); } } } endif; /** * Remove variable names that shouldn't influence cache. * * @param array $variables List of variable names. * * @return array */ if (!function_exists('wpo_cache_maybe_ignore_query_variables')) : function wpo_cache_maybe_ignore_query_variables($variables) { /** * Filters the current $_GET variables that will be used when caching or excluding from cache. * Currently: * - 'wpo_cache_debug' (Shows the reason for not being cached even when WP_DEBUG isn't set) * - 'doing_wp_cron' (alternative cron) * - 'aiosp_sitemap_path', 'aiosp_sitemap_page' (All in one SEO sitemap) * - 'xml_sitemap', 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged' (SEOPress sitemap) * - 'sitemap', 'sitemap_n' (YOAST SEO sitemap) */ $exclude_variables = array( 'wpo_cache_debug', // Shows the reason for not being cached even when WP_DEBUG isn't set 'doing_wp_cron', // alternative cron 'aiosp_sitemap_path', // All in one SEO sitemap 'aiosp_sitemap_page', 'xml_sitemap', // SEOPress sitemap 'seopress_sitemap', 'seopress_news', 'seopress_video', 'seopress_cpt', 'seopress_paged', 'sitemap', // YOAST SEO sitemap 'sitemap_n', ); $exclude_variables = function_exists('apply_filters') ? apply_filters('wpo_cache_ignore_query_variables', $exclude_variables) : $exclude_variables; if (empty($exclude_variables)) return $variables; foreach ($exclude_variables as $variable) { $exclude = array_search($variable, $variables); if (false !== $exclude) { array_splice($variables, $exclude, 1); } } return $variables; } endif; /** * Get cache config * * @param string $key - The config item * @param mixed $default - The default value * * @return mixed */ if (!function_exists('wpo_cache_config_get')) : function wpo_cache_config_get($key, $default = false) { $config = $GLOBALS['wpo_cache_config']; if (!$config) return false; if (isset($config[$key])) { return $config[$key]; } else { return $default; } } endif; if (!function_exists('wpo_read_cache_directory_htaccess')) : /** * Read .htaccess file for the cache directory. * * @return string */ function wpo_read_cache_directory_htaccess() { $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess'; return is_file($htaccess_filename) ? file_get_contents($htaccess_filename) : ''; // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- WP_Filesystem not available this early } endif; if (!function_exists('wpo_write_cache_directory_htaccess')) : /** * Write .htaccess file for the cache directory. * * @param string $htaccess_content * * @return void */ function wpo_write_cache_directory_htaccess($htaccess_content) { $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess'; // phpcs:disable // WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem not available this early // Generic.PHP.NoSilencedErrors.Discouraged -- suppress errors from displaying @file_put_contents($htaccess_filename, $htaccess_content); // phpcs:enable } endif; if (!function_exists('wpo_allow_access_to_index_cache_files')) : /** * Update the .htaccess file to allow access to index.html files in the cache directory. * * @return void */ function wpo_allow_access_to_index_cache_files() { $htaccess_content = wpo_read_cache_directory_htaccess(); if (false === strpos($htaccess_content, 'Allow access to index.html files')) { $allow_access_to_index_html = "\n\n# Allow access to index.html files\n<FilesMatch \"index\\.html$\">\n\tOrder allow,deny\n\tAllow from all\n</FilesMatch>"; $htaccess_content .= $allow_access_to_index_html; wpo_write_cache_directory_htaccess($htaccess_content); } } endif; if (!function_exists('wpo_disable_cache_directories_viewing')) : /** * Create config files to disable cache directory viewing * * @return void */ function wpo_disable_cache_directories_viewing() { global $is_apache, $is_IIS, $is_iis7; if (!is_dir(WPO_CACHE_FILES_DIR)) return; // Create a .htaccess file for apache server. if ($is_apache) { $htaccess_filename = WPO_CACHE_FILES_DIR . '/.htaccess'; // CS does not like heredoc // phpcs:disable $htaccess_content = <<<EOF # Disable directory browsing Options -Indexes # Disable access to any files <FilesMatch ".*"> Order allow,deny Deny from all </FilesMatch> EOF; // phpcs:enable if (!is_file($htaccess_filename)) wpo_write_cache_directory_htaccess($htaccess_content); } // Create web.config file for IIS servers. if ($is_IIS || $is_iis7) { $webconfig_filename = WPO_CACHE_FILES_DIR . '/web.config'; $webconfig_content = "<configuration>\n<system.webServer>\n<authorization>\n<deny users=\"*\" />\n</authorization>\n</system.webServer>\n</configuration>\n"; // phpcs:disable // Generic.PHP.NoSilencedErrors.Discouraged -- suppress the error when there is file permission issues // WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem not available this early if (!is_file($webconfig_filename)) @file_put_contents($webconfig_filename, $webconfig_content); // phpcs:enable } // Create empty index.php file for all servers. // phpcs:disable // Generic.PHP.NoSilencedErrors.Discouraged -- suppress the error when there is file permission issues // WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- WP_Filesystem not available this early if (!is_file(WPO_CACHE_FILES_DIR . '/index.php')) @file_put_contents(WPO_CACHE_FILES_DIR . '/index.php', ''); // phpcs:enable } endif; /** * Add the headers indicating why the page is not cached or served from cache * * @param string $message - The headers * * @return void */ if (!function_exists('wpo_cache_add_nocache_http_header')) : function wpo_cache_add_nocache_http_header($message = '') { if (!headers_sent()) { header('WPO-Cache-Status: not cached'); header('WPO-Cache-Message: '. trim(str_replace(array("\r", "\n", ':'), ' ', strip_tags($message)))); // phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags -- wp_strip_all_tags not available this early } } endif; /** * Add the headers indicating why the page is not cached or served from cache by integrating with the send_headers filter * * @param string $message - The headers * * @return void */ if (!function_exists('wpo_cache_add_nocache_http_header_with_send_headers_action')) : function wpo_cache_add_nocache_http_header_with_send_headers_action(string $message) { if ('' != $message && !headers_sent()) { wpo_cache_add_nocache_http_header($message); } } endif; /** * Check if feeds caching enabled * * @return bool */ if (!function_exists('wpo_feeds_caching_enabled')) : function wpo_feeds_caching_enabled() { return apply_filters('wpo_feeds_caching_enabled', true); } endif; if (!function_exists('wpo_debug_backtrace_summary')) { function wpo_debug_backtrace_summary($ignore_class = null, $skip_frames = 0, $pretty = true) { static $truncate_paths; $trace = debug_backtrace(false); $caller = array(); $check_class = !is_null($ignore_class); $skip_frames++; // Skip this function. if (!isset($truncate_paths)) { $truncate_paths = array( wpo_normalize_path(WP_CONTENT_DIR), wpo_normalize_path(ABSPATH), ); } foreach ($trace as $call) { if ($skip_frames > 0) { $skip_frames--; } elseif (isset($call['class'])) { if ($check_class && $ignore_class == $call['class']) { continue; // Filter out calls. } $caller[] = "{$call['class']}{$call['type']}{$call['function']}"; } else { if (in_array($call['function'], array('do_action', 'apply_filters', 'do_action_ref_array', 'apply_filters_ref_array'), true)) { $caller[] = "{$call['function']}('{$call['args'][0]}')"; } elseif (in_array($call['function'], array('include', 'include_once', 'require', 'require_once'), true)) { $filename = isset($call['args'][0]) ? $call['args'][0] : ''; $caller[] = $call['function'] . "('" . str_replace($truncate_paths, '', wpo_normalize_path($filename)) . "')"; } else { $caller[] = $call['function']; } } } if ($pretty) { return implode(', ', array_reverse($caller)); } else { return $caller; } } } if (!function_exists('wpo_normalize_path')) { function wpo_normalize_path($path) { // Standardise all paths to use '/'. $path = str_replace('\\', '/', $path); // Replace multiple slashes down to a singular, allowing for network shares having two slashes. $path = preg_replace('|(?<=.)/+|', '/', $path); // Windows paths should uppercase the drive letter. if (':' === substr($path, 1, 1)) { $path = ucfirst($path); } return $path; } } /** * Get path to wp-config.php when called from WP-CLI. * * @return string */ if (!function_exists('wpo_wp_cli_locate_wp_config')) : function wpo_wp_cli_locate_wp_config() { $config_path = ''; if (is_callable('\WP_CLI\Utils\locate_wp_config')) { $config_path = \WP_CLI\Utils\locate_wp_config(); } return $config_path; } endif; /** * Retrieves and sanitizes a value from a superglobal array in a way similar to WordPress's sanitize_text_field(), * for use before WordPress is fully loaded * * @param string $key * @param string $global_type * @return string sanitized string. */ if (!function_exists('wpo_early_sanitize_superglobal_text')) : function wpo_early_sanitize_superglobal_text(string $key, string $global_type = 'server'): string { $str = ''; // phpcs:disable // Sanitized later in the code, without using WordPress functions as they are not available at this stage if ('server' === $global_type) { $str = $_SERVER[$key] ?? ''; } // phpcs:enable if ('' === $str || !is_scalar($str)) { return ''; } // Remove backslashes (simulate wp_unslash()). $str = stripslashes((string) $str); // Remove ASCII control characters (0x00–0x1F and 0x7F). $str = preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // Trim whitespace and encode special HTML characters. return htmlspecialchars(trim($str), ENT_QUOTES, 'UTF-8'); } endif; PK ��}\\�HM� � class-wpo-cache-config.phpnu �[��� <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * Handles cache configuration and related I/O */ if (!class_exists('WPO_Cache_Config')) : class WPO_Cache_Config { /** * Defaults * * @var array */ public $defaults; /** * Instance of this class * * @var mixed */ public static $instance; /** * @var array */ public $config; /** * Set config defaults */ public function __construct() { $this->defaults = $this->get_defaults(); } /** * Get config from file or cache * * @return array */ public function get() { if (is_multisite()) { $config = get_site_option('wpo_cache_config', $this->defaults); } else { $config = get_option('wpo_cache_config', $this->defaults); } return wp_parse_args($config, $this->defaults); } /** * Get a specific configuration option * * @param string $option_key The option identifier * @param boolean $default Default value if the option doesn't exist (Default to false) * @return mixed */ public function get_option($option_key, $default = false) { $options = $this->get(); return apply_filters("wpo_option_key_{$option_key}", (isset($options[$option_key]) ? $options[$option_key] : $default)); } /** * Updates the given config object in file and DB * * @param array $config - the cache configuration * @param boolean $skip_disk_if_not_yet_present - only write the configuration file to disk if it already exists. This presents PHP notices if the cache has never been on, and settings are saved. * * @return true|WP_Error - returns true on success or WP_Error if the config cannot be written to disk */ public function update($config, $skip_disk_if_not_yet_present = false) { $config = wp_parse_args($config, $this->defaults); $config['page_cache_length_value'] = intval($config['page_cache_length_value']); $config['page_cache_length'] = $this->calculate_page_cache_length($config['page_cache_length_value'], $config['page_cache_length_unit']); /** * Filters the cookies used to set cache file names * * @param array $cookies - The cookies * @param array $config - The new config */ $wpo_cache_cookies = apply_filters('wpo_cache_cookies', array(), $config); sort($wpo_cache_cookies); /** * Filters the query variables used to set cache file names * * @param array $wpo_query_variables - The variables * @param array $config - The new config */ $wpo_query_variables = apply_filters('wpo_cache_query_variables', array(), $config); sort($wpo_query_variables); $config['wpo_cache_cookies'] = $wpo_cache_cookies; $config['wpo_cache_query_variables'] = $wpo_query_variables; $config = apply_filters('wpo_cache_update_config', $config); if (is_multisite()) { update_site_option('wpo_cache_config', $config); } else { update_option('wpo_cache_config', $config); } do_action('wpo_cache_config_updated', $config); return $this->write($config, $skip_disk_if_not_yet_present); } /** * Calculate cache expiration value in seconds. * * @param int $value * @param string $unit ( hours | days | months ) * * @return int */ private function calculate_page_cache_length($value, $unit) { $cache_length_units = array( 'hours' => 3600, 'days' => 86400, 'months' => 2629800, // 365.25 * 86400 / 12 ); return $value * $cache_length_units[$unit]; } /** * Deletes config files and options * * @return bool */ public function delete() { if (is_multisite()) { delete_site_option('wpo_cache_config'); } else { delete_option('wpo_cache_config'); } if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) { return false; } return true; } /** * Writes config to file * * @param array $config - Configuration array. * @param boolean $only_if_present - only writes to the disk if the configuration file already exists * * @return true|WP_Error - returns true on success or WP_Error if an attempt to write failed */ public function write($config, $only_if_present = false) { $config_file = $this->get_config_file_path(); $this->config = wp_parse_args($config, $this->defaults); // from 3.0.17 we use more secure way to store cache config files. $advanced_cache_version = WPO_Page_Cache::instance()->get_advanced_cache_version(); // if advanced-cache.php exists and has at least 3.0.17 version or // advanced-cache.php doesn't exist then // we write the cache config in a new format. if (($advanced_cache_version && (version_compare($advanced_cache_version, '3.0.17', '>='))) || !$advanced_cache_version) { // Apply the encoding required for placing within PHP single quotes - https://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.single $json_encoded_string = str_replace(array('\\', "'"), array('\\\\', '\\\''), wp_json_encode($this->config)); $config_content = '<?php' . "\n" . 'if (!defined(\'ABSPATH\')) die(\'No direct access allowed\');' . "\n\n" . '$GLOBALS[\'wpo_cache_config\'] = json_decode(\'' . $json_encoded_string . '\', true);' . "\n"; } else { $config_content = wp_json_encode($this->config); } if ((!$only_if_present || file_exists($config_file)) && (!wp_is_writable(WPO_CACHE_CONFIG_DIR) || !file_put_contents($config_file, $config_content))) { // translators: %s is the path to the cache config file return new WP_Error('write_cache_config', sprintf(__('The cache configuration file could not be saved to the disk; please check the file/folder permissions of %s .', 'wp-optimize'), $config_file)); } return true; } /** * Get config file name with full path. * * @return string */ public function get_config_file_path() { return WPO_CACHE_CONFIG_DIR . '/' . $this->get_cache_config_filename(); } /** * Return defaults * * @return array */ public function get_defaults() { $defaults = array( 'enable_page_caching' => false, 'page_cache_length_value' => 24, 'page_cache_length_unit' => 'hours', 'page_cache_length' => 86400, 'cache_exception_conditional_tags' => array(), 'cache_exception_urls' => array(), 'cache_exception_cookies' => array(), 'cache_exception_browser_agents' => array(), 'enable_sitemap_preload' => false, 'enable_schedule_preload' => false, 'preload_schedule_type' => '', 'enable_mobile_caching' => false, 'enable_user_caching' => false, 'site_url' => network_home_url('/'), 'enable_cache_per_country' => false, 'enable_cache_aelia_currency' => false, 'permalink_structure' => get_option('permalink_structure'), 'uploads' => wp_normalize_path(wp_upload_dir()['basedir']), 'gmt_offset' => get_option('gmt_offset'), 'timezone_string' => get_option('timezone_string'), 'date_format' => get_option('date_format'), 'time_format' => get_option('time_format'), 'use_webp_images' => false, 'show_avatars' => 0, 'host_gravatars_locally' => 0, 'auto_preload_purged_contents' => true ); return apply_filters('wpo_cache_defaults', $defaults); } /** * Get advanced-cache.php file name with full path. * * @return string */ public function get_cache_config_filename() { $url = wp_parse_url(network_site_url()); if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) { return 'config-'.strtolower($url['host']).'-port'.$url['port'].'.php'; } else { return 'config-'.strtolower($url['host']).'.php'; } } /** * Return an instance of the current class, create one if it doesn't exist * * @since 1.0 * @return WPO_Cache_Config */ public static function instance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } endif; PK ��}\�ҍU. U. $ class-wp-optimize-cache-commands.phpnu �[��� <?php if (!defined('ABSPATH')) die('No direct access allowed'); /** * All cache commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data. */ class WP_Optimize_Cache_Commands { private $optimizer; private $options; /** * WP_Optimize_Cache_Commands constructor. */ public function __construct() { $this->optimizer = WP_Optimize()->get_optimizer(); $this->options = WP_Optimize()->get_options(); } /** * Save cache settings * * @param array $data * * @return array */ public function save_cache_settings($data) { if (!class_exists('WPO_Cache_Config')) return array( 'result' => false, 'message' => "WPO_Cache_Config class doesn't exist", ); // filter for validate cache settings before save it. $validation = apply_filters('wpo_save_cache_settings_validation', $data['cache-settings']); if (!empty($validation) && isset($validation['result']) && false === $validation['result']) { return $validation; } $enabled = false; $disabled = false; $return = empty($validation) ? array() : $validation; $previous_settings = WPO_Cache_Config::instance()->get(); // Attempt to change current status if required if (isset($previous_settings['enable_page_caching']) && $previous_settings['enable_page_caching'] != $data['cache-settings']['enable_page_caching']) { // Disable cache. if (empty($data['cache-settings']['enable_page_caching'])) { $disabled = WPO_Page_Cache::instance()->disable(); // Disabling failed if ($disabled && is_wp_error($disabled)) { // If disabling failed, we re-enable whatever was disabled, to make sure nothing breaks. if ($previous_settings['enable_page_caching']) WPO_Page_Cache::instance()->enable(true); $return['error'] = array( 'code' => $disabled->get_error_code(), 'message' => $disabled->get_error_message() ); } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was disabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } else { // we need to rebuild advanced-cache.php and add WP_CACHE to wp-config. $enabled = WPO_Page_Cache::instance()->enable(true); // Enabling failed if (is_wp_error($enabled)) { // disable everything, to avoid half enabled things WPO_Page_Cache::instance()->disable(); $return['error'] = array( 'code' => $enabled->get_error_code(), 'message' => $enabled->get_error_message() ); if (WPO_Page_Cache::instance()->advanced_cache_file_writing_error) { $return['advanced_cache_file_writing_error'] = true; $return['advanced_cache_file_content'] = WPO_Page_Cache::instance()->advanced_cache_file_content; } } elseif (WPO_Page_Cache::instance()->has_warnings()) { $return['warnings_label'] = __('Page caching was enabled, but with some warnings:', 'wp-optimize'); $return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning'); } } // Override enabled setting value $data['cache-settings']['enable_page_caching'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); } else { $data['cache-settings']['enable_page_caching'] = $previous_settings['enable_page_caching']; $enabled = $previous_settings['enable_page_caching']; } $data['cache-settings']['use_webp_images'] = (bool) WP_Optimize()->get_options()->get_option('webp_conversion'); $skip_if_no_file_yet = !$enabled || is_wp_error($enabled); $save_settings_result = WPO_Cache_Config::instance()->update($data['cache-settings'], $skip_if_no_file_yet); if ($save_settings_result && !is_wp_error($save_settings_result)) { WP_Optimize_Page_Cache_Preloader::instance()->cache_settings_updated($data['cache-settings'], $previous_settings); $return['result'] = $save_settings_result; } else { // Saving the settings returned an error if (is_wp_error($save_settings_result)) { if (isset($return['error'])) { $return['error']['message'] .= "\n\n".$save_settings_result->get_error_message(); } else { $return['error'] = array( 'code' => $save_settings_result->get_error_code(), 'message' => $save_settings_result->get_error_message() ); } } $return['result'] = false; } $return['enabled'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled)); if ($enabled && !is_wp_error($enabled)) { if (isset($data['cache-settings']['host_gravatars_locally']) && $data['cache-settings']['host_gravatars_locally'] !== $previous_settings['host_gravatars_locally']) { $cache = WPO_Page_Cache::instance(); $cache->file_log('Host gravatars locally setting changed, purging cache'); $cache->purge(); } } // $disable can either be boolean or WP_Error if (!is_wp_error($disabled) && $disabled) { WPO_Page_Cache::instance()->prune_cache_logs(); wp_clear_scheduled_hook('wpo_prune_cache_logs'); } return $return; } /** * Get information about current cache status. Used in cli commands. * * @return array */ public function get_status_info() { $status = array(); $status[] = WPO_Page_Cache::instance()->is_enabled() ? __('Caching is enabled', 'wp-optimize') : __('Caching is disabled', 'wp-optimize'); $preloader_status = WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); // translators: %s: The current cache size $status[] = sprintf(__('Current cache size: %s', 'wp-optimize'), $preloader_status['size']); // translators: %s: The number of files in the cache $status[] = sprintf(__('Number of files: %s', 'wp-optimize'), $preloader_status['file_count']); if (array_key_exists('message', $preloader_status)) $status[] = $preloader_status['message']; $status['message'] = join(PHP_EOL, $status); return $status; } /** * Enable cache. */ public function enable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = true; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Disable cache. */ public function disable() { $settings = WPO_Cache_Config::instance()->get(); $settings['enable_page_caching'] = false; return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings))); } /** * Purge WP-Optimize page cache. * * @return array */ public function purge_page_cache() { $wpo_page_cache = WP_Optimize()->get_page_cache(); if (!$wpo_page_cache->is_enabled()) { return array( 'success' => false, 'error' => __('Cache is not enabled.', 'wp-optimize'), ); } if (!$wpo_page_cache->can_purge_cache() && !(defined('WP_CLI') && WP_CLI)) { return array( 'success' => false, 'message' => __('You do not have permission to purge the cache', 'wp-optimize'), ); } $purged = WP_Optimize()->get_page_cache()->purge(); if ($purged) WP_Optimize()->get_page_cache()->file_log("Full Cache Purge triggered by: " . __METHOD__); $cache_size = WP_Optimize()->get_page_cache()->get_cache_size(); $wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance(); $response = array( 'success' => $purged, 'size' => WP_Optimize()->format_size($cache_size['size']), 'file_count' => $cache_size['file_count'], ); // if scheduled preload enabled then reschedule and run preloader. if ($wpo_page_cache_preloader->is_scheduled_preload_enabled()) { // cancel preload and reschedule preload action. $wpo_page_cache_preloader->cancel_preload(); $wpo_page_cache_preloader->reschedule_preload(); // run preloader. $wpo_page_cache_preloader->run('scheduled', $response); } elseif ($wpo_page_cache->should_auto_preload_purged_contents()) { // When auto preload is enabled but scheduled preload is disabled $wpo_page_cache_preloader->run('manual', $response); } if ($response['success']) { $response['message'] = __('Page cache purged successfully', 'wp-optimize'); } return $response; } /** * Run cache preload (for wp-cli). * * @return array|bool */ public function run_cache_preload_cli() { if (!(defined('WP_CLI') && WP_CLI)) return false; // define WPO_ADVANCED_CACHE constant as WP-CLI doesn't load advanced-cache.php file // but we check this constant value wen detecting status of cache if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true); // don't interrupt queue processing add_filter('updraft_interrupt_tasks_queue_load-url-task', '__return_false', 99); // if preloading is running then exit. if (WP_Optimize_Page_Cache_Preloader::instance()->is_busy()) { return array( 'success' => false, 'error' => __('Preloading is currently running in another process.', 'wp-optimize'), ); } // set default response. $response = array( 'success' => true, 'message' => __('All URLs were preloaded into cache successfully', 'wp-optimize'), ); WP_CLI::log(__('Preloading URLs into cache...', 'wp-optimize')); return WP_Optimize_Page_Cache_Preloader::instance()->run('manual', $response); } /** * Run cache preload action. * * @return void|array - Doesn't return anything if run() is successful (Run() prints a JSON object and closed browser connection) or an array if failed. */ public function run_cache_preload() { return WP_Optimize_Page_Cache_Preloader::instance()->run('manual'); } /** * Cancel cache preload action. * * @return array */ public function cancel_cache_preload() { WP_Optimize_Page_Cache_Preloader::instance()->cancel_preload(); return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Get status of cache preload. * * @return array */ public function get_cache_preload_status() { return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info(); } /** * Enable or disable browser cache. * * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache] * @return array */ public function enable_browser_cache($params) { return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params); } /** * Format save_cache_settings() result for displaying in WP-CLI console * * @param array $response * @return array */ private function format_save_cache_settings_response($response) { $result = array( 'success' => $response['result'], ); if (isset($response['error'])) { $result['success'] = false; $result['error'] = $response['error']['message']; } if ($result['success']) { $result['message'] = __('Page cache settings updated successfully.', 'wp-optimize'); } return $result; } /** * Enable or disable auto preloading after cache purge * * @param array $params Option value sent via AJAX * @return array */ public function save_cache_auto_preload_option($params) { $wpo_cache = WP_Optimize()->get_page_cache(); $wpo_cache_options = $wpo_cache->config->get(); $wpo_cache_options['auto_preload_purged_contents'] = 'true' === $params['enabled'] ? 1 : 0; $update_status = $wpo_cache->config->update($wpo_cache_options); if (is_wp_error($update_status)) { $result = array( 'success' => false, 'message' => $update_status->get_error_message(), ); } else { $result = array( 'success' => true, 'message' => __('Auto preload settings have been updated successfully', 'wp-optimize'), ); } return $result; } } PK C~\��? $ settings_inc.exclude_cookies.tpl.phpnu �[��� <?php namespace LiteSpeed ; defined( 'WPINC' ) || exit ; ?> <tr> <th> <?php $id = Base::O_CACHE_EXC_COOKIES ; ?> <?php $this->title( $id ) ; ?> </th> <td> <?php $this->build_textarea( $id ) ; ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'To prevent %s from being cached, enter them here.', 'litespeed-cache' ), __( 'cookies', 'litespeed-cache') ) ; ?> <?php Doc::one_per_line() ; ?> <?php $this->_validate_syntax( $id ) ; ?> <br /><?php Doc::notice_htaccess() ; ?> </div> </td> </tr> PK D~\�թz z entry.tpl.phpnu �[��� <?php namespace LiteSpeed; defined( 'WPINC' ) || exit; $menu_list = array( 'cache' => __( 'Cache', 'litespeed-cache' ), 'ttl' => __( 'TTL', 'litespeed-cache' ), 'purge' => __( 'Purge', 'litespeed-cache' ), 'excludes' => __( 'Excludes', 'litespeed-cache' ), 'esi' => __( 'ESI', 'litespeed-cache' ), ); if ( ! $this->_is_multisite ) { $menu_list[ 'object' ] = __( 'Object', 'litespeed-cache' ); $menu_list[ 'browser' ] = __( 'Browser', 'litespeed-cache' ); } $menu_list[ 'advanced' ] = __( 'Advanced', 'litespeed-cache' ); /** * Generate rules for setting usage * @since 1.6.2 */ global $wp_roles; if ( !isset( $wp_roles ) ) { $wp_roles = new \WP_Roles(); } $roles = array(); foreach ( $wp_roles->roles as $k => $v ) { $roles[ $k ] = $v[ 'name' ]; } ksort( $roles ); ?> <div class="wrap"> <h1 class="litespeed-h1"> <?php echo __('LiteSpeed Cache Settings', 'litespeed-cache'); ?> </h1> <span class="litespeed-desc"> v<?php echo Core::VER; ?> </span> <hr class="wp-header-end"> </div> <div class="litespeed-wrap"> <h2 class="litespeed-header nav-tab-wrapper"> <?php $i = 1; $accesskey_set = array(); foreach ( $menu_list as $tab => $val ) { $accesskey = ''; if ( $i <= 9 ) { $accesskey = "litespeed-accesskey='$i'"; } else { $tmp = strtoupper( substr( $tab, 0, 1 ) ); if ( ! in_array( $tmp, $accesskey_set ) ) { $accesskey_set[] = $tmp; $accesskey = "litespeed-accesskey='$tmp'"; } } echo "<a class='litespeed-tab nav-tab' href='#$tab' data-litespeed-tab='$tab' $accesskey>$val</a>"; $i ++; } do_action( 'litespeed_settings_tab', 'cache' ); ?> </h2> <div class="litespeed-body"> <?php $this->cache_disabled_warning(); ?> <?php $this->form_action(); require LSCWP_DIR . "tpl/inc/check_if_network_disable_all.php"; require LSCWP_DIR . "tpl/cache/more_settings_tip.tpl.php"; // include all tpl for faster UE foreach ( $menu_list as $tab => $val ) { echo "<div data-litespeed-layout='$tab'>"; require LSCWP_DIR . "tpl/cache/settings-$tab.tpl.php"; echo "</div>"; } do_action( 'litespeed_settings_content', 'cache' ); $this->form_end(); ?> </div> </div> PK E~\��ZAw w ! settings_inc.cache_mobile.tpl.phpnu �[��� <?php namespace LiteSpeed; defined( 'WPINC' ) || exit; ?> <!-- build_setting_mobile_view start --> <tr> <th> <?php $id = Base::O_CACHE_MOBILE; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_switch( $id ); ?> <div class="litespeed-desc"> <?php echo __( 'Serve a separate cache copy for mobile visitors.', 'litespeed-cache' ); ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#cache-mobile', __( 'Learn more about when this is needed', 'litespeed-cache' ) ); ?> <br /><?php Doc::notice_htaccess(); ?> <br /><?php Doc::crawler_affected(); ?> </div> </td> </tr> <tr> <th class="litespeed-padding-left"> <?php $id = Base::O_CACHE_MOBILE_RULES; ?> <?php $this->title( $id ); ?> </th> <td> <?php // if set, use value as input value if ( $this->conf( Base::O_CACHE_MOBILE ) ) { // if enabled, check the setting in file if ( defined( 'LITESPEED_ON' ) ) { try { $mobile_agents = Htaccess::cls()->current_mobile_agents(); if ( $mobile_agents !== Utility::arr2regex( $this->conf( $id ), true ) ) { echo '<div class="litespeed-callout notice notice-error inline"><p>' . __( 'Htaccess did not match configuration option.', 'litespeed-cache' ) . ' ' . sprintf( __( 'Htaccess rule is: %s', 'litespeed-cache' ), '<code>' . $mobile_agents . '</code>' ) . '</p></div>'; } } catch( \Exception $e ) { echo '<div class="litespeed-callout notice notice-error inline"><p>' . $e->getMessage() . '</p></div>'; } } } ?> <div class="litespeed-textarea-recommended"> <div> <?php $this->build_textarea( $id, 40 ); ?> </div> <div> <?php $this->recommended( $id ); ?> </div> </div> <div class="litespeed-desc"> <?php Doc::one_per_line(); ?> <?php $this->_validate_syntax( $id ); ?> <?php if ( $this->conf( Base::O_CACHE_MOBILE ) && ! $this->conf( $id ) ) : ?> <font class="litespeed-warning"> ❌ <?php echo sprintf( __( 'If %1$s is %2$s, then %3$s must be populated!', 'litespeed-cache' ), '<code>' . __('Cache Mobile', 'litespeed-cache') . '</code>', '<code>' . __('ON', 'litespeed-cache') . '</code>', '<code>' . __('List of Mobile User Agents', 'litespeed-cache') . '</code>' ); ?> </font> <?php endif; ?> </div> </td> </tr> <!-- build_setting_mobile_view end -->PK E~\R?c ! settings_inc.login_cookie.tpl.phpnu �[��� <?php namespace LiteSpeed; defined('WPINC') || exit; ?> <tr> <th> <?php $id = Base::O_CACHE_LOGIN_COOKIE; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_input($id); $this->_validate_syntax($id); echo '<p class="litespeed-desc">' . __('SYNTAX: alphanumeric and "_".', 'litespeed-cache') . ' ' . __('No spaces and case sensitive.', 'litespeed-cache') . ' ' . __('MUST BE UNIQUE FROM OTHER WEB APPLICATIONS.', 'litespeed-cache') . '</p>' . '<p class="litespeed-desc">' . sprintf(__('The default login cookie is %s.', 'litespeed-cache'), '<code>_lscache_vary</code>') . ' ' . __('The server will determine if the user is logged in based on the existence of this cookie.', 'litespeed-cache') . ' ' . __('This setting is useful for those that have multiple web applications for the same domain.', 'litespeed-cache') . ' ' . __('If every web application uses the same cookie, the server may confuse whether a user is logged in or not.', 'litespeed-cache') . ' ' . __('The cookie set here will be used for this WordPress installation.', 'litespeed-cache') . '</p>' . '<p class="litespeed-desc">' . __('Example use case:', 'litespeed-cache') . '<br />' . sprintf(__('There is a WordPress installed for %s.', 'litespeed-cache'), '<u>www.example.com</u>') . '<br />' . sprintf(__('Then another WordPress is installed (NOT MULTISITE) at %s', 'litespeed-cache'), '<u>www.example.com/blog/</u>') . ' ' . __('The cache needs to distinguish who is logged into which WordPress site in order to cache correctly.', 'litespeed-cache') . '<br />'; ?> <?php Doc::notice_htaccess(); echo '</p>'; ?> <?php if (preg_match('#[^\w\-]#', $this->conf($id))) { echo '<div class="litespeed-callout notice notice-error inline"><p>❌ ' . __('Invalid login cookie. Invalid characters found.', 'litespeed-cache') . '</p></div>'; } if (defined('LITESPEED_ON') && $this->conf($id)) { $cookie_rule = ''; try { $cookie_rule = Htaccess::cls()->current_login_cookie(); } catch (\Exception $e) { echo '<div class="litespeed-callout notice notice-error inline"><p>' . $e->getMessage() . '</p></div>'; } $cookie_arr = explode(',', $cookie_rule); if (!in_array($this->conf($id), $cookie_arr)) { echo '<div class="litespeed-callout notice notice-warning inline"><p>' . __('WARNING: The .htaccess login cookie and Database login cookie do not match.', 'litespeed-cache') . '</p></div>'; } } ?> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_VARY_COOKIES; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_textarea($id, 50); $this->_validate_syntax($id); echo '<p class="litespeed-desc">' . __('SYNTAX: alphanumeric and "_".', 'litespeed-cache') . ' ' . __('No spaces and case sensitive.', 'litespeed-cache') . '</p>' . '<p class="litespeed-desc">' . ' ' . __('You can list the 3rd party vary cookies here.', 'litespeed-cache') . '</p>' . '<p class="litespeed-desc">'; ?> <?php Doc::notice_htaccess(); echo '</p>'; ?> </td> </tr>PK F~\��#�[ [ settings-esi.tpl.phpnu �[��� <?php namespace LiteSpeed ; defined( 'WPINC' ) || exit ; ?> <h3 class="litespeed-title-short"> <?php echo __( 'ESI Settings', 'litespeed-cache' ) ; ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#esi-tab' ); ?> </h3> <div class="litespeed-description"> <p><?php echo __( 'With ESI (Edge Side Includes), pages may be served from cache for logged-in users.', 'litespeed-cache' ) ; ?></p> <p><?php echo __( 'ESI allows you to designate parts of your dynamic page as separate fragments that are then assembled together to make the whole page. In other words, ESI lets you “punch holes” in a page, and then fill those holes with content that may be cached privately, cached publicly with its own TTL, or not cached at all.', 'litespeed-cache' ) ; ?> <?php Doc::learn_more( 'https://blog.litespeedtech.com/2017/08/30/wpw-private-cache-vs-public-cache/', __( 'WpW: Private Cache vs. Public Cache', 'litespeed-cache' ) ); ?> </p> <p> 💡: <?php echo __( 'You can turn shortcodes into ESI blocks.', 'litespeed-cache' ) ; ?> <?php echo sprintf( __( 'Replace %1$s with %2$s.', 'litespeed-cache' ), '<code>[shortcodeA att1="val1" att2="val2"]</code>', '<code>[esi shortcodeA att1="val1" att2="val2"]</code>' ) ; ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/admin/#turning-wordpress-shortcodes-into-esi-blocks' ); ?> </p> <p> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/api/#generate-esi-block-url', __( 'ESI sample for developers', 'litespeed-cache' ) ); ?> </p> </div> <div class="litespeed-relative"> <?php if ( ! LSWCP_ESI_SUPPORT && ! $this->conf( Base::O_CDN_QUIC ) ) : ?> <div class="litespeed-callout-danger"> <h4><?php echo __( 'WARNING', 'litespeed-cache' ) ; ?></h4> <h4><?php echo __( 'These options are only available with LiteSpeed Enterprise Web Server or QUIC.cloud CDN.', 'litespeed-cache' ); ?></h4> </div> <?php endif; ?> <table class="wp-list-table striped litespeed-table"><tbody> <tr> <th> <?php $id = Base::O_ESI ; ?> <?php $this->title( $id ) ; ?> </th> <td> <?php $this->build_switch( $id ) ; ?> <div class="litespeed-desc"> <?php echo __( 'Turn ON to cache public pages for logged in users, and serve the Admin Bar and Comment Form via ESI blocks. These two blocks will be uncached unless enabled below.', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_ESI_CACHE_ADMBAR ; ?> <?php $this->title( $id ) ; ?> </th> <td> <?php $this->build_switch( $id ) ; ?> <div class="litespeed-desc"> <?php echo __(' Cache the built-in Admin Bar ESI block.', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_ESI_CACHE_COMMFORM ; ?> <?php $this->title( $id ) ; ?> </th> <td> <?php $this->build_switch( $id ) ; ?> <div class="litespeed-desc"> <?php echo __( 'Cache the built-in Comment Form ESI block.', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_ESI_NONCE ; ?> <?php $this->title( $id ) ; ?> </th> <td> <div class="litespeed-row-flex"> <div class=""> <?php $this->build_textarea( $id ) ; ?> </div> <div class="litespeed-width-3-10"> <p class="litespeed-desc"> <?php echo __( 'The list will be merged with the predefined nonces in your local data file.', 'litespeed-cache' ); ?> <?php echo __( 'The latest data file is', 'litespeed-cache' ); ?>: <a href="https://github.com/litespeedtech/lscache_wp/blob/master/data/esi.nonces.txt" target="_blank">https://github.com/litespeedtech/lscache_wp/blob/master/data/esi.nonces.txt</a> <br /><font class="litespeed-success"> <?php echo __( 'API', 'litespeed-cache' ); ?>: <?php echo sprintf( __( 'Filter %s is supported.', 'litespeed-cache' ), '<code>litespeed_esi_nonces</code>' ); ?> </font> </p> </div> </div> <div class="litespeed-desc"> <?php echo __( 'The above nonces will be converted to ESI automatically.', 'litespeed-cache' ); ?> <?php Doc::one_per_line(); ?> <br /><?php echo __( 'An optional second parameter may be used to specify cache control. Use a space to separate', 'litespeed-cache' ); ?>: <code>my_nonce_action private</code> </div> <div class="litespeed-desc"> <?php echo sprintf( __( 'Wildcard %1$s supported (match zero or more characters). For example, to match %2$s and %3$s, use %4$s.', 'litespeed-cache' ), '<code>*</code>', '<code>nonce_formid_1</code>', '<code>nonce_formid_3</code>', '<code>nonce_formid_*</code>' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_VARY_GROUP ; ?> <?php $this->title( $id ) ; ?> </th> <td> <table class="litespeed-vary-table wp-list-table striped litespeed-table form-table"><tbody> <?php foreach ( $roles as $role => $title ): ?> <tr> <td class='litespeed-vary-title'><?php echo $title ; ?></td> <td class='litespeed-vary-val'> <?php $this->build_input( $id . '[' . $role . ']', 'litespeed-input-short', $this->cls( 'Vary' )->in_vary_group( $role ) ); ?> </td> </tr> <?php endforeach; ?> </tbody></table> <div class="litespeed-desc"> <?php echo __( 'If your site contains public content that certain user roles can see but other roles cannot, you can specify a Vary Group for those user roles. For example, specifying an administrator vary group allows there to be a separate publicly-cached page tailored to administrators (with “edit” links, etc), while all other user roles see the default public page.', 'litespeed-cache' ) ; ?> </div> </td> </tr> </tbody></table> </div> PK F~\#�; settings-advanced.tpl.phpnu �[��� <?php namespace LiteSpeed; defined('WPINC') || exit; ?> <h3 class="litespeed-title-short"> <?php echo __('Advanced Settings', 'litespeed-cache'); ?> <?php Doc::learn_more('https://docs.litespeedtech.com/lscache/lscwp/cache/#advanced-tab'); ?> </h3> <div class="litespeed-callout notice notice-warning inline"> <h4><?php echo __('NOTICE:', 'litespeed-cache'); ?></h4> <p><?php echo __('These settings are meant for ADVANCED USERS ONLY.', 'litespeed-cache'); ?></p> </div> <table class="wp-list-table striped litespeed-table"> <tbody> <tr> <th> <?php $id = Base::O_CACHE_AJAX_TTL; ?> <?php $this->title($id); ?> </th> <td> <div class="litespeed-textarea-recommended"> <div> <?php $this->build_textarea($id, 60); ?> </div> </div> <div class="litespeed-desc"> <?php echo __('Specify an AJAX action in POST/GET and the number of seconds to cache that request, separated by a space.', 'litespeed-cache'); ?> <?php Doc::one_per_line(); ?> </div> </td> </tr> <?php if (!$this->_is_multisite) : require LSCWP_DIR . 'tpl/cache/settings_inc.login_cookie.tpl.php'; endif; ?> <tr> <th> <?php $id = Base::O_UTIL_NO_HTTPS_VARY; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_switch($id); ?> <div class="litespeed-desc"> <?php echo __('Enable this option if you are using both HTTP and HTTPS in the same domain and are noticing cache irregularities.', 'litespeed-cache'); ?> <?php Doc::learn_more('https://docs.litespeedtech.com/lscache/lscwp/cache/#improve-httphttps-compatibility'); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_UTIL_INSTANT_CLICK; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_switch($id); ?> <div class="litespeed-desc"> <?php echo __('When a visitor hovers over a page link, preload that page. This will speed up the visit to that link.', 'litespeed-cache'); ?> <?php Doc::learn_more('https://docs.litespeedtech.com/lscache/lscwp/cache/#instant-click'); ?> <br /> <font class="litespeed-danger"> ⚠️ <?php echo __('This will generate extra requests to the server, which will increase server load.', 'litespeed-cache'); ?> </font> </div> </td> </tr> </tbody> </table>PK G~\V�<�< < $ settings_inc.cache_resources.tpl.phpnu �[��� <?php namespace LiteSpeed; defined( 'WPINC' ) || exit; ?> <!-- build_setting_cache_resources --> <tr> <th> <?php $id = Base::O_CACHE_RES; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_switch( $id ); ?> <div class="litespeed-desc"> <?php echo __( 'Some themes and plugins add resources via a PHP request.', 'litespeed-cache' ); ?> <?php echo __( 'Caching these pages may improve server performance by avoiding unnecessary PHP calls.', 'litespeed-cache' ); ?> <br /><?php Doc::notice_htaccess(); ?> </div> </td> </tr> PK G~\�kC�� � network_settings-cache.tpl.phpnu �[��� <?php namespace LiteSpeed; defined('WPINC') || exit; ?> <h3 class="litespeed-title-short"> <?php echo __('Cache Control Settings', 'litespeed-cache'); ?> <?php Doc::learn_more('https://docs.litespeedtech.com/lscache/lscwp/cache/'); ?> </h3> <table class="wp-list-table striped litespeed-table"> <tbody> <tr> <th><?php echo __('Network Enable Cache', 'litespeed-cache'); ?></th> <td> <?php $this->build_switch(Base::O_CACHE); ?> <div class="litespeed-desc"> <?php echo __('Enabling LiteSpeed Cache for WordPress here enables the cache for the network.', 'litespeed-cache'); ?><br /> <?php echo __('It is <b>STRONGLY</b> recommend that the compatibility with other plugins on a single/few sites is tested first.', 'litespeed-cache'); ?> <?php echo __('This is to ensure compatibility prior to enabling the cache for all sites.', 'litespeed-cache'); ?> </div> </td> </tr> <?php require LSCWP_DIR . 'tpl/cache/settings_inc.cache_resources.tpl.php'; require LSCWP_DIR . 'tpl/cache/settings_inc.cache_mobile.tpl.php'; require LSCWP_DIR . 'tpl/cache/settings_inc.cache_dropquery.tpl.php'; ?> </tbody> </table>PK H~\�M�u u network_settings-object.tpl.phpnu �[��� <?php namespace LiteSpeed; defined('WPINC') || exit(); require LSCWP_DIR . 'tpl/cache/settings_inc.object.tpl.php'; PK I~\�؉�� � ! network_settings-advanced.tpl.phpnu �[��� <?php namespace LiteSpeed; defined( 'WPINC' ) || exit; ?> <h3 class="litespeed-title-short"> <?php echo __( 'Advanced Settings', 'litespeed-cache' ); ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#advanced-tab' ); ?> </h3> <table class="wp-list-table striped litespeed-table"><tbody> <?php require LSCWP_DIR . 'tpl/cache/settings_inc.login_cookie.tpl.php'; ?> </tbody></table> PK J~\8�s� � settings_inc.browser.tpl.phpnu �[��� <?php namespace LiteSpeed; defined( 'WPINC' ) || exit; ?> <h3 class="litespeed-title-short"> <?php echo __( 'Browser Cache Settings', 'litespeed-cache' ); ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#browser-tab' ); ?> </h3> <?php if ( LITESPEED_SERVER_TYPE === 'LITESPEED_SERVER_OLS' ) : ?> <div class="litespeed-callout notice notice-warning inline"> <h4><?php echo __( 'NOTICE:', 'litespeed-cache' ); ?></h4> <p><?php echo __( 'OpenLiteSpeed users please check this', 'litespeed-cache' ); ?>: <?php Doc::learn_more( 'https://openlitespeed.org/kb/how-to-set-up-custom-headers/', __( 'Setting Up Custom Headers', 'litespeed-cache' ) ); ?></p> </div> <?php endif; ?> <table class="wp-list-table striped litespeed-table"><tbody> <tr> <th> <?php $id = Base::O_CACHE_BROWSER; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_switch( $id ); ?> <div class="litespeed-desc"> <?php echo __( 'Browser caching stores static files locally in the user\'s browser. Turn on this setting to reduce repeated requests for static files.', 'litespeed-cache' ); ?> <br /><?php Doc::notice_htaccess(); ?> <br /><?php echo sprintf( __( 'You can turn on browser caching in server admin too. <a %s>Learn more about LiteSpeed browser cache settings</a>.', 'litespeed-cache' ), 'href="https://docs.litespeedtech.com/lscache/lscwp/cache/#how-to-set-it-up" target="_blank"' ); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_TTL_BROWSER; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id ); ?> <?php $this->readable_seconds(); ?> <div class="litespeed-desc"> <?php echo __( 'The amount of time, in seconds, that files will be stored in browser cache before expiring.', 'litespeed-cache' ); ?> <?php $this->recommended( $id ); ?> <?php $this->_validate_ttl( $id, 30 ); ?> </div> </td> </tr> </tbody></table>PK K~\��5�v v network_settings-browser.tpl.phpnu �[��� <?php namespace LiteSpeed; defined('WPINC') || exit(); require LSCWP_DIR . 'tpl/cache/settings_inc.browser.tpl.php'; PK K~\���$Z Z settings-cache.tpl.phpnu �[��� <?php namespace LiteSpeed; defined('WPINC') || exit; ?> <h3 class="litespeed-title-short"> <?php echo __('Cache Control Settings', 'litespeed-cache'); ?> <?php Doc::learn_more('https://docs.litespeedtech.com/lscache/lscwp/cache/'); ?> </h3> <table class="wp-list-table striped litespeed-table"> <tbody> <tr> <th> <?php $id = Base::O_CACHE; ?> <?php $this->title($id); ?> </th> <td> <?php if ($this->_is_multisite) : ?> <?php $this->build_switch($id, array(__('OFF', 'litespeed-cache'), __('ON', 'litespeed-cache'), __('Use Network Admin Setting', 'litespeed-cache'))); ?> <?php else : ?> <?php $this->build_switch($id); ?> <?php endif; ?> <div class="litespeed-desc"> <?php echo sprintf( __('Please visit the <a %s>Information</a> page on how to test the cache.', 'litespeed-cache'), 'href="https://docs.litespeedtech.com/lscache/lscwp/installation/#testing" target="_blank"' ); ?> <strong><?php echo __('NOTICE', 'litespeed-cache'); ?>: </strong><?php echo __('When disabling the cache, all cached entries for this site will be purged.', 'litespeed-cache'); ?> <?php if ($this->_is_multisite) : ?> <br><?php echo __('The network admin setting can be overridden here.', 'litespeed-cache'); ?> <?php endif; ?> <?php if (!$this->conf(Base::O_CACHE) && $this->conf(Base::O_CDN_QUIC)) : ?> <br> <font class="litespeed-success"><?php echo __('With QUIC.cloud CDN enabled, you may still be seeing cache headers from your local server.', 'litespeed-cache'); ?></font> <?php endif; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_PRIV; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_switch($id); ?> <div class="litespeed-desc"> <?php echo sprintf(__('Privately cache frontend pages for logged-in users. (LSWS %s required)', 'litespeed-cache'), 'v5.2.1+'); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_COMMENTER; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_switch($id); ?> <div class="litespeed-desc"> <?php echo sprintf(__('Privately cache commenters that have pending comments. Disabling this option will serve non-cacheable pages to commenters. (LSWS %s required)', 'litespeed-cache'), 'v5.2.1+'); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_REST; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_switch($id); ?> <div class="litespeed-desc"> <?php echo __('Cache requests made by WordPress REST API calls.', 'litespeed-cache'); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_PAGE_LOGIN; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_switch($id); ?> <div class="litespeed-desc"> <?php echo __('Disabling this option may negatively affect performance.', 'litespeed-cache'); ?> </div> </td> </tr> <?php if (!$this->_is_multisite) : require LSCWP_DIR . 'tpl/cache/settings_inc.cache_resources.tpl.php'; require LSCWP_DIR . 'tpl/cache/settings_inc.cache_mobile.tpl.php'; endif; ?> <tr> <th> <?php $id = Base::O_CACHE_PRIV_URI; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_textarea($id); ?> <div class="litespeed-desc"> <?php echo __('URI Paths containing these strings will NOT be cached as public.', 'litespeed-cache'); ?> <?php $this->_uri_usage_example(); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_FORCE_URI; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_textarea($id); ?> <div class="litespeed-desc"> <?php echo __('Paths containing these strings will be cached regardless of no-cacheable settings.', 'litespeed-cache'); ?> <?php $this->_uri_usage_example(); ?> <br /><?php echo __('To define a custom TTL for a URI, add a space followed by the TTL value to the end of the URI.', 'litespeed-cache'); ?> <?php echo sprintf(__('For example, %1$s defines a TTL of %2$s seconds for %3$s.', 'litespeed-cache'), '<code>/mypath/mypage 300</code>', 300, '<code>/mypath/mypage</code>'); ?> <?php Doc::one_per_line(); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_CACHE_FORCE_PUB_URI; ?> <?php $this->title($id); ?> </th> <td> <?php $this->build_textarea($id); ?> <div class="litespeed-desc"> <?php echo __('Paths containing these strings will be forced to public cached regardless of no-cacheable settings.', 'litespeed-cache'); ?> <?php $this->_uri_usage_example(); ?> <br /><?php echo __('To define a custom TTL for a URI, add a space followed by the TTL value to the end of the URI.', 'litespeed-cache'); ?> <?php echo sprintf(__('For example, %1$s defines a TTL of %2$s seconds for %3$s.', 'litespeed-cache'), '<code>/mypath/mypage 300</code>', 300, '<code>/mypath/mypage</code>'); ?> <?php Doc::one_per_line(); ?> </div> </td> </tr> <?php if (!$this->_is_multisite) : require LSCWP_DIR . 'tpl/cache/settings_inc.cache_dropquery.tpl.php'; endif; ?> </tbody> </table>PK L~\8p�� settings_inc.object.tpl.phpnu �[��� <?php namespace LiteSpeed ; defined( 'WPINC' ) || exit ; $lang_enabled = '<font class="litespeed-success">' . __( 'Enabled', 'litespeed-cache' ) . '</font>' ; $lang_disabled = '<font class="litespeed-warning">' . __( 'Disabled', 'litespeed-cache' ) . '</font>' ; $mem_enabled = class_exists( 'Memcached' ) ? $lang_enabled : $lang_disabled ; $redis_enabled = class_exists( 'Redis' ) ? $lang_enabled : $lang_disabled ; $mem_conn = $this->cls( 'Object_Cache' )->test_connection(); if ( $mem_conn === null ) { $mem_conn_desc = '<font class="litespeed-desc">' . __( 'Not Available', 'litespeed-cache' ) . '</font>' ; } elseif ( $mem_conn ) { $mem_conn_desc = '<font class="litespeed-success">' . __( 'Passed', 'litespeed-cache' ) . '</font>' ; } else { $severity = $this->conf( Base::O_OBJECT, true ) ? "danger" : "warning"; $mem_conn_desc = '<font class="litespeed-' . $severity . '">' . __( 'Failed', 'litespeed-cache' ) . '</font>' ; } ?> <h3 class="litespeed-title-short"> <?php echo __( 'Object Cache Settings', 'litespeed-cache' ) ; ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#object-tab' ); ?> </h3> <table class="wp-list-table striped litespeed-table"><tbody> <tr> <th> <?php $id = Base::O_OBJECT ; ?> <?php $this->title( $id ) ; ?> </th> <td> <?php $this->build_switch( $id ) ; ?> <div class="litespeed-desc"> <?php echo __( 'Use external object cache functionality.', 'litespeed-cache' ) ; ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/admin/#memcached-lsmcd-and-redis-object-cache-support-in-lscwp' ); ?> </div> <div class="litespeed-block"> <div class='litespeed-col-auto'> <h4><?php echo __( 'Status', 'litespeed-cache' ) ; ?></h4> </div> <div class='litespeed-col-auto'> <?php echo sprintf( __( '%s Extension', 'litespeed-cache' ), 'Memcached' ) ; ?>: <?php echo $mem_enabled ; ?><br /> <?php echo sprintf( __( '%s Extension', 'litespeed-cache' ), 'Redis' ) ; ?>: <?php echo $redis_enabled ; ?><br /> <?php echo __( 'Connection Test', 'litespeed-cache' ) ; ?>: <?php echo $mem_conn_desc ; ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/admin/#how-to-debug' ); ?> </div> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_KIND ; ?> <?php $this->title( $id ) ; ?> </th> <td> <?php $this->build_switch( $id, array( 'Memcached', 'Redis' ) ); ?> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_HOST; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id ); ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'Your %s Hostname or IP address.', 'litespeed-cache' ), 'Memcached/<a href="https://docs.litespeedtech.com/products/lsmcd/" target="_blank">LSMCD</a>/Redis' ) ; ?> <br /><?php echo sprintf( __( 'If you are using a %1$s socket, %2$s should be set to %3$s', 'litespeed-cache' ), 'UNIX', Lang::title( $id ), '<code>/path/to/memcached.sock</code>' ); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_PORT; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id, 'litespeed-input-short2' ) ; ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'Default port for %1$s is %2$s.', 'litespeed-cache' ), 'Memcached', '<code>11211</code>' ) ; ?> <?php echo sprintf( __( 'Default port for %1$s is %2$s.', 'litespeed-cache' ), 'Redis', '<code>6379</code>' ) ; ?> <br /><?php echo sprintf( __( 'If you are using a %1$s socket, %2$s should be set to %3$s', 'litespeed-cache' ), 'UNIX', Lang::title( $id ), '<code>0</code>' ); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_LIFE; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id, 'litespeed-input-short2' ) ; ?> <?php echo __( 'seconds', 'litespeed-cache' ) ; ?> <div class="litespeed-desc"> <?php echo __( 'Default TTL for cached objects.', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_USER; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id ); ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'Only available when %s is installed.', 'litespeed-cache' ), 'SASL' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_PSWD; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id ); ?> <div class="litespeed-desc"> <?php echo __( 'Specify the password used when connecting.', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_DB_ID; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id, 'litespeed-input-short' ); ?> <div class="litespeed-desc"> <?php echo __( 'Database to be used', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_GLOBAL_GROUPS; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_textarea( $id, 30 ) ; ?> <div class="litespeed-desc"> <?php echo __( 'Groups cached at the network level.', 'litespeed-cache' ) ; ?> <?php Doc::one_per_line() ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_NON_PERSISTENT_GROUPS; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_textarea( $id, 30 ) ; ?> <div class="litespeed-desc"> <?php Doc::one_per_line() ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_PERSISTENT; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_switch( $id ) ; ?> <div class="litespeed-desc"> <?php echo __( 'Use keep-alive connections to speed up cache operations.', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_ADMIN; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_switch( $id ) ; ?> <div class="litespeed-desc"> <?php echo __( 'Improve wp-admin speed through caching. (May encounter expired data)', 'litespeed-cache' ) ; ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_OBJECT_TRANSIENTS; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_switch( $id ) ; ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'Save transients in database when %1$s is %2$s.', 'litespeed-cache' ), '<code>' . Lang::title( Base::O_OBJECT_ADMIN ) . '</code>', '<code>' . __( 'OFF', 'litespeed-cache' ) . '</code>' ) ; ?> <br /> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#store-transients' ); ?> </div> </td> </tr> </tbody></table> PK M~\O#�i i settings-purge.tpl.phpnu �[��� <?php namespace LiteSpeed; defined( 'WPINC' ) || exit; ?> <h3 class="litespeed-title-short"> <?php echo __( 'Purge Settings', 'litespeed-cache' ); ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#purge-tab' ); ?> </h3> <?php $option_list = array( Base::O_PURGE_POST_ALL => __( 'All pages', 'litespeed-cache' ), Base::O_PURGE_POST_FRONTPAGE => __( 'Front page', 'litespeed-cache' ), Base::O_PURGE_POST_HOMEPAGE => __( 'Home page', 'litespeed-cache' ), Base::O_PURGE_POST_PAGES => __( 'Pages', 'litespeed-cache' ), Base::O_PURGE_POST_PAGES_WITH_RECENT_POSTS => __( 'All pages with Recent Posts Widget', 'litespeed-cache' ), Base::O_PURGE_POST_AUTHOR => __( 'Author archive', 'litespeed-cache' ), Base::O_PURGE_POST_POSTTYPE => __( 'Post type archive', 'litespeed-cache' ), Base::O_PURGE_POST_YEAR => __( 'Yearly archive', 'litespeed-cache' ), Base::O_PURGE_POST_MONTH => __( 'Monthly archive', 'litespeed-cache' ), Base::O_PURGE_POST_DATE => __( 'Daily archive', 'litespeed-cache' ), Base::O_PURGE_POST_TERM => __( 'Term archive (include category, tag, and tax)', 'litespeed-cache' ), ); // break line at these ids $break_arr = array( Base::O_PURGE_POST_PAGES, Base::O_PURGE_POST_PAGES_WITH_RECENT_POSTS, Base::O_PURGE_POST_POSTTYPE, Base::O_PURGE_POST_DATE, ); ?> <table class="wp-list-table striped litespeed-table"><tbody> <?php if ( ! $this->_is_multisite ) : ?> <?php require LSCWP_DIR . 'tpl/cache/settings_inc.purge_on_upgrade.tpl.php'; ?> <?php endif; ?> <tr> <th><?php echo __( 'Auto Purge Rules For Publish/Update', 'litespeed-cache' ); ?></th> <td> <div class="litespeed-callout notice notice-warning inline"> <h4><?php echo __( 'Note', 'litespeed-cache' ); ?></h4> <p> <?php echo __( 'Select "All" if there are dynamic widgets linked to posts on pages other than the front or home pages.', 'litespeed-cache' ); ?><br /> <?php echo __( 'Other checkboxes will be ignored.', 'litespeed-cache' ); ?><br /> <?php echo __( 'Select only the archive types that are currently used, the others can be left unchecked.', 'litespeed-cache' ); ?> </p> </div> <div class="litespeed-top20"> <div class="litespeed-tick-wrapper"> <?php foreach ( $option_list as $id => $title ) { $this->build_checkbox( $id, $title ); if ( in_array( $id, $break_arr ) ) { echo '</div><div class="litespeed-tick-wrapper litespeed-top10">'; } } ?> </div> </div> <div class="litespeed-desc"> <?php echo __( 'Select which pages will be automatically purged when posts are published/updated.', 'litespeed-cache' ); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_PURGE_STALE; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_switch( $id ); ?> <div class="litespeed-desc"> <?php echo __( 'If ON, the stale copy of a cached page will be shown to visitors until a new cache copy is available. Reduces the server load for following visits. If OFF, the page will be dynamically generated while visitors wait.', 'litespeed-cache' ); ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#serve-stale' ); ?> </div> <div class="litespeed-callout notice notice-warning inline"> <h4><?php echo __( 'Note', 'litespeed-cache' ); ?></h4> <p> <?php echo __( 'By design, this option may serve stale content. Do not enable this option, if that is not OK with you.', 'litespeed-cache' ); ?><br /> </p> </div> </td> </tr> <tr> <th> <?php $id = Base::O_PURGE_TIMED_URLS; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_textarea( $id, 80 ); ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'The URLs here (one per line) will be purged automatically at the time set in the option "%s".', 'litespeed-cache' ), __( 'Scheduled Purge Time', 'litespeed-cache' ) ); ?><br /> <?php echo sprintf( __( 'Both %1$s and %2$s are acceptable.', 'litespeed-cache' ), '<code>http://www.example.com/path/url.php</code>', '<code>/path/url.php</code>' ); ?> <?php Doc::one_per_line(); ?> </div> <div class="litespeed-desc"> <?php echo sprintf( __( 'Wildcard %1$s supported (match zero or more characters). For example, to match %2$s and %3$s, use %4$s.', 'litespeed-cache' ), '<code>*</code>', '<code>/path/u-1.html</code>', '<code>/path/u-2.html</code>', '<code>/path/u-*.html</code>' ); ?> </div> <div class="litespeed-callout notice notice-warning inline"> <h4><?php echo __( 'Note', 'litespeed-cache' ); ?></h4> <p> <?php echo __( 'For URLs with wildcards, there may be a delay in initiating scheduled purge.', 'litespeed-cache' ); ?><br /> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#scheduled-purge-urls' ); ?> </p> </div> </td> </tr> <tr> <th> <?php $id = Base::O_PURGE_TIMED_URLS_TIME; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_input( $id, null, null, 'time' ); ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'Specify the time to purge the "%s" list.', 'litespeed-cache' ), __( 'Scheduled Purge URLs', 'litespeed-cache' ) ); ?> <?php echo sprintf( __( 'Current server time is %s.', 'litespeed-cache' ), '<code>' . date( 'H:i:s', time() + LITESPEED_TIME_OFFSET ) . '</code>' ); ?> </div> </td> </tr> <tr> <th> <?php $id = Base::O_PURGE_HOOK_ALL; ?> <?php $this->title( $id ); ?> </th> <td> <div class="litespeed-textarea-recommended"> <div> <?php $this->build_textarea( $id, 50 ); ?> </div> <div> <?php $this->recommended( $id ); ?> </div> </div> <div class="litespeed-desc"> <?php echo __( 'A Purge All will be executed when WordPress runs these hooks.', 'litespeed-cache' ); ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#purge-all-hooks' ); ?> </div> </td> </tr> </tbody></table> PK N~\�� � $ settings_inc.cache_dropquery.tpl.phpnu �[��� <?php namespace LiteSpeed ; defined( 'WPINC' ) || exit ; ?> <tr> <th> <?php $id = Base::O_CACHE_DROP_QS; ?> <?php $this->title( $id ); ?> </th> <td> <?php $this->build_textarea( $id, 40 ); ?> <div class="litespeed-desc"> <?php echo sprintf( __( 'Ignore certain query strings when caching. (LSWS %s required)', 'litespeed-cache' ), 'v5.2.3+' ); ?> <?php echo sprintf( __( 'For example, to drop parameters beginning with %s, %s can be used here.', 'litespeed-cache' ), '<code>utm</code>', '<code>utm*</code>' ); ?> <?php Doc::learn_more( 'https://docs.litespeedtech.com/lscache/lscwp/cache/#drop-query-string' ); ?> <br /> <?php Doc::one_per_line(); ?> <br /><?php Doc::notice_htaccess() ; ?> </div> </td> </tr> PK O~\�A͔ &