ly anonymous visitors are served from the page cache; // the optimization pipeline (ob_start below) still runs for logged-in users, but // lwsop_add_to_cache() refuses to persist their responses. if (!is_user_logged_in() && !empty(glob($this->cache_directory))) { $user_id = 0; $extension = "html"; if (file_exists($this->cache_directory . "index_$user_id.html")) { header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($this->cache_directory . "index_$user_id.html")) . ' GMT', true, 200); $extension = "html"; } elseif (file_exists($this->cache_directory . "index_$user_id.xml")) { header('Content-type: text/xml'); $extension = "xml"; } elseif (file_exists($this->cache_directory . "index_$user_id.json")) { header('Content-type: application/json'); $extension = "json"; } $content = @file_get_contents($this->cache_directory . "index_$user_id.$extension"); if ($content) { header('Edge-Cache-Platform: lwsoptimize'); header('X-LWSOP-Cache: HIT'); if (class_exists('Lws\\Classes\\FileCache\\LwsOptimizeUsageStats')) { \Lws\Classes\FileCache\LwsOptimizeUsageStats::track('hits', strlen($content)); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $content is the full pre-rendered cached HTML/JSON page read back from disk; it IS the response body, escaping it would corrupt the page echo $content; exit; } } add_action('wp', array($this, "lwsop_detect_page_type")); add_action('get_footer', array($this, "lwsop_detect_page_type")); add_action('get_footer', function () { echo ""; }); if ($this->base->lwsop_check_option('webfont_optimize')['state'] == "true") { add_filter('style_loader_tag', [$this, 'lws_optimize_manage_frontend_webfont_optimize'], 10, 3); } if ($this->base->lwsop_check_option('deactivate_emoji')['state'] == "true") { add_filter('init', [$this, 'lws_optimize_manage_frontend_deactivate_emoji']); } if ($this->base->lwsop_check_option('eliminate_requests')['state'] == "true") { add_filter('style_loader_src', [$this, 'lws_optimize_manage_frontend_eliminate_requests']); add_filter('script_loader_src', [$this, 'lws_optimize_manage_frontend_eliminate_requests']); } ob_start(array($this, "callback")); } public function callback($buffer) { // Do NOT cache if the content is null if (empty($buffer)) { return $buffer; } // Get the Content-Type of the current page (xml, json, html) $this->lwsop_detect_page_content_type($buffer); // We need to wait until now to check if the page type is excluded as we have no way of knowing the type beforehand if ($this->lwsop_page_has_been_excluded($buffer)) { return $buffer; } // If not a 200, do NOT cache if ((function_exists("http_response_code") && http_response_code() !== 200)) { return $buffer; } // We cannot cache the error page, otherwise even once the error is resolved or the page created, it won't appear if ((function_exists("http_response_code") && (http_response_code() === 404 || http_response_code() !== 200)) || is_404() || preg_match("/\s*/i", $buffer)) { return $buffer; } // If the page is password protected, then do not cache if (preg_match("/action\=[\'\"].+postpass.*[\'\"]/", $buffer)) { return $buffer . ""; } // We cannot cache the login page for obvious reasons if ($GLOBALS["pagenow"] == "wp-login.php") { return $buffer . ""; } // // Do not cache the page if the DONOTCACHEPAGE is defined (can be defined by a few plugins, like Wordfence or iThemes) // if (defined('DONOTCACHEPAGE')) { // return $buffer . ""; // } if ((is_single() || is_page()) && preg_match("/]+_wpcf7_captcha[^\>]+>/i", $buffer)) { return $buffer . ""; } // Check a list of pages that cannot be cached (core WP, specific plugin pages like WooCommerce, ...) as it would break or hinder the website if ($this->lwsop_page_to_ignore($buffer)) { return $buffer; } // Do not cache the page if it is a page preview (from Gutenberg, for example) if (is_preview()) { return $buffer . ""; } // Do not cache the page if it is a page preview (from Gutenberg, for example) (Alt version) if (isset($_GET["preview"])) { return $buffer . ""; } // If the current page is HTML but does not have the correct structure, do not cache it. if ($this->content_type === "html" && !(preg_match('/<\s*html[^\>]*>/si', $buffer) && preg_match('/<\s*body[^\>]*>/si', $buffer) && preg_match('/<\/body\s*>/si', $buffer))) { return $buffer; } // If the page is a redirection (temp/permanent), do not cache the page. if (http_response_code() == 301 || http_response_code() == 302) { return $buffer; } $modified = $buffer; $cached_elements = [ 'css' => ['file' => 0, 'size' => 0], 'js' => ['file' => 0, 'size' => 0], 'desktop' => ['file' => 0, 'size' => 0], 'mobile' => ['file' => 0, 'size' => 0] ]; $original_data_array = get_option("lws_optimize_original_image", []); $media_data = $original_data_array['auto_update']['original_media'] ?? []; $media_to_update = []; if (!empty($media_data)) { foreach ($media_data as $media) { if (file_exists($media['path'])) { $media_to_update[] = [ 'original' => $media['original_url'], 'new' => $media['url'] ]; } } } // TODO : Unused CSS : removed before minifying/combining CSS if ($this->base->lwsop_check_option('preload_css')['state'] == "true") { $preload = $this->base->lwsop_check_option('preload_css')['data']['links'] ?? []; $lwsOptimizeCssManager = new LwsOptimizeCSSManager($modified, $preload, []); $modified = $lwsOptimizeCssManager->preload_css(); } if ($this->base->lwsop_check_option('preload_font')['state'] == "true") { $preload = $this->base->lwsop_check_option('preload_font')['data']['links'] ?? []; $lwsOptimizeCssManager = new LwsOptimizeCSSManager($modified, [], $preload); $modified = $lwsOptimizeCssManager->preload_fonts(); } if ($this->base->lwsop_check_option('remove_css')['state'] == "true") { $lwsOptimizeUnusedCssManager = new LwsOptimizeUnusedCSS($modified); $modified = $lwsOptimizeUnusedCssManager->applyCleanedCSS(); } // We can put the current page to cache. We now apply the chosen options to the file (minify CSS/JS, combine CSS/JS, ...) if ($this->base->lwsop_check_option('combine_css')['state'] == "true") { if ($this->base->lwsop_check_option('minify_css')['state'] == "true") { $lwsOptimizeCssManager = new LwsOptimizeCSSManager($modified, [], [], $media_to_update, true); $data = $lwsOptimizeCssManager->combine_css_update(true); } else { $lwsOptimizeCssManager = new LwsOptimizeCSSManager($modified, [], [], $media_to_update); $data = $lwsOptimizeCssManager->combine_css_update(); } $modified = $data['html']; $cached_elements['css']['file'] += $data['files']['file']; $cached_elements['css']['size'] += $data['files']['size']; } elseif ($this->base->lwsop_check_option('minify_css')['state'] == "true") { if ($this->base->lwsop_check_option('cloudflare')['state'] == "false") { $lwsOptimizeCssManager = new LwsOptimizeCSSManager($modified, [], [], $media_to_update); $data = $lwsOptimizeCssManager->minify_css(); $modified = $data['html']; $cached_elements['css']['file'] += $data['files']['file']; $cached_elements['css']['size'] += $data['files']['size']; } } if ($this->base->lwsop_check_option('combine_js')['state'] == "true") { if ($this->base->lwsop_check_option('minify_js')['state'] == "true") { $lwsOptimizeJsManager = new LwsOptimizeJSManager($modified, true); $data = $lwsOptimizeJsManager->combine_js_update(); } else { $lwsOptimizeJsManager = new LwsOptimizeJSManager($modified); $data = $lwsOptimizeJsManager->combine_js_update(); } $modified = $data['html']; $cached_elements['js']['file'] += $data['files']['file']; $cached_elements['js']['size'] += $data['files']['size']; } elseif ($this->base->lwsop_check_option('minify_js')['state'] == "true") { if ($this->base->lwsop_check_option('cloudflare')['state'] == "false") { $lwsOptimizeJsManager = new LwsOptimizeJSManager($modified); $data = $lwsOptimizeJsManager->minify_js(); $modified = $data['html']; $cached_elements['js']['file'] += $data['files']['file']; $cached_elements['js']['size'] += $data['files']['size']; } } if ($this->base->lwsop_check_option('critical_css')['state'] == "true") { $lwsOptimizeCriticalCssManager = new LwsOptimizeCriticalCSS($modified); $modified = $lwsOptimizeCriticalCssManager->applyCriticalCSS(); } if ($this->base->lwsop_check_option('defer_js')['state'] == "true") { $lwsOptimizeJsManager = new LwsOptimizeJSManager($modified); $data = $lwsOptimizeJsManager->defer_js(); $modified = $data['html']; } if ($this->base->lwsop_check_option('delay_js')['state'] == "true") { $lwsOptimizeJsManager = new LwsOptimizeJSManager($modified); $data = $lwsOptimizeJsManager->delay_js_execution(); $modified = $data['html']; } // Finally add the cache file if ($this->content_type === "html") { // Add a filter for users to modify the cache file before it is saved $tmp_content = (string) apply_filters('lwsop_buffer_callback_filter', $modified, "cache", $this->cache_directory); if (!$tmp_content) { return $modified; } else { $modified = $tmp_content; } if ($this->base->lwsop_check_option('minify_html')['state'] == "true") { $exclusions = $this->base->lwsop_check_option('minify_html'); $exclusions = $exclusions['data']['exclusions'] ?? null; if ($exclusions === null || empty($exclusions)) { // Use voku/html-min to minify the HTML $htmlMin = new \voku\helper\HtmlMin(); // Configure advanced minification options $htmlMin->doOptimizeViaHtmlDomParser(true); // Enable HTML DOM optimization $htmlMin->doRemoveComments(true); // Remove HTML comments $htmlMin->doRemoveWhitespaceAroundTags(true); // Remove whitespace around tags $htmlMin->doRemoveOmittedQuotes(false); // Don't remove quotes to preserve attribute values $htmlMin->doRemoveOmittedHtmlTags(false); // Don't remove optional HTML tags $htmlMin->doSumUpWhitespace(true); // Combine multiple whitespace $htmlMin->doRemoveHttpPrefixFromAttributes(true); // Remove http: when possible $modified = $htmlMin->minify($modified); } else { $no_minify = false; $request_uri = isset($_SERVER["REQUEST_URI"]) ? sanitize_text_field(wp_unslash($_SERVER["REQUEST_URI"])) : ''; foreach ($exclusions as $exclusion) { if (preg_match("~$exclusion~", $request_uri)) { $no_minify = true; } } if (!$no_minify) { $htmlMin = new \voku\helper\HtmlMin(); // Configure advanced minification options $htmlMin->doOptimizeViaHtmlDomParser(true); // Enable HTML DOM optimization $htmlMin->doRemoveComments(true); // Remove HTML comments $htmlMin->doRemoveWhitespaceAroundTags(true); // Remove whitespace around tags $htmlMin->doRemoveOmittedQuotes(false); // Don't remove quotes to preserve attribute values $htmlMin->doRemoveOmittedHtmlTags(false); // Don't remove optional HTML tags $htmlMin->doSumUpWhitespace(true); // Combine multiple whitespace $htmlMin->doRemoveWhitespaceAroundTags(true); // Remove whitespace around tags $htmlMin->doRemoveHttpPrefixFromAttributes(true); // Remove http: when possible $modified = $htmlMin->minify($modified); } } } $is_mobile = false; if ($this->_lwsop_is_mobile()) { $is_mobile = true; } else { $is_mobile = false; } $this->lwsop_add_to_cache($modified, $cached_elements, $is_mobile); } elseif ($this->content_type === "xml") { if (preg_match("/<\/link>/", $buffer) && preg_match("/\/feed$/", isset($_SERVER["REQUEST_URI"]) ? sanitize_text_field(wp_unslash($_SERVER["REQUEST_URI"])) : '')) { return $buffer . time(); } $this->lwsop_add_to_cache($buffer, $cached_elements, false); } elseif ($this->content_type === "json") { $this->lwsop_add_to_cache($buffer, $cached_elements, false); } if (!headers_sent() && class_exists('Lws\\Classes\\FileCache\\LwsOptimizeUsageStats')) { header('X-LWSOP-Cache: BYPASS'); } header ('Edge-Cache-Platform: lwsoptimize'); return $modified; } public function lwsop_add_to_cache($content, $cached, $mobile = false) { $this->lwsop_set_cachedir(); // SECURITY (CACHE-1): only persist responses for anonymous visitors. Caching an // authenticated response under a shared key leaked personalized content between // users; authenticated pages are never written to the file cache. if (is_user_logged_in()) { return; } if (!empty($content) && $this->cache_directory !== false) { $user_id = 0; $name = "index_$user_id."; // If the file is html/xml/json, add it to /wp-content/cache/ if ($content !== false && preg_match("/html|xml|json/i", $this->content_type)) { if (!is_dir($this->cache_directory)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir -- per-page-view cache write hot path; WP_Filesystem overhead/credential prompts are unacceptable here mkdir($this->cache_directory, 0755, true); } if (is_dir($this->cache_directory) && !file_exists($this->cache_directory . $name . $this->content_type)) { // CACHE-3: write atomically (tmp file + rename) so a concurrent request // — or the Apache static-serve path — can never read a half-written file. $this->base->lwsop_atomic_write($this->cache_directory . $name . $this->content_type, $content); // Pre-generate compressed siblings so lwsop_cache_serve.php (used when // the PHP intermediary option is on) can send Content-Encoding without // depending on Apache's mod_deflate/mod_brotli being loaded. if ($this->content_type === 'html') { $this->lwsop_write_compressed_variants($this->cache_directory . $name . $this->content_type, $content); } $cached['html']['file'] = 1; $cached['html']['size'] = filesize($this->cache_directory . $name . $this->content_type); $GLOBALS['lws_optimize']->lwsop_recalculate_stats("plus", $cached, $mobile); // Validate against the per-site secret so any client can't spoof the header. $preload_secret = get_option('lwsop_preload_secret', ''); $is_preload = $preload_secret !== '' && isset($_SERVER['HTTP_X_LWS_PRELOAD']) && hash_equals($preload_secret, sanitize_text_field(wp_unslash($_SERVER['HTTP_X_LWS_PRELOAD']))); if (!$is_preload && class_exists('Lws\\Classes\\FileCache\\LwsOptimizeUsageStats') && !headers_sent()) { header('X-LWSOP-Cache: MISS'); } if (!$is_preload && class_exists('Lws\\Classes\\FileCache\\LwsOptimizeUsageStats')) { \Lws\Classes\FileCache\LwsOptimizeUsageStats::track('misses'); } } } } } /** * Writes .gz/.br siblings next to a cached HTML file so the request never pays * compression cost — the shared-hosting Apache modules this used to depend on * (mod_deflate/mod_brotli) aren't guaranteed to be loaded on every vhost. */ private function lwsop_write_compressed_variants($path, $content) { if (function_exists('gzencode')) { $gzipped = @gzencode($content, 9); if ($gzipped !== false) { $this->base->lwsop_atomic_write($path . '.gz', $gzipped); } } if (function_exists('brotli_compress')) { $br = @brotli_compress($content); if ($br !== false && $br !== null) { $this->base->lwsop_atomic_write($path . '.br', $br); } } } public function lws_optimize_manage_frontend_preload_css($html) { if (is_admin()) { return $html; } $html = str_replace("rel='stylesheet'", "rel='preload' as='style' ", $html); return $html; } public function lws_optimize_manage_frontend_preload_js($tag, $handle, $src) { if (is_admin()) { return $tag; } if ($handle == "admin-bar" || str_contains($src, "jquery") || str_contains($handle, "jquery") || str_contains($handle, "wc")) { return $tag; } $optimize_options = get_option('lws_optimize_config_array', []); if (isset($optimize_options['preload_js']['exclusions'])) { foreach ((array)$optimize_options['preload_js']['exclusions'] as $exception) { if (preg_match("~$exception~", $src)) { return $tag; } } } $tag = str_replace('>', ' defer>', $tag); return $tag; } public function lws_optimize_manage_frontend_eliminate_requests($src) { if (is_admin()) { return $src; } if (strpos($src, '?ver=')) { $src = remove_query_arg('ver', $src); } if (strpos($src, '?v=')) { $src = remove_query_arg('v', $src); } return $src; } public function lws_optimize_manage_frontend_webfont_optimize($html, $handle, $href) { if (is_admin()) { return $html; } if (!str_contains($handle, "fonts") && !str_contains($href, "fonts")) { return $html; } return ""; } public function lws_optimize_manage_frontend_deactivate_emoji() { // Disable WordPress emoji support remove_action('wp_head', 'print_emoji_detection_script', 7); remove_action('wp_print_styles', 'print_emoji_styles'); remove_action('admin_print_scripts', 'print_emoji_detection_script'); remove_action('admin_print_styles', 'print_emoji_styles'); remove_filter('the_content_feed', 'wp_staticize_emoji'); remove_filter('comment_text_rss', 'wp_staticize_emoji'); remove_filter('wp_mail', 'wp_staticize_emoji_for_email'); add_filter('wp_resource_hints', function ($urls, $relation_type) { if ('dns-prefetch' == $relation_type) { $urls = array_diff($urls, array(apply_filters('emoji_svg_url', 'https://s.w.org/images/core/emoji/2/svg/'))); } return $urls; }, 10, 2); // Disable TinyMCE emoji script add_filter('tiny_mce_plugins', function ($plugins) { return is_array($plugins) ? array_diff($plugins, array('wpemoji')) : array(); }); } public function lwsop_detect_page_type() { $request_uri = isset($_SERVER["REQUEST_URI"]) ? sanitize_text_field(wp_unslash($_SERVER["REQUEST_URI"])) : ''; if (preg_match("/\?/", $request_uri) || preg_match("/^\/wp-json/", $request_uri)) { return true; } if (is_front_page()) { $this->page_type = "homepage"; } elseif (is_category()) { $this->page_type = "category"; } elseif (is_tag()) { $this->page_type = "tag"; } elseif (is_tax()) { $this->page_type = "tax"; } elseif (is_author()) { $this->page_type = "author"; } elseif (is_search()) { $this->page_type = "search"; } elseif (is_single()) { $this->page_type = "post"; } elseif (is_page()) { $this->page_type = "page"; } elseif (is_attachment()) { $this->page_type = "attachment"; } elseif (is_archive()) { $this->page_type = "archive"; } } public function lwsop_detect_page_content_type() { $content_type = false; if (function_exists("headers_list")) { $headers = headers_list(); foreach ($headers as $header) { if (preg_match("/Content-Type\:/i", $header)) { $content_type = preg_replace("/Content-Type\:\s(.+)/i", "$1", $header); } } } if (preg_match("/xml/i", $content_type)) { $this->content_type = "xml"; } elseif (preg_match("/json/i", $content_type)) { $this->content_type = "json"; } else { $this->content_type = "html"; } } /** * Exclude from the cache all pages containing user-chosen cookies */ public function lwsop_page_has_excluded_cookies() { $optimize_options = get_option('lws_optimize_config_array', []); if (!isset($optimize_options['filebased_cache']['exclusions_cookies'])) { return false; } $excluded_cookies = $optimize_options['filebased_cache']['exclusions_cookies']; foreach ($excluded_cookies as $cookie) { foreach ($_COOKIE as $key => $value) { // Convert wildcard pattern to regex pattern and check if cookie name matches $pattern = preg_replace('/(?page_type) { return true; } } $pattern = preg_replace('/(? array('srfm_submit'), ); } private function lwsop_page_has_uncacheable_form($buffer) { if (empty($buffer)) { return false; } foreach ($this->lwsop_form_plugins_with_cache_nonce_issue() as $plugin_file => $needles) { if (!$GLOBALS['lws_optimize']->lwsop_plugin_active($plugin_file)) { continue; } foreach ($needles as $needle) { if (strpos($buffer, $needle) !== false) { return true; } } } return false; } public function lwsop_page_to_ignore($buffer = null) { if ($this->lwsop_page_has_uncacheable_form($buffer)) { return true; } $ignored = array( "\/wp\-comments\-post\.php", "\/wp\-login\.php", "\/robots\.txt", "\/wp\-cron\.php", "\/wp\-content", "\/wp\-admin", "\/wp\-includes", "\/index\.php", "\/xmlrpc\.php", "\/wp\-api\/", "leaflet\-geojson\.php", "\/clientarea\.php" ); if ($GLOBALS['lws_optimize']->lwsop_plugin_active('woocommerce/woocommerce.php') && $this->page_type != "homepage") { global $post; if (isset($post->ID) && $post->ID && function_exists("wc_get_page_id")) { $woocommerce_ids = array(); array_push($woocommerce_ids, \wc_get_page_id('cart'), \wc_get_page_id('checkout'), \wc_get_page_id('receipt'), \wc_get_page_id('confirmation'), \wc_get_page_id('myaccount'), \wc_get_page_id('product'), \wc_get_page_id('product-category')); if (in_array($post->ID, $woocommerce_ids)) { return true; } } array_push($ignored, "\/cart\/?$", "\/checkout", "\/receipt", "\/confirmation", "\/wc-api\/"); } if ($GLOBALS['lws_optimize']->lwsop_plugin_active('wp-easycart/wpeasycart.php')) { array_push($ignored, "\/cart"); } if ($GLOBALS['lws_optimize']->lwsop_plugin_active('easy-digital-downloads/easy-digital-downloads.php')) { array_push($ignored, "\/cart", "\/checkout"); } if (preg_match("/" . implode("|", $ignored) . "/i", isset($_SERVER["REQUEST_URI"]) ? sanitize_text_field(wp_unslash($_SERVER["REQUEST_URI"])) : '')) { return true; } return false; } /** * Check if the cache needs to be created for this URL. As a general rule, we do not cache pages with errors, bad URLs or redirections * as it serves no purposes to cache bad data. Unless specifically activated, no cache is made for admins and connected users. * Finally, if the user excluded the page, we do not cache it. Some checks are from WPFastestCache. */ public function lwsop_check_need_cache($uri = false) { if (!$uri) { $uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; } else { $uri = esc_url($uri); } // If URL has parameter do_not_cache_lwsoptimize, do not cache the page. if (isset($_GET['do_not_cache_lwsoptimize'])) { return false; } // var_dump($this->base->lwsop_check_option('cache_logged_user')['state']); // First check if the user is connected ; There is no point in doing checks even though the user is connected if ((is_user_logged_in() && $this->base->lwsop_check_option('cache_logged_user')['state'] == "true") || is_user_admin()) { return false; } // The user may choose to exclude some pages from the cache. We need to check that soon to reduce potentially useless checks if ($this->lwsop_page_has_been_excluded()) { return false; } // If the page has excluded cookies, do not cache if ($this->lwsop_page_has_excluded_cookies()) { return false; } // To prevent issues with requests and their data, no cache when sending POST requests if (isset($_SERVER['REQUEST_METHOD']) && sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) !== "GET") { return false; } // To prevent issues with requests and their data, no cache when sending POST requests if (isset($_SERVER['REQUEST_METHOD']) && sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) == "POST") { return false; } // If the request is HEAD, then do not cache if (isset($_SERVER['REQUEST_METHOD']) && sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) === 'HEAD') { return false; } // If there is no User Agent defined, do not cache ; It may also have been a request from a CDM, which we do not cache if (empty($_SERVER['HTTP_USER_AGENT'])) { return false; } // Do not put into cache if user deactivated cache on mobile devices if ($this->base->lwsop_check_option('cache_mobile_user')['state'] == "true" && $this->_lwsop_is_mobile()) { return false; } $http_user_agent = sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])); // Do not cache the page if the UserAgent is not from a real user (non exhaustive list) if ( preg_match("/(googlebot|bingbot|yandexbot|slurp|spider|robot|bot.html|bot.htm|facebookbot|facebookexternalhit|twitterbot|storebot|microsoftpreview|ahrefsbot|semrushbot|siteauditbot|splitsignalbot)/", $http_user_agent) ) { return false; } // Do not cache pages if it comes from PentHouse if (strpos(strtolower($http_user_agent), 'penthouse') !== false) { return false; } // If the page has Yandex CID or GoogleAnalytics parameters, no cache #WPFC if (preg_match("/y(ad|s)?clid\=/i", urldecode($uri))) { return false; } if (preg_match("/utm_(source|medium|campaign|content|term)/i", urldecode($uri))) { return false; } // Do not cache sitemap pages if (preg_match("/(wp-sitemap|sitemap\.xml)/i", urldecode($uri))) { return false; } // Do not cache wp-json pages if (preg_match("/(wp-json)/i", urldecode($uri))) { return false; } // Get the COOKIES if set and loop through them to check for specific cookies if (isset($_COOKIE)) { foreach ($_COOKIE as $key => $cookie) { // We could use WP functions to check if a comment has been sent, but it is faster to check the cookie // + it can be done with the next check if (is_string($cookie) && preg_match("/comment_author_/i", $cookie)) { return false; } // If WPTouch Pro is active and current mode is "desktop", does not cache if the user is on mobile #WPFC if ($this->_lwsop_is_mobile() && $key == "wptouch-pro-view" && $cookie == "desktop") { return false; } } } // If the request end with //, do not cache #WPFC if (isset($uri) && preg_match("/(\/){2}$/", $uri)) { return false; } // Do not cache if the permalink does not match the URL #WPFC if (isset($uri) && preg_match("/[^\/]+\/$/", $uri) && !preg_match("/\/$/", get_option('permalink_structure'))) { return false; } // No cache if the www. is inconsistent #WPFC $http_host = isset($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : ''; if ( $http_host !== '' && ( (preg_match("/www\./i", get_option("home")) && !preg_match("/www\./i", $http_host)) || (!preg_match("/www\./i", get_option("home")) && preg_match("/www\./i", $http_host)) ) ) { return false; } // Do not cache if SSL parameters do not match // In case a plugin doing HTTPS redirection is active, proceed with the caching (this part if from #WPFC) if(preg_match("/^https/i", get_option("home")) && !is_ssl()){ return false; } if(!preg_match("/^https/i", get_option("home")) && is_ssl()) { //must be normal connection if ($GLOBALS['lws_optimize']->lwsop_plugin_active('really-simple-ssl/rlrsssl-really-simple-ssl.php') || $GLOBALS['lws_optimize']->lwsop_plugin_active('really-simple-ssl-on-specific-pages/really-simple-ssl-on-specific-pages.php') || $GLOBALS['lws_optimize']->lwsop_plugin_active('ssl-insecure-content-fixer/ssl-insecure-content-fixer.php') || $GLOBALS['lws_optimize']->lwsop_plugin_active('https-redirection/https-redirection.php') || $GLOBALS['lws_optimize']->lwsop_plugin_active('better-wp-security/better-wp-security.php')) { return false; } } return true; } /** * Return the PATH to the cachefile for the current URL * * Adapted from WPFastestCache, changes have been made to clean up the code a bit and update it * * @return string PATH to the cachefile. If it does not exist, */ public function lwsop_set_cachedir($uri = false, $mobile = false) { // No cache if deactivated if (get_option('lws_optimize_deactivate_temporarily')) { return false; } if (!$uri) { $uri = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; } else { $uri = esc_url($uri); } $parsed = wp_parse_url($uri); $parsed_full = wp_parse_url($uri, PHP_URL_PATH); $query = $parsed['query'] ?? ''; parse_str($query, $params); unset($params['nocache']); $string = http_build_query($params); // If the dynamic URL option is not activated, do not cache the page if it has parameters if ($this->base->lwsop_check_option('no_parameters')['state'] == "false") { if (isset($string) && !empty($string)) { $this->cache_directory = false; return $this->cache_directory; } } if (!empty($string)) { $uri = "$parsed_full?$string"; } else { $uri = $parsed_full; } $parsed = wp_parse_url($uri); $parsed_full = wp_parse_url($uri, PHP_URL_PATH); $query = $parsed['query'] ?? ''; $uri = preg_replace("/^(http|https):\/\//sx", "", $uri); // By default, "cache"; $dir = "cache"; // If the user is on mobile and the site has mobile cache, then "cache_mobile" if ($this->_lwsop_is_mobile() || $mobile) { $dir = "cache-mobile"; } if ($GLOBALS['lws_optimize']->lwsop_plugin_active('gtranslate/gtranslate.php')) { // SECURITY: the language comes from an untrusted request header; sanitize it to // a bare filename token so it can never influence the cache directory path. $gt_lang = isset($_SERVER["HTTP_X_GT_LANG"]) ? sanitize_file_name(wp_unslash($_SERVER["HTTP_X_GT_LANG"])) : ''; if ($gt_lang !== '') { $this->cache_directory = $GLOBALS['lws_optimize']->lwsop_get_content_directory("$dir/{$gt_lang}/"); } else { $this->cache_directory = $GLOBALS['lws_optimize']->lwsop_get_content_directory("$dir/"); } } else { $this->cache_directory = $GLOBALS['lws_optimize']->lwsop_get_content_directory("$dir/"); } $this->cache_directory .= $uri; $this->cache_directory = rtrim(rtrim($this->cache_directory), "\/") . "/" ?? ""; // Remove the query parameters from the URL if it has any ; Only if the parameters are from GoogleAnalytics, Google Click Identifier, Yandex, Facebook #WPFC if ((preg_match("/gclid\=/i", $this->cache_directory) || preg_match("/y(ad|s)?clid\=/i", $this->cache_directory) || preg_match("/fbclid\=/i", $this->cache_directory) || preg_match("/utm_(source|medium|campaign|content|term)/i", $this->cache_directory)) && strlen($uri) > 1) { $this->cache_directory = preg_replace("/\/*\?.+/", "", $this->cache_directory); $this->cache_directory = $this->cache_directory . "/"; } $this->cache_directory = urldecode($this->cache_directory); // Security if (preg_match("/\.{2,}/", $this->cache_directory)) { $this->cache_directory = false; return $this->cache_directory; } if (strlen($uri) > 1) { // for the sub-pages if (!preg_match("/\.(html|xml)/i", $uri)) { if ($this->base->lwsop_plugin_active("custom-permalinks/custom-permalinks.php") || preg_match("/\/$/", get_option('permalink_structure', ""))) { if (!preg_match("/\/$/", $uri)) { if (!empty($_SERVER["QUERY_STRING"])) { } elseif (preg_match("/y(ad|s)?clid\=/i", $this->cache_directory)) { } elseif (preg_match("/gclid\=/i", $this->cache_directory)) { } elseif (preg_match("/fbclid\=/i", $this->cache_directory)) { } elseif (preg_match("/utm_(source|medium|campaign|content|term)/i", $this->cache_directory)) { } else { $this->cache_directory = false; return $this->cache_directory; } } } } } if ($this->_lwsop_is_mobile() && $this->base->lwsop_check_option('cache_mobile_user')['state'] == "true") { $this->cache_directory = false; return $this->cache_directory; } return $this->cache_directory; } /** * Check whether the current device is mobile of desktop * A copy of wp_is_mobile() [wp-includes/vars.php] - Last Updated 6.4.0 * * @return bool true if is mobile, false otherwise */ private function _lwsop_is_mobile() { if (isset($_SERVER['HTTP_SEC_CH_UA_MOBILE'])) { // This is the `Sec-CH-UA-Mobile` user agent client hint HTTP request header. // See . return '?1' === sanitize_text_field(wp_unslash($_SERVER['HTTP_SEC_CH_UA_MOBILE'])); } elseif (empty($_SERVER['HTTP_USER_AGENT'])) { return false; } $mobile_user_agent = sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])); if ( str_contains($mobile_user_agent, 'Mobile') // Many mobile devices (all iPhone, iPad, etc.) || str_contains($mobile_user_agent, 'Android') || str_contains($mobile_user_agent, 'Silk/') || str_contains($mobile_user_agent, 'Kindle') || str_contains($mobile_user_agent, 'BlackBerry') || str_contains($mobile_user_agent, 'Opera Mini') || str_contains($mobile_user_agent, 'Opera Mobi') ) { return true; } else { return false; } } }