| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | |
| 3 | 3 | use BerqWP\BerqWP; |
| 4 | -use voku\helper\HtmlDomParser; | |
| 4 | +use BerqWP_Deps\voku\helper\HtmlDomParser; | |
| 5 | 5 | |
| 6 | 6 | if (!defined('ABSPATH')) |
| 7 | 7 | exit; |
| 8 | 8 | |
| @@ -82,9 +82,8 @@ | ||
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | function berqwp_activate_single_site() { |
| 85 | 85 | if (empty(berqwp_get_license_key())) { |
| 86 | - set_transient('bqwp_hide_feedback_notice', true, 60 * 60); | |
| 87 | 86 | set_transient('berqwp_redirect', true, 1); |
| 88 | 87 | } |
| 89 | 88 | update_option('berqwp_sync_addons', true); |
| 90 | 89 | do_action('berqwp_activate_plugin'); |
| @@ -225,8 +224,9 @@ | ||
| 225 | 224 | "/embed", |
| 226 | 225 | "/view-order/", |
| 227 | 226 | "/redirect/", |
| 228 | 227 | "/elementskit-content/", |
| 228 | + "/checkout/", | |
| 229 | 229 | ]; |
| 230 | 230 | |
| 231 | 231 | $exclude_items = apply_filters('berqwp_exclude_slug_match', $exclude_items); |
| 232 | 232 | |
| @@ -238,8 +238,52 @@ | ||
| 238 | 238 | |
| 239 | 239 | return false; |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | + | |
| 243 | +function berqwp_home_url() { | |
| 244 | + return untrailingslashit(apply_filters('berqwp_site_url', home_url())); | |
| 245 | +} | |
| 246 | + | |
| 247 | +function bwp_canonicalize_page_url($url) { | |
| 248 | + $permalink_structure = get_option('permalink_structure'); | |
| 249 | + | |
| 250 | + if (!$permalink_structure) { | |
| 251 | + return $url; | |
| 252 | + } | |
| 253 | + | |
| 254 | + $path = parse_url($url, PHP_URL_PATH) ?? '/'; | |
| 255 | + | |
| 256 | + if ($path === '/') { | |
| 257 | + return $url; | |
| 258 | + } | |
| 259 | + | |
| 260 | + $uses_trailing_slash = substr(rtrim($permalink_structure), -1) === '/'; | |
| 261 | + $has_trailing_slash = substr($path, -1) === '/'; | |
| 262 | + | |
| 263 | + if ($uses_trailing_slash && !$has_trailing_slash) { | |
| 264 | + return trailingslashit($url); | |
| 265 | + } | |
| 266 | + | |
| 267 | + if (!$uses_trailing_slash && $has_trailing_slash) { | |
| 268 | + return untrailingslashit($url); | |
| 269 | + } | |
| 270 | + | |
| 271 | + return $url; | |
| 272 | +} | |
| 273 | + | |
| 274 | +function bwp_sync_permalink_config() { | |
| 275 | + $permalink_structure = get_option('permalink_structure'); | |
| 276 | + $trailing_slash = empty($permalink_structure) ? null : (substr(rtrim($permalink_structure), -1) === '/'); | |
| 277 | + | |
| 278 | + $berqconfigs = berqConfigs::getInstance(); | |
| 279 | + $current = $berqconfigs->get_configs(); | |
| 280 | + | |
| 281 | + if ($current === false || !array_key_exists('permalink_trailing_slash', $current) || $current['permalink_trailing_slash'] !== $trailing_slash) { | |
| 282 | + $berqconfigs->update_configs(['permalink_trailing_slash' => $trailing_slash]); | |
| 283 | + } | |
| 284 | +} | |
| 285 | + | |
| 242 | 286 | function berqwp_get_page_params($page_url, $is_forced = false) |
| 243 | 287 | { |
| 244 | 288 | |
| 245 | 289 | if (empty($page_url)) { |
| @@ -262,8 +306,10 @@ | ||
| 262 | 306 | } elseif ($optimization_mode == 1) { |
| 263 | 307 | $optimization_mode = 'basic'; |
| 264 | 308 | } |
| 265 | 309 | |
| 310 | + $home_url = berqwp_home_url(); | |
| 311 | + | |
| 266 | 312 | // Data to send as POST parameters |
| 267 | 313 | $post_data = array( |
| 268 | 314 | 'site_id' => $berqwp_configs['site_id'], |
| 269 | 315 | 'license_key' => berqwp_get_license_key(), |
| @@ -268,13 +314,14 @@ | ||
| 268 | 314 | 'site_id' => $berqwp_configs['site_id'], |
| 269 | 315 | 'license_key' => berqwp_get_license_key(), |
| 270 | 316 | 'page_url' => $page_url, |
| 271 | 317 | 'page_slug' => $page_slug, |
| 272 | - 'site_url' => home_url(), | |
| 318 | + 'site_url' => $home_url, | |
| 273 | 319 | 'webp_max_width' => (int) get_option('berqwp_webp_max_width'), |
| 274 | 320 | 'webp_quality' => (int) get_option('berqwp_webp_quality'), |
| 275 | 321 | 'fluid_images' => get_option('berqwp_fluid_images'), |
| 276 | 322 | 'enable_critical_css' => get_option('berqwp_enable_critical_css'), |
| 323 | + 'enable_used_css' => get_option('berqwp_enable_used_css'), | |
| 277 | 324 | 'force_include_critical_css'=> get_option('berqwp_force_include_critical_css', []), |
| 278 | 325 | 'exclude_css' => get_option('berqwp_exclude_css', []), |
| 279 | 326 | 'exclude_js' => get_option('berqwp_exclude_js', []), |
| 280 | 327 | 'exclude_third_party_js' => get_option('berqwp_exclude_third_party_js', []), |
| @@ -490,9 +537,9 @@ | ||
| 490 | 537 | if (file_exists($cache_file)) { |
| 491 | 538 | $buffer = file_get_contents($cache_file); |
| 492 | 539 | |
| 493 | 540 | if (!empty($buffer)) { |
| 494 | - $html = berqwp_str_get_html($buffer); | |
| 541 | + $html = HtmlDomParser::str_get_html($buffer); | |
| 495 | 542 | |
| 496 | 543 | if ($html !== false) { |
| 497 | 544 | $style_tag = $html->find('style#berqwp-critical-css', 0); |
| 498 | 545 | |
| @@ -1301,9 +1348,9 @@ | ||
| 1301 | 1348 | |
| 1302 | 1349 | function bwp_sluguri_into_path($slug_uri) |
| 1303 | 1350 | { |
| 1304 | 1351 | $is_multisite = function_exists('is_multisite') && is_multisite(); |
| 1305 | - $home_path = parse_url(home_url(), PHP_URL_PATH); | |
| 1352 | + $home_path = parse_url(berqwp_home_url(), PHP_URL_PATH); | |
| 1306 | 1353 | |
| 1307 | 1354 | // if (berqwp_is_sub_dir_wp() && !$is_multisite) { |
| 1308 | 1355 | if (!$is_multisite && $home_path !== null) { |
| 1309 | 1356 | // Parse strings to extract paths |
| @@ -1324,9 +1371,9 @@ | ||
| 1324 | 1371 | { |
| 1325 | 1372 | $parsed_url = parse_url($url); |
| 1326 | 1373 | $path = isset($parsed_url['path']) ? $parsed_url['path'] : ''; |
| 1327 | 1374 | $query = isset($parsed_url['query']) ? $parsed_url['query'] : ''; |
| 1328 | - $homeurl = home_url(); | |
| 1375 | + $homeurl = berqwp_home_url(); | |
| 1329 | 1376 | |
| 1330 | 1377 | if (!empty($query)) { |
| 1331 | 1378 | $path = $path . '?' . $query; |
| 1332 | 1379 | } |
| @@ -1450,9 +1497,9 @@ | ||
| 1450 | 1497 | // Set the number of posts per batch to handle |
| 1451 | 1498 | $posts_per_page = 10000; // Adjust this based on server capacity |
| 1452 | 1499 | |
| 1453 | 1500 | // Get current page from query string (for pagination) |
| 1454 | - $paged = isset($_GET['paged']) ? intval($_GET['paged']) : 1; | |
| 1501 | + $paged = isset($_GET['paged']) ? intval($_GET['paged']) : 1; | |
| 1455 | 1502 | |
| 1456 | 1503 | // Build the query arguments with pagination |
| 1457 | 1504 | $args = array( |
| 1458 | 1505 | 'post_type' => $post_types, |
| @@ -1480,8 +1527,9 @@ | ||
| 1480 | 1527 | |
| 1481 | 1528 | $berqconfigs = berqConfigs::getInstance(); |
| 1482 | 1529 | $configs = $berqconfigs->get_configs(); |
| 1483 | 1530 | $post_params['cache_lifespan'] = $configs['cache_lifespan']; |
| 1531 | + $post_params['sandbox'] = get_option('berqwp_enable_sandbox'); | |
| 1484 | 1532 | |
| 1485 | 1533 | if ($query->have_posts()) { |
| 1486 | 1534 | $sitemap_urls = []; |
| 1487 | 1535 | |
| @@ -1504,8 +1552,24 @@ | ||
| 1504 | 1552 | $post_name = get_post_field( 'post_name', $post_id ); |
| 1505 | 1553 | $url = trailingslashit( home_url( '/' . $rewrite_map[ $post_type ] . '/' . $post_name ) ); |
| 1506 | 1554 | } |
| 1507 | 1555 | |
| 1556 | + // SEO Generator | |
| 1557 | + if (class_exists('NSG_Seo_Generator')) { | |
| 1558 | + $nsg = NSG_Seo_Generator::get_instance(); | |
| 1559 | + $slugs = $nsg->nsg_get_seo_page_slugs( $post_id ); | |
| 1560 | + | |
| 1561 | + if ( is_array( $slugs ) ) { | |
| 1562 | + foreach ( $slugs as $slug ) { | |
| 1563 | + $generated_url = trailingslashit( $url ) . $slug . '/'; | |
| 1564 | + | |
| 1565 | + if (bwp_can_optimize_page_url($generated_url)) { | |
| 1566 | + $sitemap_urls[] = $generated_url; | |
| 1567 | + } | |
| 1568 | + } | |
| 1569 | + } | |
| 1570 | + } | |
| 1571 | + | |
| 1508 | 1572 | $translation_urls = apply_filters('berqwp_page_translation_urls', [], $url); |
| 1509 | 1573 | |
| 1510 | 1574 | if (!bwp_can_optimize_page_url($url)) { |
| 1511 | 1575 | continue; |
| @@ -1623,21 +1687,21 @@ | ||
| 1623 | 1687 | |
| 1624 | 1688 | if (!empty($_GET['tab_id'])) { |
| 1625 | 1689 | if (sanitize_text_field($_GET['tab_id']) == $tab_id) { |
| 1626 | 1690 | // echo ' style="display:block" '; |
| 1627 | - echo ' style="visibility:visible;opacity:1;height:auto;" '; | |
| 1691 | + echo ' style="visibility:visible;opacity:1;height:auto;display:block;" '; | |
| 1628 | 1692 | } else { |
| 1629 | 1693 | // echo ' style="display:none" '; |
| 1630 | - echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;" '; | |
| 1694 | + echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;display:none;" '; | |
| 1631 | 1695 | } |
| 1632 | 1696 | } else { |
| 1633 | 1697 | |
| 1634 | 1698 | if ($tab_id == $default_tab) { |
| 1635 | 1699 | // echo ' style="display:block" '; |
| 1636 | - echo ' style="visibility:visible;opacity:1;height:auto;" '; | |
| 1700 | + echo ' style="visibility:visible;opacity:1;height:auto;display:block;" '; | |
| 1637 | 1701 | } else { |
| 1638 | 1702 | // echo ' style="display:none" '; |
| 1639 | - echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;" '; | |
| 1703 | + echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;display:none;" '; | |
| 1640 | 1704 | } |
| 1641 | 1705 | } |
| 1642 | 1706 | } |
| 1643 | 1707 | |
| @@ -1675,15 +1739,15 @@ | ||
| 1675 | 1739 | d="M6.43896 0H17.561C21.1172 0 24 2.88287 24 6.43903V17.561C24 21.1171 21.1172 24 17.561 24H6.43896C2.88281 24 0 21.1171 0 17.561V6.43903C0 2.88287 2.88281 0 6.43896 0ZM15.7888 4.09753L8.59961 12.7534H12.3517L7.02441 20.4878L16.3903 11.0222L12.7814 10.3799L15.7888 4.09753Z" |
| 1676 | 1740 | fill="#1f72ff" /> |
| 1677 | 1741 | </svg></div> |
| 1678 | 1742 | <div class="content"> |
| 1679 | - <div class="status-tag"><?php esc_html_e($status, 'searchpro'); ?></div> | |
| 1743 | + <div class="status-tag"><?php echo esc_html($status); ?></div> | |
| 1680 | 1744 | <?php if (!empty($title)) { ?> |
| 1681 | - <h5><?php echo wp_kses_post(__($title, 'searchpro')); ?></h5> | |
| 1745 | + <h5><?php echo wp_kses_post($title); ?></h5> | |
| 1682 | 1746 | <?php } ?> |
| 1683 | 1747 | |
| 1684 | 1748 | <?php if (!empty($message)) { ?> |
| 1685 | - <?php echo wp_kses_post(__($message, 'searchpro')); ?> | |
| 1749 | + <?php echo wp_kses_post($message); ?> | |
| 1686 | 1750 | <?php } ?> |
| 1687 | 1751 | |
| 1688 | 1752 | <?php if (!empty($btn) && is_array($btn)) { ?> |
| 1689 | 1753 | <div class="bwp-notice-btn"> |
| @@ -1707,9 +1771,9 @@ | ||
| 1707 | 1771 | ?> |
| 1708 | 1772 | <a target="<?php echo esc_attr($bwp_btn['target']) ?? ''; ?>" |
| 1709 | 1773 | href="<?php echo esc_attr($bwp_btn['href']) ?? ''; ?>" |
| 1710 | 1774 | class="bwp-btn <?php echo esc_attr($bwp_btn['classes']) ?? ''; ?>"> |
| 1711 | - <?php echo esc_html__($bwp_btn['text'], 'searchpro') ?? ''; ?> | |
| 1775 | + <?php echo esc_html($bwp_btn['text']); ?> | |
| 1712 | 1776 | </a> |
| 1713 | 1777 | <?php |
| 1714 | 1778 | } |
| 1715 | 1779 | ?> |
| @@ -1794,9 +1858,9 @@ | ||
| 1794 | 1858 | if (isset($_GET['berqwp_logs'])) { |
| 1795 | 1859 | |
| 1796 | 1860 | // Check if the current user is logged in and has admin privileges |
| 1797 | 1861 | if (!is_user_logged_in() || !current_user_can('administrator')) { |
| 1798 | - wp_die(__('You are not allowed to access this page.', 'berqwp')); | |
| 1862 | + wp_die(__('You are not allowed to access this page.', 'searchpro')); | |
| 1799 | 1863 | } |
| 1800 | 1864 | |
| 1801 | 1865 | // Define the path to the BerqWP logs file |
| 1802 | 1866 | $log_file_path = optifer_cache . '/logs/berqwp.log'; // Adjust path if needed |
| @@ -1864,8 +1928,16 @@ | ||
| 1864 | 1928 | if (!file_exists($cache_dir)) { |
| 1865 | 1929 | wp_mkdir_p($cache_dir); |
| 1866 | 1930 | } |
| 1867 | 1931 | |
| 1932 | + if (!function_exists('got_mod_rewrite')) { | |
| 1933 | + require_once ABSPATH . 'wp-admin/includes/misc.php'; | |
| 1934 | + } | |
| 1935 | + | |
| 1936 | + if (!got_mod_rewrite()) { | |
| 1937 | + return; | |
| 1938 | + } | |
| 1939 | + | |
| 1868 | 1940 | $rules = <<<HTACCESS |
| 1869 | 1941 | Order allow,deny |
| 1870 | 1942 | Deny from all |
| 1871 | 1943 | |
| @@ -1872,13 +1944,50 @@ | ||
| 1872 | 1944 | <FilesMatch "index\.html\.gz$"> |
| 1873 | 1945 | Order allow,deny |
| 1874 | 1946 | Allow from all |
| 1875 | 1947 | </FilesMatch> |
| 1948 | + | |
| 1949 | +# Block PHP execution and dot-files to prevent webshell deployment | |
| 1950 | +<FilesMatch "\.php\d*$|\.phtml$|\.phar$"> | |
| 1951 | + Order allow,deny | |
| 1952 | + Deny from all | |
| 1953 | +</FilesMatch> | |
| 1954 | +<FilesMatch "^\."> | |
| 1955 | + Order allow,deny | |
| 1956 | + Deny from all | |
| 1957 | +</FilesMatch> | |
| 1876 | 1958 | HTACCESS; |
| 1877 | 1959 | |
| 1878 | 1960 | file_put_contents($cache_dir . '.htaccess', $rules); |
| 1961 | + | |
| 1962 | + // Suppress directory listing | |
| 1963 | + $index_stub = $cache_dir . 'index.php'; | |
| 1964 | + if (!file_exists($index_stub)) { | |
| 1965 | + file_put_contents($index_stub, '<?php // Silence is golden'); | |
| 1966 | + } | |
| 1967 | + | |
| 1879 | 1968 | } |
| 1880 | 1969 | |
| 1970 | +function bwp_delete_php_files_in_cache() | |
| 1971 | +{ | |
| 1972 | + $cache_dir = optifer_cache; | |
| 1973 | + if (!is_dir($cache_dir)) { | |
| 1974 | + return; | |
| 1975 | + } | |
| 1976 | + | |
| 1977 | + $php_extensions = ['php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'phar']; | |
| 1978 | + | |
| 1979 | + $iterator = new RecursiveIteratorIterator( | |
| 1980 | + new RecursiveDirectoryIterator($cache_dir, RecursiveDirectoryIterator::SKIP_DOTS) | |
| 1981 | + ); | |
| 1982 | + | |
| 1983 | + foreach ($iterator as $file) { | |
| 1984 | + if ($file->isFile() && in_array(strtolower($file->getExtension()), $php_extensions, true)) { | |
| 1985 | + @unlink($file->getRealPath()); | |
| 1986 | + } | |
| 1987 | + } | |
| 1988 | +} | |
| 1989 | + | |
| 1881 | 1990 | function bwp_write_htaccess_rules($ignore_sandbox = false) |
| 1882 | 1991 | { |
| 1883 | 1992 | if (!got_mod_rewrite() || bwp_is_openlitespeed_server()) { |
| 1884 | 1993 | return; |
| @@ -1888,14 +1997,27 @@ | ||
| 1888 | 1997 | return; |
| 1889 | 1998 | } |
| 1890 | 1999 | |
| 1891 | 2000 | $htaccess = get_home_path() . '.htaccess'; |
| 1892 | - $rules = [ | |
| 2001 | + $cache_tag_host = parse_url(home_url(), PHP_URL_HOST); | |
| 2002 | + | |
| 2003 | + // Match the cache-serving RewriteCond to the site's actual permalink convention, | |
| 2004 | + // so caching works whether the site uses trailing slashes or not. | |
| 2005 | + $permalink_structure = get_option('permalink_structure'); | |
| 2006 | + $uses_trailing_slash = empty($permalink_structure) || substr(rtrim($permalink_structure), -1) === '/'; | |
| 2007 | + | |
| 2008 | + $slash_conds = $uses_trailing_slash | |
| 2009 | + ? [' RewriteCond %{REQUEST_URI} /$'] | |
| 2010 | + : [' RewriteCond %{REQUEST_URI} ^/$ [OR]', ' RewriteCond %{REQUEST_URI} !/$']; | |
| 2011 | + | |
| 2012 | + $rules = array_merge([ | |
| 1893 | 2013 | '<IfModule mod_rewrite.c>', |
| 1894 | 2014 | ' RewriteEngine On', |
| 1895 | 2015 | ' RewriteCond %{REQUEST_METHOD} !POST', |
| 1896 | 2016 | ' RewriteCond %{QUERY_STRING} ^$', |
| 1897 | 2017 | ' RewriteCond %{HTTP_COOKIE} !(wp\-postpass|wordpress_logged_in|comment_author|woocommerce_cart_hash|edd_items_in_cart) [NC]', |
| 2018 | + ' RewriteCond %{HTTP_USER_AGENT} !(Googlebot|Google-InspectionTool|Bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Sogou|Exabot|facebookexternalhit|Twitterbot|LinkedInBot|WhatsApp|TelegramBot|Applebot|AhrefsBot|SemrushBot|MJ12bot|DotBot|PetalBot|BLEXBot|archive\.org_bot|UptimeRobot|Pingdom|ChatGPT-User|GPTBot|ClaudeBot|Bytespider) [NC]', | |
| 2019 | + ], $slash_conds, [ | |
| 1898 | 2020 | ' RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/berqwp/html/%{HTTP_HOST}%{REQUEST_URI}/index.html.gz -f', |
| 1899 | 2021 | ' RewriteRule .* /wp-content/cache/berqwp/html/%{HTTP_HOST}%{REQUEST_URI}/index.html.gz [L]', |
| 1900 | 2022 | '</IfModule>', |
| 1901 | 2023 | '<IfModule mod_mime.c>', |
| @@ -1901,16 +2023,55 @@ | ||
| 1901 | 2023 | '<IfModule mod_mime.c>', |
| 1902 | 2024 | ' <FilesMatch "index\.html\.gz$">', |
| 1903 | 2025 | ' ForceType text/html', |
| 1904 | 2026 | ' AddEncoding gzip .gz', |
| 2027 | + ' AddDefaultCharset utf-8', | |
| 1905 | 2028 | ' </FilesMatch>', |
| 1906 | 2029 | '</IfModule>', |
| 1907 | 2030 | '<IfModule mod_headers.c>', |
| 1908 | 2031 | ' <FilesMatch "index\.html\.gz$">', |
| 2032 | + ' Header set X-BerqWP-Cache "HIT"', | |
| 1909 | 2033 | ' Header set X-Served "server"', |
| 2034 | + ' Header set Content-Encoding "gzip"', | |
| 2035 | + ' Header set Vary "Accept-Encoding, Cookie"', | |
| 2036 | + ' Header set CDN-Cache-Control "max-age=2592000"', | |
| 2037 | + ' Header set Cache-Control "public, max-age=600, s-maxage=2592000, stale-while-revalidate=86400"', | |
| 2038 | + ' Header set Cache-Tag "' . $cache_tag_host . '"', | |
| 2039 | + ' Header set X-Content-Type-Options "nosniff"', | |
| 1910 | 2040 | ' </FilesMatch>', |
| 1911 | 2041 | '</IfModule>', |
| 1912 | - ]; | |
| 2042 | + '<IfModule mod_expires.c>', | |
| 2043 | + ' ExpiresActive On', | |
| 2044 | + ' ExpiresByType text/css "access plus 1 year"', | |
| 2045 | + ' ExpiresByType application/javascript "access plus 1 year"', | |
| 2046 | + ' ExpiresByType text/javascript "access plus 1 year"', | |
| 2047 | + ' ExpiresByType image/jpeg "access plus 1 year"', | |
| 2048 | + ' ExpiresByType image/png "access plus 1 year"', | |
| 2049 | + ' ExpiresByType image/gif "access plus 1 year"', | |
| 2050 | + ' ExpiresByType image/webp "access plus 1 year"', | |
| 2051 | + ' ExpiresByType image/avif "access plus 1 year"', | |
| 2052 | + ' ExpiresByType image/svg+xml "access plus 1 year"', | |
| 2053 | + ' ExpiresByType image/x-icon "access plus 1 year"', | |
| 2054 | + ' ExpiresByType font/woff "access plus 1 year"', | |
| 2055 | + ' ExpiresByType font/woff2 "access plus 1 year"', | |
| 2056 | + ' ExpiresByType application/font-woff "access plus 1 year"', | |
| 2057 | + ' ExpiresByType application/font-woff2 "access plus 1 year"', | |
| 2058 | + ' ExpiresByType application/x-font-ttf "access plus 1 year"', | |
| 2059 | + ' ExpiresByType application/x-font-opentype "access plus 1 year"', | |
| 2060 | + '</IfModule>', | |
| 2061 | + '<IfModule mod_headers.c>', | |
| 2062 | + ' <FilesMatch "\.(css|js)$">', | |
| 2063 | + ' Header set Cache-Control "public, max-age=31536000, immutable"', | |
| 2064 | + ' </FilesMatch>', | |
| 2065 | + ' <FilesMatch "\.(jpg|jpeg|png|gif|webp|avif|svg|ico)$">', | |
| 2066 | + ' Header set Cache-Control "public, max-age=31536000, immutable"', | |
| 2067 | + ' </FilesMatch>', | |
| 2068 | + ' <FilesMatch "\.(woff|woff2|ttf|otf|eot)$">', | |
| 2069 | + ' Header set Cache-Control "public, max-age=31536000, immutable"', | |
| 2070 | + ' Header set Access-Control-Allow-Origin "*"', | |
| 2071 | + ' </FilesMatch>', | |
| 2072 | + '</IfModule>', | |
| 2073 | + ]); | |
| 1913 | 2074 | |
| 1914 | 2075 | // Must appear before the WordPress block so Apache processes it first |
| 1915 | 2076 | $marker = 'BerqWP Cache'; |
| 1916 | 2077 | $start = "# BEGIN $marker"; |
| @@ -2086,8 +2247,40 @@ | ||
| 2086 | 2247 | // Fallback: no <head> tag found, return unchanged |
| 2087 | 2248 | return $buffer; |
| 2088 | 2249 | } |
| 2089 | 2250 | |
| 2251 | +function berqwp_earlyHeadHtml($buffer, $htmlToInsert) | |
| 2252 | +{ | |
| 2253 | + // Locate <head> opening tag | |
| 2254 | + if (!preg_match('/<head(\s[^>]*)?>/i', $buffer, $headMatch, PREG_OFFSET_CAPTURE)) { | |
| 2255 | + return berqwp_prependHtmlToHead($buffer, $htmlToInsert); | |
| 2256 | + } | |
| 2257 | + | |
| 2258 | + $headStart = $headMatch[0][1] + strlen($headMatch[0][0]); | |
| 2259 | + | |
| 2260 | + // Bound the search to content inside <head>...</head> | |
| 2261 | + $headEndPos = stripos($buffer, '</head>', $headStart); | |
| 2262 | + if ($headEndPos === false) { | |
| 2263 | + return berqwp_prependHtmlToHead($buffer, $htmlToInsert); | |
| 2264 | + } | |
| 2265 | + | |
| 2266 | + $headContent = substr($buffer, $headStart, $headEndPos - $headStart); | |
| 2267 | + | |
| 2268 | + // Find first <script, <link, or <style in the head | |
| 2269 | + // if (preg_match('/<(script|link|style)[\s>\/]/i', $headContent, $tagMatch, PREG_OFFSET_CAPTURE)) { | |
| 2270 | + | |
| 2271 | + $regex = "/<(script|link[^>]+rel=['\"]+(modulepreload|stylesheet|preload)['\"]|style)[\s>\/]/i"; | |
| 2272 | + | |
| 2273 | + if (preg_match($regex, $headContent, $tagMatch, PREG_OFFSET_CAPTURE)) { | |
| 2274 | + $insertPos = $headStart + $tagMatch[0][1]; | |
| 2275 | + return substr_replace($buffer, $htmlToInsert . PHP_EOL, $insertPos, 0); | |
| 2276 | + } | |
| 2277 | + | |
| 2278 | + // Fallback: no matching tag in head | |
| 2279 | + return berqwp_prependHtmlToHead($buffer, $htmlToInsert); | |
| 2280 | +} | |
| 2281 | + | |
| 2282 | + | |
| 2090 | 2283 | function berqwp_setup_dropin() |
| 2091 | 2284 | { |
| 2092 | 2285 | if (defined('BERQWP_ADVANCED_CACHE_PATH')) { |
| 2093 | 2286 | $adv_cache_path = BERQWP_ADVANCED_CACHE_PATH; |
| @@ -2200,9 +2393,8 @@ | ||
| 2200 | 2393 | |
| 2201 | 2394 | function berqwp_validate_url_array($urls) |
| 2202 | 2395 | { |
| 2203 | 2396 | $home_host = parse_url(home_url(), PHP_URL_HOST); |
| 2204 | - $home_scheme = parse_url(home_url(), PHP_URL_SCHEME); | |
| 2205 | 2397 | |
| 2206 | 2398 | $urls = array_filter($urls, function ($url) use ($home_host) { |
| 2207 | 2399 | $url_host = parse_url($url, PHP_URL_HOST); |
| 2208 | 2400 | |
| @@ -2213,35 +2405,9 @@ | ||
| 2213 | 2405 | |
| 2214 | 2406 | return $url_host === $home_host; |
| 2215 | 2407 | }); |
| 2216 | 2408 | |
| 2217 | - $urls = array_map(function ($url) use ($home_scheme) { | |
| 2218 | - // Skip invalid URLs | |
| 2219 | - if (!is_string($url) || $url === '') { | |
| 2220 | - return $url; | |
| 2221 | - } | |
| 2222 | - | |
| 2223 | - $parts = parse_url($url); | |
| 2224 | - | |
| 2225 | - // Relative URL → leave as-is | |
| 2226 | - if (empty($parts['scheme'])) { | |
| 2227 | - return $url; | |
| 2228 | - } | |
| 2229 | - | |
| 2230 | - // Rebuild URL with home scheme | |
| 2231 | - $parts['scheme'] = $home_scheme; | |
| 2232 | - | |
| 2233 | - $new_url = $parts['scheme'] . '://'; | |
| 2234 | - $new_url .= $parts['host'] ?? ''; | |
| 2235 | - $new_url .= isset($parts['port']) ? ':' . $parts['port'] : ''; | |
| 2236 | - $new_url .= $parts['path'] ?? ''; | |
| 2237 | - $new_url .= isset($parts['query']) ? '?' . $parts['query'] : ''; | |
| 2238 | - $new_url .= isset($parts['fragment']) ? '#' . $parts['fragment'] : ''; | |
| 2239 | - | |
| 2240 | - return $new_url; | |
| 2241 | - }, $urls); | |
| 2242 | - | |
| 2243 | - return $urls; | |
| 2409 | + return array_values($urls); | |
| 2244 | 2410 | } |
| 2245 | 2411 | |
| 2246 | 2412 | function berqwp_render_toggle($name, $checked) { |
| 2247 | 2413 | ?> |
| @@ -2251,8 +2417,52 @@ | ||
| 2251 | 2417 | </label> |
| 2252 | 2418 | <?php |
| 2253 | 2419 | } |
| 2254 | 2420 | |
| 2421 | +function bwp_log_recently_optimized_page($page_url) | |
| 2422 | +{ | |
| 2423 | + if (empty($page_url)) return; | |
| 2424 | + | |
| 2425 | + // berqwp_stored_page_cache passes a slug/path, not a full URL — reconstruct it | |
| 2426 | + if (!str_starts_with($page_url, 'http')) { | |
| 2427 | + $page_url = home_url($page_url); | |
| 2428 | + } | |
| 2429 | + $page_url = urldecode($page_url); | |
| 2430 | + | |
| 2431 | + $log = json_decode(get_option('berqwp_recently_optimized', '[]'), true); | |
| 2432 | + if (!is_array($log)) $log = []; | |
| 2433 | + | |
| 2434 | + // Remove existing entry for this URL so re-caching moves it to the top | |
| 2435 | + $log = array_values(array_filter($log, fn($e) => $e['url'] !== $page_url)); | |
| 2436 | + | |
| 2437 | + array_unshift($log, [ | |
| 2438 | + 'url' => esc_url_raw($page_url), | |
| 2439 | + 'cached_at' => current_time('Y-m-d H:i:s'), | |
| 2440 | + ]); | |
| 2441 | + | |
| 2442 | + if (count($log) > 200) { | |
| 2443 | + $log = array_slice($log, 0, 200); | |
| 2444 | + } | |
| 2445 | + | |
| 2446 | + update_option('berqwp_recently_optimized', wp_json_encode($log), false); | |
| 2447 | +} | |
| 2448 | + | |
| 2449 | +function bwp_clear_recently_optimized_log() | |
| 2450 | +{ | |
| 2451 | + delete_option('berqwp_recently_optimized'); | |
| 2452 | +} | |
| 2453 | + | |
| 2454 | +function bwp_remove_recently_optimized_entry($page_url) | |
| 2455 | +{ | |
| 2456 | + if (empty($page_url)) return; | |
| 2457 | + | |
| 2458 | + $log = json_decode(get_option('berqwp_recently_optimized', '[]'), true); | |
| 2459 | + if (!is_array($log)) return; | |
| 2460 | + | |
| 2461 | + $log = array_values(array_filter($log, fn($e) => $e['url'] !== $page_url)); | |
| 2462 | + update_option('berqwp_recently_optimized', wp_json_encode($log), false); | |
| 2463 | +} | |
| 2464 | + | |
| 2255 | 2465 | function berqwp_can_use_cloud() { |
| 2256 | 2466 | $berqconfigs = berqConfigs::getInstance(); |
| 2257 | 2467 | $configs = $berqconfigs->get_configs(); |
| 2258 | 2468 | $license_key = berqwp_get_license_key(); |
| @@ -2257,5 +2467,12 @@ | ||
| 2257 | 2467 | $configs = $berqconfigs->get_configs(); |
| 2258 | 2468 | $license_key = berqwp_get_license_key(); |
| 2259 | 2469 | |
| 2260 | 2470 | return !empty($configs['site_id']) && !empty($configs['secret']) && !empty($configs['optimization_method']) && $configs['optimization_method'] == 'cloud' && !empty($license_key); |
| 2471 | +} | |
| 2472 | + | |
| 2473 | +function berqwp_generate_site_id() { | |
| 2474 | + $blog_id = get_current_blog_id(); | |
| 2475 | + $network_id = function_exists('get_current_network_id') ? get_current_network_id() : 1; | |
| 2476 | + $siteurl = get_option('siteurl'); | |
| 2477 | + return md5("berqwp|$network_id|$blog_id|$siteurl"); | |
| 2261 | 2478 | } |