PluginProbe
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript / trunk
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript vtrunk
4.1.16 4.1.15 4.1.14 4.1.13 4.1.12 4.1.11 4.1.10 4.0.30 4.0.29 4.0.28 4.0.27 4.0.26 4.0.24 4.0.25 4.0.23 4.0.22 4.0.21 4.0.19 4.0.18 4.0.17 4.0.16 1.9.3 1.9.4 1.9.5 1.9.6 All 170 releases
← All changes | inc/helper-functions.php +1744 -228 1.9.7trunk View file →
@@ -1,16 +1,233 @@
1 1 <?php
2 +
3 +use BerqWP\BerqWP;
4 +use BerqWP_Deps\voku\helper\HtmlDomParser;
5 +
2 6 if (!defined('ABSPATH'))
3 7 exit;
4 8
9 +// ==========================================
10 +// Multisite Network Option Helpers
11 +// ==========================================
5 12
13 +function berqwp_get_license_key() {
14 + if (function_exists('is_multisite') && is_multisite()) {
15 + return get_site_option('berqwp_license_key', '');
16 + }
17 + return get_option('berqwp_license_key', '');
18 +}
19 +
20 +function berqwp_remove_license_key() {
21 + if (function_exists('is_multisite') && is_multisite()) {
22 + return delete_site_option('berqwp_license_key');
23 + }
24 + return delete_option('berqwp_license_key');
25 +}
26 +
27 +function berqwp_update_license_key($key) {
28 + if (function_exists('is_multisite') && is_multisite()) {
29 + return update_site_option('berqwp_license_key', $key);
30 + }
31 + return update_option('berqwp_license_key', $key);
32 +}
33 +
34 +function berqwp_delete_license_key() {
35 + if (function_exists('is_multisite') && is_multisite()) {
36 + return delete_site_option('berqwp_license_key');
37 + }
38 + return delete_option('berqwp_license_key');
39 +}
40 +
41 +function berqwp_get_network_option($key, $default = false) {
42 + if (function_exists('is_multisite') && is_multisite()) {
43 + return get_site_option($key, $default);
44 + }
45 + return get_option($key, $default);
46 +}
47 +
48 +function berqwp_update_network_option($key, $value) {
49 + if (function_exists('is_multisite') && is_multisite()) {
50 + return update_site_option($key, $value);
51 + }
52 + return update_option($key, $value);
53 +}
54 +
55 +function berqwp_delete_network_option($key) {
56 + if (function_exists('is_multisite') && is_multisite()) {
57 + return delete_site_option($key);
58 + }
59 + return delete_option($key);
60 +}
61 +
62 +function berqwp_is_network_activated() {
63 + if (!function_exists('is_multisite') || !is_multisite()) {
64 + return false;
65 + }
66 + if (function_exists('is_plugin_active_for_network')) {
67 + return is_plugin_active_for_network('searchpro/berqwp.php');
68 + }
69 + return false;
70 +}
71 +
72 +function berqwp_is_multisite() {
73 + return function_exists('is_multisite') && is_multisite();
74 +}
75 +
76 +function berqwp_is_license_managed_by_network() {
77 + return berqwp_is_multisite() && berqwp_is_network_activated();
78 +}
79 +
80 +function berqwp_is_license_active() {
81 + return !empty(berqwp_get_license_key());
82 +}
83 +
84 +function berqwp_activate_single_site() {
85 + if (empty(berqwp_get_license_key())) {
86 + set_transient('berqwp_redirect', true, 1);
87 + }
88 + update_option('berqwp_sync_addons', true);
89 + do_action('berqwp_activate_plugin');
90 +}
91 +
6 92 function berqwp_is_slug_excludable($slug)
7 93 {
8 - if (empty($slug)) {
9 - return true;
10 - }
94 + // Allow empty slug
95 + // if (empty($slug)) {
96 + // return true;
97 + // }
11 98
12 - $exclude_items = ["elementor_library=", "add_to_wishlist=", "robots.txt", ".html", ".php", "run_warmup=", "et-compare-page=", "add_to_compare=", "min_price=", "max_price=", "view_mode=", "view_mode_smart=", "et_columns-count=", "add_to_wishlist=", "et-wishlist-page=", "remove_wishlist=", "stock_status=", "page_id=", "?p="];
99 + $exclude_items = [
100 + "favicon.ico",
101 + "moderation-hash=",
102 + "elementor_library=",
103 + "add_to_wishlist=",
104 + "robots.txt",
105 + ".php",
106 + "run_warmup=",
107 + "et-compare-page=",
108 + "add_to_compare=",
109 + "min_price=",
110 + "max_price=",
111 + "view_mode=",
112 + "view_mode_smart=",
113 + "et_columns-count=",
114 + "add_to_wishlist=",
115 + "et-wishlist-page=",
116 + "remove_wishlist=",
117 + "stock_status=",
118 + "page_id=",
119 + "?p=",
120 + "add-to-cart=",
121 + "remove_item=",
122 + "cart_item_key=",
123 + "quantity=",
124 + "my-account=",
125 + "lost-password=",
126 + "reset-password=",
127 + "order-pay=",
128 + "order-received=",
129 + "view-order=",
130 + "?s=",
131 + "&s=",
132 + "orderby=",
133 + "product_tag=",
134 + "product_cat=",
135 + "min_price=",
136 + "max_price=",
137 + "rating=",
138 + "filter_",
139 + "edd_action=",
140 + "download_id=",
141 + "bbp_=",
142 + "bbp-search=",
143 + "&bp_=",
144 + "?bp_=",
145 + "?action=",
146 + "&action=",
147 + "gf_page=",
148 + "gf_token=",
149 + "gform_submit=",
150 + "wordfence_logHuman=",
151 + "wordfence_lh=",
152 + "wordfence_syncAttackData=",
153 + "?elementor=",
154 + "&elementor=",
155 + "?ld_=",
156 + "&ld_=",
157 + "lesson_id=",
158 + "quiz_id=",
159 + "wpforms=",
160 + "?ref=",
161 + "&ref=",
162 + "?aff=",
163 + "&aff=",
164 + "?llms_=",
165 + "&llms_=",
166 + "lesson_id=",
167 + "course_id=",
168 + "vc_editable=true",
169 + "et_fb=1",
170 + "et_fb_edit",
171 + "rcp_action=",
172 + "member_id=",
173 + "give_action=",
174 + "donation_id=",
175 + "giveDonationFormInIframe=",
176 + "tribe-bar-date=",
177 + "tribe_eventcategory=",
178 + "tribe_paged=",
179 + "tribe_organizer=",
180 + "tribe_venue=",
181 + "job_id=",
182 + "job_applications=",
183 + "job_alerts=",
184 + "mepr-process=",
185 + "mepr-transaction=",
186 + "mepr_coupon=",
187 + "popmake=",
188 + "pum_form_sub=",
189 + "pum_action=",
190 + "ngg_page=",
191 + "gallery_id=",
192 + "pid=",
193 + "wp_simple_pay=",
194 + "sp_dont_optimize=",
195 + "remove_from_wishlist=",
196 + "action=yith-woocompare",
197 + "?amp=",
198 + "&amp=",
199 + "?noamp=",
200 + "&noamp=",
201 + "subscription_id=",
202 + "renewal_order=",
203 + "edd_bk=",
204 + "wpgmza=",
205 + "poll_id=",
206 + "pollresult=",
207 + "swpquery=",
208 + "swpengine=",
209 + "monsterinsights=",
210 + "defender=",
211 + "wdf_scan=",
212 + "wc_bookings_field=",
213 + "wc_bookings_calendar=",
214 + "?na=",
215 + "&na=",
216 + "?newsletter=",
217 + "&newsletter=",
218 + "affwp_ref=",
219 + "affwp_campaign=",
220 + "hmwp_token=",
221 + "/page/",
222 + "/search/",
223 + "?",
224 + "/embed",
225 + "/view-order/",
226 + "/redirect/",
227 + "/elementskit-content/",
228 + "/checkout/",
229 + ];
13 230
14 231 $exclude_items = apply_filters('berqwp_exclude_slug_match', $exclude_items);
15 232
16 233 foreach ($exclude_items as $item) {
@@ -21,26 +238,20 @@
21 238
22 239 return false;
23 240 }
24 241
25 -function berqwp_get_page_params($slug, $is_forced = false) {
26 - if (empty($slug)) {
242 +function berqwp_get_page_params($page_url, $is_forced = false)
243 +{
244 +
245 + if (empty($page_url)) {
27 246 return;
28 247 }
29 248
30 - $url = home_url() . $slug;
31 - $slug_md5 = md5($slug);
249 + $page_slug = bwp_url_into_path($page_url);
250 + $key = '';
251 + $berqconfigs = berqConfigs::getInstance();
252 + $berqwp_configs = $berqconfigs->get_configs();
32 253
33 - $cache_directory = optifer_cache . '/html/';
34 - $cache_file = $cache_directory . $slug_md5 . '.html';
35 - $key = uniqid();
36 - $cache_max_life = @filemtime($cache_file) + (18 * 60 * 60);
37 -
38 - if (!file_exists($cache_file) || (file_exists($cache_file) && $cache_max_life < time()) || (file_exists($cache_file) && bwp_is_partial_cache($slug) === true)) {
39 - // Priority 1
40 - $key = '';
41 - }
42 -
43 254 $optimization_mode = get_option('berq_opt_mode');
44 255
45 256 if ($optimization_mode == 4) {
46 257 $optimization_mode = 'aggressive';
@@ -53,52 +264,90 @@
53 264 }
54 265
55 266 // Data to send as POST parameters
56 267 $post_data = array(
57 - 'license_key' => get_option('berqwp_license_key'),
58 - 'page_url' => $url,
59 - 'page_slug' => $slug,
60 - 'site_url' => home_url(),
61 - 'webp_max_width' => (int) get_option('berqwp_webp_max_width'),
62 - 'webp_quality' => (int) get_option('berqwp_webp_quality'),
63 - 'img_lazyloading' => get_option('berqwp_image_lazyloading'),
64 - 'youtube_lazyloading' => get_option('berqwp_lazyload_youtube_embed'),
65 - 'js_mode' => get_option('berqwp_javascript_execution_mode'),
66 - 'key' => $key,
67 - 'interaction_delay' => get_option('berqwp_interaction_delay'),
68 - 'cache_js' => true,
69 - 'use_cdn' => get_option('berqwp_enable_cdn'),
70 - 'opt_mode' => $optimization_mode,
71 - 'disable_webp' => get_option('berqwp_disable_webp'),
72 - 'js_css_exclude_urls' => get_option('berq_exclude_js_css', []),
73 - 'preload_fontfaces' => get_option('berqwp_preload_fontfaces'),
74 - // 'mobile_lcp' => json_encode($mobile_lcp),
75 - // 'desktop_lcp' => json_encode($desktop_lcp),
76 - 'version' => BERQWP_VERSION
268 + 'site_id' => $berqwp_configs['site_id'],
269 + 'license_key' => berqwp_get_license_key(),
270 + 'page_url' => $page_url,
271 + 'page_slug' => $page_slug,
272 + 'site_url' => home_url(),
273 + 'webp_max_width' => (int) get_option('berqwp_webp_max_width'),
274 + 'webp_quality' => (int) get_option('berqwp_webp_quality'),
275 + 'fluid_images' => get_option('berqwp_fluid_images'),
276 + 'enable_critical_css' => get_option('berqwp_enable_critical_css'),
277 + 'force_include_critical_css'=> get_option('berqwp_force_include_critical_css', []),
278 + 'exclude_css' => get_option('berqwp_exclude_css', []),
279 + 'exclude_js' => get_option('berqwp_exclude_js', []),
280 + 'exclude_third_party_js' => get_option('berqwp_exclude_third_party_js', []),
281 + 'async_excluded_styles' => get_option('berqwp_async_excluded_styles'),
282 + 'prerender_link' => get_option('berqwp_prerender_on_hover'),
283 + 'defer_excluded_js' => get_option('berqwp_defer_excluded_js'),
284 + 'delay_third_party_scripts' => get_option('berqwp_delay_third_party_scripts'),
285 + 'lazy_render' => get_option('berqwp_lazy_render'),
286 + 'img_lazyloading' => get_option('berqwp_image_lazyloading'),
287 + 'exclude_img_lazy_load' => get_option('berqwp_exclude_lazy_load_images', []),
288 + 'lazy_load_videos' => get_option('berqwp_lazy_load_videos'),
289 + 'youtube_lazyloading' => get_option('berqwp_lazyload_youtube_embed'),
290 + 'preload_yt_poster' => get_option('berqwp_preload_yt_poster'),
291 + 'js_mode' => get_option('berqwp_javascript_execution_mode'),
292 + 'key' => $key,
293 + // 'interaction_delay' => get_option('berqwp_interaction_delay'),
294 + 'use_cdn' => get_option('berqwp_enable_cdn'),
295 + 'opt_mode' => $optimization_mode,
296 + 'disable_webp' => !get_option('berqwp_enable_webp'),
297 + // 'js_css_exclude_urls' => get_option('berq_exclude_js_css', []),
298 + 'preload_fontfaces' => get_option('berqwp_preload_fontfaces'),
299 + 'enable_cwv' => get_option('berqwp_enable_cwv'),
300 + 'preload_cookiebanner' => get_option('berqwp_preload_cookiebanner'),
301 + 'css_optimization' => get_option('berq_css_optimization'),
302 + 'js_optimization' => get_option('berq_js_optimization'),
303 + 'exclude_cdn' => get_option('berq_exclude_cdn', []),
304 + 'webhook' => true,
305 + 'version' => BERQWP_VERSION
77 306 );
78 307
79 - if (defined('BERQ_STAGING') || $is_forced) {
80 - $post_data['run_queue'] = 1;
81 - $post_data['doing_queue'] = true;
308 + if (!get_option('berqwp_can_use_fluid_images')) {
309 + $post_data['fluid_images'] = 0;
82 310 }
83 311
312 + // if (defined('BERQ_STAGING')) {
313 + // $post_data['run_queue'] = 1;
314 + // $post_data['doing_queue'] = true;
315 + // }
316 +
317 + if ($page_url == home_url('/')) {
318 + $is_forced = true;
319 + }
320 +
321 + if ($is_forced) {
322 + $post_data['force'] = true;
323 + }
324 +
84 325 return $post_data;
326 +}
85 327
328 +function bwp_pass_account_requirement()
329 +{
330 + global $berq_log;
331 + $berqWP = \berqWP::getInstance();
86 332
87 -}
333 + $license_key = berqwp_get_license_key();
88 334
89 -function bwp_pass_account_requirement() {
90 - global $berqWP, $berq_log;
335 + if (empty($license_key)) {
336 + return false;
337 + }
91 338
92 - $license_key = get_option('berqwp_license_key');
93 - $key_response = $berqWP->verify_license_key($license_key);
339 + global $berq_log;
340 + // $berq_log->info("License key check from bwp_pass_account_requirement function.");
94 341
342 + $key_response = $berqWP->verify_license_key($license_key);
343 +
95 344 if (empty($key_response->product_ref)) {
96 345 return false;
97 346 }
98 347
99 - if ($key_response->result !== 'success' || $key_response->status !== 'active') {
100 - $berq_log->error("account requirement: license verification failed");
348 + if ($key_response->result !== 'success' || $key_response->status !== 'active') {
349 + // $berq_log->error("account requirement: license verification failed");
101 350 return false;
102 351 }
103 352
104 353 if ($key_response->product_ref == 'Free Account' && bwp_cached_pages_count() >= 10) {
@@ -111,120 +360,151 @@
111 360
112 361 return true;
113 362 }
114 363
115 -function warmup_cache_by_slug($slug, $is_forced = false)
364 +function warmup_cache_by_url($page_url, $is_forced = false, $async = false)
116 365 {
117 - if (empty($slug)) {
366 +
367 + if (!berqwp_can_use_cloud()) {
118 368 return;
119 369 }
120 370
121 - if (berqwp_is_slug_excludable($slug)) {
371 + if (empty($page_url)) {
122 372 return;
123 373 }
124 374
125 - $slug_md5 = md5($slug);
375 + if (empty(berqwp_get_license_key())) {
376 + return;
377 + }
126 378
127 - $cache_directory = optifer_cache . '/html/';
128 - $cache_file = $cache_directory . $slug_md5 . '.html';
129 - $cache_max_life = @filemtime($cache_file) + (18 * 60 * 60);
379 + if (berq_is_localhost() && !defined('BERQWP_ALLOW_LOCALHOST')) {
380 + return;
381 + }
130 382
131 - if (!file_exists($cache_file) && bwp_pass_account_requirement() === false) {
383 + if (berq_is_localhost() && defined('BERQWP_ALLOW_LOCALHOST') && BERQWP_ALLOW_LOCALHOST === false) {
132 384 return;
133 385 }
134 386
135 - // Return if page is excluded from cache
136 - $pages_to_exclude = get_option('berq_exclude_urls', []);
387 + $page_url = strtolower($page_url);
137 388
138 - if (in_array(home_url() . $slug, $pages_to_exclude)) {
389 + $parsed_site_url = wp_parse_url(home_url());
390 + $parsed_page_url = wp_parse_url($page_url);
391 +
392 + if ($parsed_page_url['host'] !== $parsed_site_url['host']) {
139 393 return;
140 394 }
141 395
142 - $check_rest = bwp_check_rest_api(true);
143 - if ( $check_rest['status'] == 'error' ) {
144 - global $berq_log;
145 - $berq_log->error('Exiting cache warmup by slug, rest api not working.');
396 + // Avoid caching file URLs e.g .php
397 + // Allow .html
398 + if (berqwp_is_file_url($page_url)) {
146 399 return;
147 400 }
148 -
149 - // Hook to modify cache lifespan
150 - $cache_max_life = apply_filters('berqwp_cache_lifespan', $cache_max_life);
151 401
152 - if (file_exists($cache_file) && bwp_is_partial_cache($slug) === false && $cache_max_life > time()) {
402 + // We don't want to cache page URL with query params
403 + if (strpos($page_url, '?') !== false) {
153 404 return;
154 405 }
155 406
156 - // API endpoint URL
157 - $api_endpoint = 'https://boost.berqwp.com/photon/';
158 -
159 - if (get_site_url() == 'http://berq-test.local') {
160 - $api_endpoint = 'http://dev-berqwp.local/photon/';
407 + // Return if page url or page path (slug) is excluded
408 + if (!bwp_can_optimize_page_url($page_url)) {
409 + return;
161 410 }
162 411
163 - // Modify photon engine endpoint for testing purposes
164 - $api_endpoint = apply_filters( 'berqwp_photon_endpoint', $api_endpoint );
412 + global $berq_log;
413 + $berq_log->info('warming page: ' . $page_url);
165 414
166 - $post_data = berqwp_get_page_params($slug, $is_forced);
167 -
168 - // Set up the request arguments
169 - $args = array(
170 - 'body' => $post_data, // Pass the POST data here
171 - 'method' => 'POST',
172 - // 'blocking' => false,
173 - 'timeout' => $is_forced === true ? 20 : 0.1,
174 - 'headers' => array(
175 - 'Content-Type' => 'application/x-www-form-urlencoded', // Adjust content type if needed
176 - ),
177 - );
415 + // Prepare post data for this page
416 + $post_data = berqwp_get_page_params($page_url, $is_forced);
178 417
179 - // Send the POST request
180 - $response = wp_remote_post($api_endpoint, $args);
418 + $berqwp = new BerqWP(get_option('berqwp_license_key'), null, optifer_cache);
419 + $timeout = 30;
181 420
182 - // Check for errors and handle the response
183 - if (is_wp_error($response)) {
184 - // There was an error with the request
185 - error_log('Error: ' . $response->get_error_message());
421 + if ($async) {
422 + $timeout = 1;
186 423 }
187 424
425 + $berqwp->request_cache($post_data, $timeout);
188 426 }
189 427
190 -function bwp_is_home_cached() {
191 - $slug_md5 = md5('/');
192 - $cache_directory = optifer_cache . '/html/';
193 - $cache_file = $cache_directory . $slug_md5 . '.html';
428 +function bwp_is_home_cached()
429 +{
430 + $cache_directory = bwp_get_cache_dir();
431 + $cache_file = $cache_directory . bwp_build_cache_path(bwp_admin_home_url('/')) . '/index.html.gz';
194 432
195 433 return file_exists($cache_file);
196 434 }
197 435
198 -function bwp_is_partial_cache($slug) {
436 +function bwp_cache_current_page()
437 +{
438 + global $bwp_current_page, $berq_log;
199 439
200 - if (!function_exists('str_get_html')) {
201 - require_once optifer_PATH . '/simplehtmldom/simple_html_dom.php';
440 + // $berq_log->info('Shutdown hook fired.');
441 +
442 + if (empty($bwp_current_page)) {
443 + return;
202 444 }
203 -
204 - $cache_directory = optifer_cache . '/html/';
205 - $cache_key = md5($slug);
445 +
446 + // Check if the current user is logged in or if it's a POST request
447 + if (is_user_logged_in() || $_SERVER['REQUEST_METHOD'] === 'POST' || $_SERVER['REQUEST_METHOD'] === 'PURGE') {
448 + return;
449 + }
450 +
451 + if (is_admin()) {
452 + return;
453 + }
454 +
455 + if (defined('DOING_CRON') && DOING_CRON) {
456 + return;
457 + }
458 +
459 + if (defined('DOING_AJAX') && DOING_AJAX) {
460 + return;
461 + }
462 +
463 + if (defined('REST_REQUEST') && REST_REQUEST) {
464 + return;
465 + }
466 +
467 + if (php_sapi_name() === 'cli' || defined('WP_CLI')) {
468 + return;
469 + }
470 +
471 + if (!bwp_is_webpage()) {
472 + return;
473 + }
474 +
475 + if (!bwp_can_warmup_cache($bwp_current_page)) {
476 + return;
477 + }
478 +
479 + warmup_cache_by_url($bwp_current_page, false, false);
480 + $bwp_current_page = null;
481 +}
482 +
483 +function bwp_is_partial_cache($identifier)
484 +{
485 +
486 + $cache_directory = bwp_get_cache_dir();
487 + $cache_key = md5($identifier);
206 488 $cache_file = $cache_directory . $cache_key . '.html';
207 -
489 +
208 490 if (file_exists($cache_file)) {
209 491 $buffer = file_get_contents($cache_file);
210 492
211 493 if (!empty($buffer)) {
212 - $html = str_get_html($buffer);
494 + $html = HtmlDomParser::str_get_html($buffer);
213 495
214 496 if ($html !== false) {
215 497 $style_tag = $html->find('style#berqwp-critical-css', 0);
216 -
498 +
217 499 if ($style_tag === null) {
218 500 return true;
219 501 }
220 502 }
221 -
222 503 }
223 504 }
224 505
225 506 return false;
226 -
227 507 }
228 508
229 509 function berq_is_localhost()
230 510 {
@@ -241,19 +521,19 @@
241 521 {
242 522 // List of tracking parameters to remove
243 523 $tracking_params = get_option('berq_ignore_urls_params', []);
244 524
245 - $tracking_params = apply_filters( 'berqwp_ignored_urls_params', $tracking_params );
525 + $tracking_params = apply_filters('berqwp_ignored_urls_params', $tracking_params);
246 526
247 527 // Parse the provided slug
248 528 $url_parts = parse_url($slug);
249 -
529 +
250 530 // Get the current URL parameters
251 531 $url_params = array();
252 532 if (isset($url_parts['query'])) {
253 533 parse_str($url_parts['query'], $url_params);
254 534 }
255 -
535 +
256 536 // Remove specified tracking parameters from the URL
257 537 foreach ($tracking_params as $param) {
258 538 $param = trim($param);
259 539 if (isset($url_params[$param])) {
@@ -264,23 +544,49 @@
264 544 // Build the new query string
265 545 $new_query_string = http_build_query($url_params);
266 546
267 547 // Reconstruct the URL with the new query string
268 - $new_slug = $url_parts['path'];
548 + $updated_url = $url_parts['scheme'] . "://" . $url_parts['host'] . $url_parts['path'];
269 549 if (!empty($new_query_string)) {
270 - $new_slug .= '?' . $new_query_string;
550 + $updated_url .= '?' . $new_query_string;
271 551 }
272 552
273 - return $new_slug;
553 + return $updated_url;
274 554 }
275 555
276 556 function berqwp_is_sub_dir_wp()
277 557 {
278 - // remove http
279 - $site_url = explode('//', home_url())[1];
280 - $break_slash = explode('/', $site_url);
558 + // // remove http
559 + // $site_url = explode('//', home_url())[1];
560 + // $break_slash = explode('/', $site_url);
281 561
282 - return count($break_slash) > 1;
562 + // return count($break_slash) > 1;
563 +
564 + $site_url = site_url();
565 + $home_url = home_url();
566 +
567 + // Parse paths from URLs
568 + $site_path = @trim(parse_url($site_url, PHP_URL_PATH), '/');
569 + $home_path = @trim(parse_url($home_url, PHP_URL_PATH), '/');
570 +
571 + // Split paths into segments
572 + $site_segments = explode('/', $site_path);
573 + $home_segments = explode('/', $home_path);
574 +
575 + // Check if Site URL has any segments and is not empty
576 + if (!empty($site_path) && count($site_segments) > 0) {
577 + // If both paths are the same and contain at least one segment
578 + if ($site_path === $home_path && count($site_segments) > 0) {
579 + return true; // WordPress is in a subdirectory
580 + }
581 + }
582 +
583 + // Check if the Home URL has more segments than the Site URL
584 + if (count($home_segments) > 1) {
585 + return true; // Home URL indicates a subdirectory
586 + }
587 +
588 + return false; // Otherwise, it's likely not in a subdirectory
283 589 }
284 590
285 591 function berqwp_current_page_cache_file()
286 592 {
@@ -320,9 +626,9 @@
320 626 }
321 627
322 628
323 629 // Attempt to retrieve the cached HTML from the cache directory
324 - $cache_directory = optifer_cache . '/html/';
630 + $cache_directory = bwp_get_cache_dir();
325 631
326 632 // Generate a unique cache key based on the current page URL
327 633 $cache_key = md5($slug);
328 634 $cache_file = $cache_directory . $cache_key . '.html';
@@ -327,9 +633,8 @@
327 633 $cache_key = md5($slug);
328 634 $cache_file = $cache_directory . $cache_key . '.html';
329 635
330 636 return $cache_file;
331 -
332 637 }
333 638
334 639 function berqwp_get_LCP_details($url, $device = 'mobile')
335 640 {
@@ -346,90 +651,152 @@
346 651 // Convert the JSON response to a PHP array
347 652 $body = wp_remote_retrieve_body($response);
348 653 $output = json_decode($body, true);
349 654
350 - // Get the LCP data
655 + // Get the LCP data
351 656 return $output['lighthouseResult']['audits']['largest-contentful-paint-element']['details']['items'][0]['items'][0]['node'];
352 657 }
353 658
354 -function berqwp_enable_object_cache($enable) {
659 +function berqwp_enable_advanced_cache($status)
660 +{
355 661 global $berq_log;
356 - $berq_log->info("Updating wp-config.php");
357 662
358 - // Specify the wp-config.php file path
359 - $wp_config_file = ABSPATH . 'wp-config.php';
663 + // Get wp-config.php path
664 + $configFilePath = defined('BERQWP_WP_CONFIG') ? BERQWP_WP_CONFIG : ABSPATH . 'wp-config.php';
360 665
361 - // Read the contents of wp-config.php
362 - $wp_config_content = file_get_contents($wp_config_file);
666 + // Check if the file exists
667 + if (!file_exists($configFilePath)) {
668 + $berq_log->error("Error: wp-config.php does not exist.");
669 + return false;
670 + }
363 671
364 - // Find the position of the first PHP tag using a regular expression
365 - preg_match('/<\?php/', $wp_config_content, $matches, PREG_OFFSET_CAPTURE);
672 + // Check if the file is writable
673 + if (!is_writable($configFilePath)) {
674 + $berq_log->error("Error: wp-config.php is not writable. Check file permissions.");
675 + return false;
676 + }
366 677
367 - // Check if the PHP opening tag exists
368 - if (!empty($matches)) {
369 - $first_php_comment_position = $matches[0][1] + 5; // Move past the length of '<?php'
678 + // Prepare the new WP_CACHE definition
679 + $newVal = sprintf("define( 'WP_CACHE', %s ); /* Added by BerqWP */\n", ($status ? "true" : "false"));
680 + $replacementVal = sprintf(" %s ", ($status ? "true" : "false"));
370 681
371 - // Check if the WP_CACHE definition exists in the file
372 - if (strpos($wp_config_content, "define('WP_CACHE'") === false && strpos($wp_config_content, "define( 'WP_CACHE' ") === false) {
373 - // If not, add the definition right after the opening PHP tag
374 - $wp_config_content = substr_replace($wp_config_content, "\n"
375 - . "// Enable or disable BerqWP object cache\n"
376 - . "define('WP_CACHE', " . ($enable ? 'true' : 'false') . ");\n",
377 - $first_php_comment_position, 0);
682 + // Read the file into an array of lines
683 + $lines = file($configFilePath);
684 + if ($lines === false || empty($lines)) {
685 + $berq_log->error("Error: Could not read wp-config.php or file is empty.");
686 + return false;
687 + }
688 +
689 + $wpCacheFound = false;
690 + $phpOpeningTagLine = false;
691 +
692 + // Process each line to update an existing WP_CACHE definition
693 + foreach ($lines as $lineIndex => &$line) {
694 + if (strpos($line, "<?php") !== false && strpos($line, "?>") === false) {
695 + $phpOpeningTagLine = $lineIndex;
696 + }
697 + if (!$wpCacheFound && preg_match("/define\s*\(\s*['\"](.*?)['\"]\s*,(.*?)\)/", $line, $matches)) {
698 + if ($matches[1] === "WP_CACHE") {
699 + // Replace the existing WP_CACHE value with the new value
700 + $line = str_replace($matches[2], $replacementVal, $line);
701 + $wpCacheFound = true;
702 + }
703 + }
704 + // If we have found both the opening tag and WP_CACHE, we can stop processing further lines.
705 + if ($phpOpeningTagLine !== false && $wpCacheFound !== false) {
706 + break;
707 + }
708 + }
709 + unset($line);
710 +
711 + // If WP_CACHE was not found and we are enabling it, insert it after the PHP opening tag.
712 + if (!$wpCacheFound && $status) {
713 + if ($phpOpeningTagLine !== false) {
714 + array_splice($lines, $phpOpeningTagLine + 1, 0, [$newVal]);
378 715 } else {
379 - // Otherwise, enable or disable the existing definition
380 - // $wp_config_content = preg_replace(
381 - // "/define\('WP_CACHE', [^\n]*\);/",
382 - // "define('WP_CACHE', " . ($enable ? 'true' : 'false') . ");",
383 - // $wp_config_content
384 - // );
716 + // If no PHP opening tag is found, prepend a new one with the WP_CACHE definition.
717 + array_unshift($lines, "<?php " . trim($newVal) . " ?>\n");
718 + }
719 + }
385 720
386 - $wp_config_content = preg_replace(
387 - "/define\(\s*'WP_CACHE'\s*,\s*[^\n]*\);/",
388 - "define('WP_CACHE', " . ($enable ? 'true' : 'false') . ");",
389 - $wp_config_content
390 - );
391 - }
721 + // Rebuild the file content
722 + $newContent = implode("", $lines);
723 + $tempFile = $configFilePath . '.tmp';
392 724
393 - // Write the modified content back to wp-config.php
394 - file_put_contents($wp_config_file, $wp_config_content);
395 - } else {
725 + // Write to a temporary file first (atomic write)
726 + if (file_put_contents($tempFile, $newContent, LOCK_EX) === false) {
727 + $berq_log->error("Error: Could not write to temporary file: $tempFile");
728 + return false;
729 + }
396 730
397 - global $berq_log;
398 - $berq_log->error("Error: PHP opening tag not found in wp-config.php");
399 -
731 + // Rename the temporary file to wp-config.php
732 + if (!rename($tempFile, $configFilePath)) {
733 + $berq_log->error("Error: Could not rename temporary file to wp-config.php");
734 + unlink($tempFile);
735 + return false;
400 736 }
737 +
738 + $berq_log->info("wp-config.php updated successfully.");
739 + return true;
401 740 }
402 741
403 742 // Copied from Nginx Helper plugin
404 -function berqwp_unlink_recursive( $dir ) {
743 +// function berqwp_unlink_recursive($dir)
744 +// {
405 745
406 - if ( ! is_dir( $dir ) ) {
407 - return;
408 - }
746 +// if (!is_dir($dir)) {
747 +// return;
748 +// }
409 749
410 - $dh = opendir( $dir );
750 +// $dh = opendir($dir);
411 751
412 - if ( ! $dh ) {
413 - return;
752 +// if (!$dh) {
753 +// return;
754 +// }
755 +
756 +// // phpcs:ignore -- WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition -- Variable assignment required for recursion.
757 +// while (false !== ($obj = readdir($dh))) {
758 +
759 +// if ('.' === $obj || '..' === $obj) {
760 +// continue;
761 +// }
762 +
763 +// if (!@unlink($dir . '/' . $obj)) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
764 +// berqwp_unlink_recursive($dir . '/' . $obj, false);
765 +// }
766 +// }
767 +
768 +// closedir($dh);
769 +// }
770 +
771 +function berqwp_unlink_recursive($dir)
772 +{
773 + if (!is_dir($dir)) {
774 + return false;
414 775 }
415 776
416 - // phpcs:ignore -- WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition -- Variable assignment required for recursion.
417 - while ( false !== ( $obj = readdir( $dh ) ) ) {
777 + $files = new RecursiveIteratorIterator(
778 + new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
779 + RecursiveIteratorIterator::CHILD_FIRST
780 + );
418 781
419 - if ( '.' === $obj || '..' === $obj ) {
420 - continue;
782 + foreach ($files as $file) {
783 + if ($file->isFile()) {
784 + if (!unlink($file->getRealPath())) {
785 + error_log("Failed to delete file: " . $file->getRealPath());
786 + }
787 + } elseif ($file->isDir()) {
788 + if (!rmdir($file->getRealPath())) {
789 + error_log("Failed to delete directory: " . $file->getRealPath());
790 + }
421 791 }
422 -
423 - if ( ! @unlink( $dir . '/' . $obj ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
424 - berqwp_unlink_recursive( $dir . '/' . $obj, false );
425 - }
426 792 }
427 793
428 - closedir( $dh );
794 + return rmdir($dir); // remove the root directory itself
429 795 }
430 796
431 -function berqwp_get_last_modified_timestamp() {
797 +function berqwp_get_last_modified_timestamp()
798 +{
432 799 global $post;
433 800
434 801 // Check if it's a single post or page
435 802 if (is_singular()) {
@@ -486,19 +853,45 @@
486 853 // For other cases (fallback)
487 854 return false;
488 855 }
489 856
490 -function bwp_is_gzip_supported() {
857 +function bwp_is_gzip_supported()
858 +{
491 859 return function_exists('gzencode') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;
492 860 }
493 861
494 -function bwp_cached_pages_count() {
495 - $cache_directory = optifer_cache . DIRECTORY_SEPARATOR . 'html';
496 - $cache_files = glob($cache_directory . DIRECTORY_SEPARATOR . "*.html");
497 - return count($cache_files);
862 +// function bwp_cached_pages_count()
863 +// {
864 +// $cache_directory = bwp_get_cache_dir();
865 +// $cache_files = glob($cache_directory . "*.gz");
866 +// return is_array($cache_files) ? count($cache_files) : 0;
867 +// }
868 +
869 +function bwp_cached_pages_count()
870 +{
871 + $cache_directory = bwp_get_cache_dir();
872 +
873 + if (!is_dir($cache_directory)) {
874 + return 0;
875 + }
876 +
877 + $count = 0;
878 +
879 + $iterator = new RecursiveIteratorIterator(
880 + new RecursiveDirectoryIterator($cache_directory, FilesystemIterator::SKIP_DOTS)
881 + );
882 +
883 + foreach ($iterator as $file) {
884 + if ($file->isFile() && str_ends_with($file->getFilename(), '.gz')) {
885 + $count++;
886 + }
887 + }
888 +
889 + return $count;
498 890 }
499 891
500 -function bwp_wp_remote_get($url, $args = array()) {
892 +function bwp_wp_remote_get($url, $args = array())
893 +{
501 894 // Default arguments
502 895 $defaults = array(
503 896 'headers' => array(
504 897 'User-Agent' => 'BerqWP Bot', // Customize user agent if needed
@@ -570,13 +963,25 @@
570 963
571 964 return $response;
572 965 }
573 966
574 -function bwp_is_openlitespeed_server() {
575 - return isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false;
967 +function bwp_is_openlitespeed_server()
968 +{
969 + $is_litespeed = false;
970 + $is_litespeed = isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false;
971 +
972 + $headers = getallheaders();
973 + foreach ($headers as $header => $value) {
974 + if (stripos($value, 'LiteSpeed') !== false) {
975 + $is_litespeed = true;
976 + }
977 + }
978 +
979 + return $is_litespeed;
576 980 }
577 981
578 -function verify_request_origin($request) {
982 +function verify_request_origin($request)
983 +{
579 984 // Check the referrer header to ensure the request is coming from the same site
580 985 $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
581 986 $site_url = get_site_url();
582 987
@@ -595,12 +1000,18 @@
595 1000
596 1001 return true;
597 1002 }
598 1003
599 -function berq_rest_permission_callback(WP_REST_Request $request) {
1004 +function berq_rest_permission_callback(WP_REST_Request $request)
1005 +{
600 1006 // Get the nonce from the request
601 1007 $nonce = $request->get_header('X-WP-Nonce');
1008 + $hash = $request->get_header('X-berqwp-key-hash');
602 1009
1010 + if ($hash == md5(berqwp_get_license_key())) {
1011 + return true;
1012 + }
1013 +
603 1014 // Verify the nonce
604 1015 if (!wp_verify_nonce($nonce, 'wp_rest')) {
605 1016 return new WP_Error('rest_invalid_nonce', __('Invalid nonce', 'searchpro'), array('status' => 403));
606 1017 }
@@ -607,25 +1018,27 @@
607 1018
608 1019 return true; // Return true to allow the request
609 1020 }
610 1021
611 -function berq_rest_verify_license_callback(WP_REST_Request $request) {
1022 +function berq_rest_verify_license_callback(WP_REST_Request $request)
1023 +{
612 1024 $license_key_hash = sanitize_text_field($request->get_param('license_key_hash'));
1025 + $license_key = berqwp_get_license_key();
613 1026
614 - if (empty($license_key_hash) || $license_key_hash !== md5(get_option('berqwp_license_key'))) {
1027 + if (empty($license_key_hash) || empty($license_key) || $license_key_hash !== md5($license_key)) {
615 1028 global $berq_log;
616 1029 $berq_log->error("Exiting... Invalid license key.");
617 1030 return new WP_Error('rest_invalid_nonce', __('Invalid license key', 'searchpro'), array('status' => 403));
618 -
619 1031 }
620 1032
621 1033 return true; // Return true to allow the request
622 1034 }
623 1035
624 -function bwp_dash_notification($msg = '', $status = 'warning') {
625 - ?>
626 - <div class="berqwp-notification <?php echo esc_attr($status)?>">
627 - <?php
1036 +function bwp_dash_notification($msg = '', $status = 'warning')
1037 +{
1038 +?>
1039 + <div class="berqwp-notification <?php echo esc_attr($status) ?>">
1040 + <?php
628 1041
629 1042 echo "<div class='icon'>";
630 1043 if ($status == 'warning') {
631 1044 echo '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480L40 480c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/></svg>';
@@ -636,31 +1049,33 @@
636 1049 } else {
637 1050 return;
638 1051 }
639 1052 echo "</div>";
640 - echo esc_html($msg);
1053 + echo esc_html($msg);
641 1054 ?>
642 1055 </div>
643 - <?php
1056 +<?php
644 1057 }
645 1058
646 -function bwp_can_warmup_cache($slug) {
1059 +function bwp_can_warmup_cache($identifier)
1060 +{
647 1061
648 - if (get_transient( 'bwp_warmup_lock_'.md5($slug) ) === false) {
1062 + if (get_transient('bwp_warmup_lock_' . md5($identifier)) === false) {
649 1063
650 - set_transient( 'bwp_warmup_lock_'.md5($slug), true, 100 );
1064 + set_transient('bwp_warmup_lock_' . md5($identifier), true, 100);
651 1065 return true;
652 -
653 1066 }
654 1067
655 1068 return false;
656 1069 }
657 1070
658 -function bwp_clear_warmup_lock($slug) {
659 - delete_transient( 'bwp_warmup_lock_'.md5($slug) );
1071 +function bwp_clear_warmup_lock($slug)
1072 +{
1073 + delete_transient('bwp_warmup_lock_' . md5($slug));
660 1074 }
661 1075
662 -function bwp_extractUrlsFromCss($cssContent) {
1076 +function bwp_extractUrlsFromCss($cssContent)
1077 +{
663 1078 $urls = [];
664 1079 $pattern = '/url\((.*?)\)/i';
665 1080
666 1081 preg_match_all($pattern, $cssContent, $matches);
@@ -674,9 +1089,10 @@
674 1089
675 1090 return $urls;
676 1091 }
677 1092
678 -function bwp_getBaseUrl($fileUrl) {
1093 +function bwp_getBaseUrl($fileUrl)
1094 +{
679 1095 // Parse the URL and get its components
680 1096 $parsedUrl = parse_url($fileUrl);
681 1097 $scheme = isset($parsedUrl['scheme']) ? $parsedUrl['scheme'] . '://' : '';
682 1098 $host = isset($parsedUrl['host']) ? $parsedUrl['host'] : '';
@@ -691,12 +1107,14 @@
691 1107
692 1108 function bwp_rel2abs($rel, $base)
693 1109 {
694 1110 /* return if already absolute URL */
695 - if (parse_url($rel, PHP_URL_SCHEME) != '') return $rel;
1111 + if (parse_url($rel, PHP_URL_SCHEME) != '')
1112 + return $rel;
696 1113
697 1114 /* queries and anchors */
698 - if ($rel[0]=='#' || $rel[0]=='?') return $base.$rel;
1115 + if ($rel[0] == '#' || $rel[0] == '?')
1116 + return $base . $rel;
699 1117
700 1118 /* parse base URL and convert to local variables:
701 1119 $scheme, $host, $path */
702 1120 extract(parse_url($base));
@@ -704,9 +1122,10 @@
704 1122 /* remove non-directory element from path */
705 1123 $path = preg_replace('#/[^/]*$#', '', $path);
706 1124
707 1125 /* destroy path if relative url points to root */
708 - if ($rel[0] == '/') $path = '';
1126 + if ($rel[0] == '/')
1127 + $path = '';
709 1128
710 1129 /* dirty absolute URL */
711 1130 $abs = "$host$path/$rel";
712 1131
@@ -711,15 +1130,17 @@
711 1130 $abs = "$host$path/$rel";
712 1131
713 1132 /* replace '//' or '/./' or '/foo/../' with '/' */
714 1133 $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
715 - for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
1134 + for ($n = 1; $n > 0; $abs = preg_replace($re, '/', $abs, -1, $n)) {
1135 + }
716 1136
717 1137 /* absolute URL is ready! */
718 - return $scheme.'://'.$abs;
1138 + return $scheme . '://' . $abs;
719 1139 }
720 1140
721 -function update_image_url_extension($image_url, $file_extension) {
1141 +function update_image_url_extension($image_url, $file_extension)
1142 +{
722 1143 $url_arr = explode('.', $image_url);
723 1144 $last_index = count($url_arr) - 1;
724 1145
725 1146 // Extract the file extension
@@ -728,55 +1149,73 @@
728 1149 $url_arr[$last_index] = str_replace("$current_file_extension", $file_extension, $url_arr[$last_index]);
729 1150 $new_image_url = implode('.', $url_arr);
730 1151
731 1152 return $new_image_url;
732 -
733 1153 }
734 1154
735 1155 if (!function_exists('str_contains')) {
736 - function str_contains(string $haystack, string $needle): bool {
1156 + function str_contains(string $haystack, string $needle): bool
1157 + {
737 1158 return strpos($haystack, $needle) !== false;
738 1159 }
739 1160 }
740 1161
741 -function bwp_check_rest_api($force_check = false) {
1162 +function bwp_check_connection($short_live = false, $force = false)
1163 +{
1164 +
1165 + $transient_key = "berqwp_connection_status";
1166 +
1167 + if ($force) {
1168 + delete_transient('berqwp_connection_status');
1169 + delete_transient('berqwp_connection_status_sl');
1170 + }
1171 +
742 1172 // Allow cache busting by passing $force_check = true
743 - if ($force_check) {
744 - delete_transient('berqwp_rest_api_status');
1173 + // if ($force_check) {
1174 + // delete_transient($transient_key);
1175 + // }
1176 +
1177 + if ($short_live) {
1178 + $transient_key = "berqwp_connection_status_sl";
745 1179 }
746 1180
747 1181 // Check if the result is cached
748 - $cached_status = get_transient('berqwp_rest_api_status');
1182 + $cached_status = get_transient($transient_key);
749 1183
750 - if ($cached_status && !$force_check) {
1184 + if ($cached_status) {
751 1185 return $cached_status;
752 1186 }
753 1187
754 1188 // Perform the actual REST API check
755 - $response = wp_safe_remote_get( rest_url(), ['timeout' => 10] );
1189 + $response = wp_safe_remote_get('https://boost.berqwp.com/photon/?connection_test=1&url=' . bwp_admin_home_url('/?utm_source=' . time()), ['timeout' => 60]);
756 1190
757 - if ( is_wp_error( $response ) ) {
758 - $result = array(
759 - 'status' => 'error',
760 - 'message' => 'The REST API is not working. Error: ' . $response->get_error_message(),
761 - );
1191 + if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
1192 + return ['status' => 'success']; // Skip if server is unreachable
1193 + // $result = array(
1194 + // 'status' => 'error',
1195 + // 'message' => 'The site is not accessible. Error: ' . $response->get_error_message(),
1196 + // );
762 1197 } else {
763 - $status_code = wp_remote_retrieve_response_code( $response );
1198 + $body = wp_remote_retrieve_body($response);
764 1199
765 - if ( $status_code == 200 ) {
1200 + if ($body == 'pingpong') {
766 1201 $result = array(
767 1202 'status' => 'success',
768 - 'message' => 'The REST API is working correctly.',
1203 + 'message' => 'Your website is accessible by BerqWP server.',
769 1204 );
770 1205 } else {
771 1206 $result = array(
772 1207 'status' => 'error',
773 - 'message' => 'The REST API returned an unexpected status code: ' . $status_code,
1208 + 'message' => 'BerqWP server is unable to access your website, please whitelist our server IP address.',
774 1209 );
775 1210 }
776 1211 }
777 1212
778 - set_transient('berqwp_rest_api_status', $result, 60 * 60 * 24);
1213 + if ($short_live) {
1214 + set_transient($transient_key, $result, 60 * 5);
1215 + } else {
1216 + set_transient($transient_key, $result, 60 * 60 * 24);
1217 + }
779 1218
780 1219 return $result;
781 1220 }
782 1221
@@ -789,9 +1228,9 @@
789 1228 $path = isset($urlParts['path']) ? $urlParts['path'] : '/';
790 1229 if (isset($urlParts['query'])) {
791 1230 $path .= '?' . $urlParts['query'];
792 1231 }
793 -
1232 +
794 1233 $postString = http_build_query($params);
795 1234
796 1235 $host = $urlParts['host'];
797 1236 $scheme = isset($urlParts['scheme']) ? $urlParts['scheme'] : 'http';
@@ -814,9 +1253,9 @@
814 1253 } else {
815 1254 // If fsockopen fails, fallback to wp_remote_post
816 1255 $args = array(
817 1256 'timeout' => 0.01,
818 - 'headers' => array(
1257 + 'headers' => array(
819 1258 'User-Agent' => $userAgent,
820 1259 ),
821 1260 'body' => $params
822 1261 );
@@ -824,12 +1263,13 @@
824 1263 wp_remote_post($url, $args);
825 1264 }
826 1265 }
827 1266
828 -function bwp_is_webpage() {
1267 +function bwp_is_webpage()
1268 +{
829 1269 $headers = headers_list();
830 1270 $contentType = '';
831 -
1271 +
832 1272 foreach ($headers as $header) {
833 1273 if (stripos($header, 'Content-Type') !== false) {
834 1274 $contentType = $header;
835 1275 break;
@@ -840,5 +1280,1081 @@
840 1280 return true;
841 1281 }
842 1282
843 1283 return false;
1284 +}
1285 +
1286 +function bwp_isGzipEncoded()
1287 +{
1288 + // Check if the Content-Encoding header is set to gzip
1289 + if (isset($_SERVER['HTTP_CONTENT_ENCODING']) && strtolower($_SERVER['HTTP_CONTENT_ENCODING']) === 'gzip') {
1290 + return true;
1291 + }
1292 +
1293 + foreach (headers_list() as $header) {
1294 + if (stripos($header, 'Content-Encoding: gzip') !== false) {
1295 + return true;
1296 + }
1297 + }
1298 +
1299 + return false;
1300 +}
1301 +
1302 +function bwp_sluguri_into_path($slug_uri)
1303 +{
1304 + $is_multisite = function_exists('is_multisite') && is_multisite();
1305 + $home_path = parse_url(home_url(), PHP_URL_PATH);
1306 +
1307 + // if (berqwp_is_sub_dir_wp() && !$is_multisite) {
1308 + if (!$is_multisite && $home_path !== null) {
1309 + // Parse strings to extract paths
1310 + $path1 = explode('/', $home_path);
1311 + $path2 = explode('/', parse_url($slug_uri, PHP_URL_PATH));
1312 +
1313 + // Find the common part of the paths
1314 + $commonPath = implode('/', array_intersect($path1, $path2));
1315 +
1316 + // Subtract the common part from the first string
1317 + $slug_uri = str_replace($commonPath, '', $slug_uri);
1318 + }
1319 +
1320 + return $slug_uri;
1321 +}
1322 +
1323 +function bwp_url_into_path($url)
1324 +{
1325 + $parsed_url = parse_url($url);
1326 + $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
1327 + $query = isset($parsed_url['query']) ? $parsed_url['query'] : '';
1328 + $homeurl = home_url();
1329 +
1330 + if (!empty($query)) {
1331 + $path = $path . '?' . $query;
1332 + }
1333 +
1334 + $is_multisite = function_exists('is_multisite') && is_multisite();
1335 + $home_path = parse_url($homeurl, PHP_URL_PATH);
1336 +
1337 + if (!$is_multisite && $home_path !== null) {
1338 + // Parse strings to extract paths
1339 + $path1 = explode('/', $home_path);
1340 + $path2 = explode('/', parse_url($path, PHP_URL_PATH));
1341 +
1342 + // Find the common part of the paths
1343 + $commonPath = implode('/', array_intersect($path1, $path2));
1344 +
1345 + // Subtract the common part from the first string
1346 + $path = str_replace($commonPath, '', $path);
1347 + }
1348 +
1349 + // $path = bwp_intersect_str(bwp_admin_home_url(), $path);
1350 +
1351 + return $path;
1352 +}
1353 +
1354 +function bwp_get_cache_dir()
1355 +{
1356 + $cache_directory = optifer_cache . 'html/';
1357 +
1358 + if (function_exists('is_multisite') && is_multisite()) {
1359 + $site_id = get_current_blog_id();
1360 + $cache_directory .= 'site-' . $site_id . '/';
1361 + }
1362 +
1363 + if (!is_dir($cache_directory)) {
1364 + wp_mkdir_p($cache_directory);
1365 + }
1366 +
1367 + return $cache_directory;
1368 +}
1369 +
1370 +function bwp_get_static_cache_dir()
1371 +{
1372 + $dir = optifer_cache . 'static/';
1373 +
1374 + if (function_exists('is_multisite') && is_multisite()) {
1375 + $dir .= 'site-' . get_current_blog_id() . '/';
1376 + }
1377 +
1378 + if (!is_dir($dir)) {
1379 + wp_mkdir_p($dir);
1380 + }
1381 +
1382 + return $dir;
1383 +}
1384 +
1385 +function bwp_webhook()
1386 +{
1387 + require_once optifer_PATH . '/api/webhook.php';
1388 +}
1389 +
1390 +function bwp_update_configs_webhook()
1391 +{
1392 + require_once optifer_PATH . '/api/update_configs.php';
1393 +}
1394 +
1395 +function bwp_check_status_webhook()
1396 +{
1397 + require_once optifer_PATH . '/api/check_status.php';
1398 +}
1399 +
1400 +function bwp_handle_request_cache()
1401 +{
1402 + require_once optifer_PATH . '/api/request_cache.php';
1403 +}
1404 +
1405 +function bwp_get_translatepress_urls($page_url)
1406 +{
1407 + $trp = TRP_Translate_Press::get_trp_instance();
1408 + $trp_settings = get_option('trp_settings', array());
1409 + $languages = $trp->get_component('languages');
1410 + $url_converter = $trp->get_component('url_converter');
1411 + $publish_languages = $languages->get_language_names($trp_settings['publish-languages'], 'english_name');
1412 + $urls = [];
1413 +
1414 +
1415 + if (!empty($publish_languages)) {
1416 + foreach ($publish_languages as $key => $value) {
1417 + $translation_url = $url_converter->get_url_for_language($key, $page_url, '');
1418 + $urls[] = $translation_url;
1419 + }
1420 + }
1421 +
1422 + return $urls;
1423 +}
1424 +
1425 +function bwp_can_optimize_page_url($page_url)
1426 +{
1427 + $slug = bwp_url_into_path($page_url);
1428 + if (berqwp_is_slug_excludable($slug)) {
1429 + return false;
1430 + }
1431 +
1432 + if (berqwp_is_page_url_excluded($page_url)) {
1433 + return false;
1434 + }
1435 +
1436 + return true;
1437 +}
1438 +
1439 +function bwp_get_sitemap()
1440 +{
1441 + if (isset($_GET['berqwp_sitemap'])) {
1442 +
1443 +
1444 + // Get post types to optimize
1445 + $post_types = get_option('berqwp_optimize_post_types');
1446 +
1447 + $post_types = apply_filters('berqwp_warmup_post_types', $post_types);
1448 + $rewrite_map = apply_filters('berqwp_warmup_post_types_rewrite_map', []);
1449 +
1450 + // Set the number of posts per batch to handle
1451 + $posts_per_page = 10000; // Adjust this based on server capacity
1452 +
1453 + // Get current page from query string (for pagination)
1454 + $paged = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
1455 +
1456 + // Build the query arguments with pagination
1457 + $args = array(
1458 + 'post_type' => $post_types,
1459 + 'post_status' => array('publish'), // Only published posts
1460 + 'posts_per_page' => $posts_per_page,
1461 + 'paged' => $paged,
1462 + 'fields' => 'ids', // Only retrieve IDs to save memory
1463 + );
1464 +
1465 + // Run the query
1466 + $query = new WP_Query($args);
1467 + $total_posts = $query->found_posts; // Get the total number of posts
1468 +
1469 + // Calculate total pages
1470 + $total_pages = ceil($total_posts / $posts_per_page);
1471 +
1472 + // Output JSON header
1473 + header('Content-Type: application/json');
1474 +
1475 + $post_params = berqwp_get_page_params('/');
1476 + unset($post_params['license_key']);
1477 + unset($post_params['page_slug']);
1478 + unset($post_params['page_url']);
1479 + $post_params['key'] = '';
1480 +
1481 + $berqconfigs = berqConfigs::getInstance();
1482 + $configs = $berqconfigs->get_configs();
1483 + $post_params['cache_lifespan'] = $configs['cache_lifespan'];
1484 + $post_params['sandbox'] = get_option('berqwp_enable_sandbox');
1485 +
1486 + if ($query->have_posts()) {
1487 + $sitemap_urls = [];
1488 +
1489 + if (!isset($_GET['configs_only'])) {
1490 +
1491 + if (get_option('show_on_front') !== 'page') {
1492 + $sitemap_urls[] = home_url('/');
1493 + }
1494 +
1495 + // Loop through the posts and generate URLs
1496 + while ($query->have_posts()) {
1497 + $query->the_post();
1498 +
1499 + $post_id = get_the_ID();
1500 + $post_type = get_post_field( 'post_type', $post_id );
1501 + $url = get_permalink( $post_id );
1502 +
1503 + // Fallback for MB CPTs whose rewrite rules aren't loaded (post type not registered)
1504 + if ( strpos( $url, '?' ) !== false && isset( $rewrite_map[ $post_type ] ) ) {
1505 + $post_name = get_post_field( 'post_name', $post_id );
1506 + $url = trailingslashit( home_url( '/' . $rewrite_map[ $post_type ] . '/' . $post_name ) );
1507 + }
1508 +
1509 + // SEO Generator
1510 + if (class_exists('NSG_Seo_Generator')) {
1511 + $nsg = NSG_Seo_Generator::get_instance();
1512 + $slugs = $nsg->nsg_get_seo_page_slugs( $post_id );
1513 +
1514 + if ( is_array( $slugs ) ) {
1515 + foreach ( $slugs as $slug ) {
1516 + $generated_url = trailingslashit( $url ) . $slug . '/';
1517 +
1518 + if (bwp_can_optimize_page_url($generated_url)) {
1519 + $sitemap_urls[] = $generated_url;
1520 + }
1521 + }
1522 + }
1523 + }
1524 +
1525 + $translation_urls = apply_filters('berqwp_page_translation_urls', [], $url);
1526 +
1527 + if (!bwp_can_optimize_page_url($url)) {
1528 + continue;
1529 + }
1530 +
1531 + if (!in_array($url, $sitemap_urls)) {
1532 + $sitemap_urls[] = $url;
1533 + }
1534 +
1535 + if (!empty($translation_urls)) {
1536 + foreach ($translation_urls as $page_url) {
1537 + if (!bwp_can_optimize_page_url($page_url)) {
1538 + continue;
1539 + }
1540 +
1541 + if (!in_array($page_url, $sitemap_urls)) {
1542 + $sitemap_urls[] = $page_url;
1543 + }
1544 + }
1545 + }
1546 + }
1547 + }
1548 +
1549 + // Return response with pagination info
1550 + $response = array(
1551 + 'paged' => $paged,
1552 + 'post_params' => $post_params,
1553 + 'total_pages' => $total_pages,
1554 + 'total_posts' => $total_posts,
1555 + 'urls' => $sitemap_urls,
1556 + );
1557 +
1558 + echo json_encode($response);
1559 + } else {
1560 + // If no posts found
1561 + echo json_encode(array('error' => 'No posts found'));
1562 + }
1563 +
1564 + // Clean up
1565 + wp_reset_postdata();
1566 + exit;
1567 + }
1568 +}
1569 +
1570 +function bwp_show_account()
1571 +{
1572 + if (!defined('BERQWP_HIDE_ACCOUNT')) {
1573 + return true;
1574 + }
1575 +
1576 + if (defined('BERQWP_HIDE_ACCOUNT') && BERQWP_HIDE_ACCOUNT) {
1577 + return false;
1578 + }
1579 +
1580 + return true;
1581 +}
1582 +
1583 +function bwp_show_docs()
1584 +{
1585 +
1586 + if (!defined('BERQWP_HIDE_DOCS')) {
1587 + return true;
1588 + }
1589 +
1590 + if (defined('BERQWP_HIDE_DOCS') && BERQWP_HIDE_DOCS) {
1591 + return false;
1592 + }
1593 +
1594 + return true;
1595 +}
1596 +
1597 +function bwp_admin_home_url($relative_path = '')
1598 +{
1599 + $home_url = home_url();
1600 +
1601 + if (class_exists('TRP_Translate_Press')) {
1602 + $trp = TRP_Translate_Press::get_trp_instance();
1603 + $trp_settings = get_option('trp_settings', array());
1604 + $default_lang = $trp_settings['default-language'];
1605 + $url_converter = $trp->get_component('url_converter');
1606 + $url_slugs = $trp_settings['url-slugs'];
1607 +
1608 + if (!empty($default_lang) && $trp_settings['add-subdirectory-to-default-language'] == 'yes' && !empty($url_slugs[$default_lang]) && strpos($home_url, "/$url_slugs[$default_lang]") === false) {
1609 + // var_dump($trp_settings);
1610 + return $home_url . '/' . $url_slugs[$default_lang] . $relative_path;
1611 + }
1612 + }
1613 +
1614 + return $home_url . $relative_path;
1615 +}
1616 +
1617 +function bwp_intersect_str($str1, $str2)
1618 +{
1619 + $arr = explode('/', $str1);
1620 + $last_item = $arr[count($arr) - 1]; // Get last item from $arr
1621 + $arr2 = explode('/', $str2);
1622 +
1623 + if (!empty($arr2) && strpos($str2, $last_item) !== false) {
1624 +
1625 + for ($i = 1; $i < count($arr2); $i++) {
1626 + if (!empty($arr2[$i]) && $arr2[$i] == $last_item) {
1627 + unset($arr2[$i]);
1628 + }
1629 + }
1630 +
1631 + $str2 = implode('/', $arr2);
1632 + }
1633 +
1634 + return $str2;
1635 +}
1636 +
1637 +function bwp_is_tab($tab_id)
1638 +{
1639 + $default_tab = 'dashboard';
1640 +
1641 + if (!empty($_GET['tab_id'])) {
1642 + if (sanitize_text_field($_GET['tab_id']) == $tab_id) {
1643 + // echo ' style="display:block" ';
1644 + echo ' style="visibility:visible;opacity:1;height:auto;display:block;" ';
1645 + } else {
1646 + // echo ' style="display:none" ';
1647 + echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;display:none;" ';
1648 + }
1649 + } else {
1650 +
1651 + if ($tab_id == $default_tab) {
1652 + // echo ' style="display:block" ';
1653 + echo ' style="visibility:visible;opacity:1;height:auto;display:block;" ';
1654 + } else {
1655 + // echo ' style="display:none" ';
1656 + echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;display:none;" ';
1657 + }
1658 + }
1659 +}
1660 +
1661 +function bwp_is_tab_nav($tab_id)
1662 +{
1663 + $default_tab = 'dashboard';
1664 +
1665 + if (!empty($_GET['tab_id'])) {
1666 + if (sanitize_text_field($_GET['tab_id']) == $tab_id) {
1667 + echo ' active ';
1668 + }
1669 + } else {
1670 +
1671 + if ($tab_id == $default_tab) {
1672 + echo ' active ';
1673 + }
1674 + }
1675 +}
1676 +
1677 +function bwp_notice($status = '', $title = null, $message = null, $btn = [], $dismissible = false)
1678 +{
1679 +?>
1680 + <div
1681 + class="bwp-notice <?php echo 'status-' . esc_attr($status); ?> <?php echo $dismissible ? 'dismissible' : ''; ?> <?php echo empty($title) ? 'no-title' : ''; ?>">
1682 + <?php if ($dismissible) { ?>
1683 + <div class="close"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px"
1684 + fill="#000">
1685 + <path
1686 + d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z" />
1687 + </svg></div>
1688 + <?php } ?>
1689 +
1690 + <div class="icon"><svg width="30" height="30" viewBox="0 0 24 24" fill="#fff" xmlns="http://www.w3.org/2000/svg">
1691 + <path fill-rule="evenodd" clip-rule="evenodd"
1692 + 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"
1693 + fill="#1f72ff" />
1694 + </svg></div>
1695 + <div class="content">
1696 + <div class="status-tag"><?php echo esc_html($status); ?></div>
1697 + <?php if (!empty($title)) { ?>
1698 + <h5><?php echo wp_kses_post($title); ?></h5>
1699 + <?php } ?>
1700 +
1701 + <?php if (!empty($message)) { ?>
1702 + <?php echo wp_kses_post($message); ?>
1703 + <?php } ?>
1704 +
1705 + <?php if (!empty($btn) && is_array($btn)) { ?>
1706 + <div class="bwp-notice-btn">
1707 + <?php
1708 + foreach ($btn as $bwp_btn) {
1709 + if (empty($bwp_btn['target'])) {
1710 + $bwp_btn['target'] = '';
1711 + }
1712 +
1713 + if (empty($bwp_btn['href'])) {
1714 + $bwp_btn['href'] = '';
1715 + }
1716 +
1717 + if (empty($bwp_btn['classes'])) {
1718 + $bwp_btn['classes'] = '';
1719 + }
1720 +
1721 + if (empty($bwp_btn['text'])) {
1722 + $bwp_btn['text'] = '';
1723 + }
1724 + ?>
1725 + <a target="<?php echo esc_attr($bwp_btn['target']) ?? ''; ?>"
1726 + href="<?php echo esc_attr($bwp_btn['href']) ?? ''; ?>"
1727 + class="bwp-btn <?php echo esc_attr($bwp_btn['classes']) ?? ''; ?>">
1728 + <?php echo esc_html($bwp_btn['text']); ?>
1729 + </a>
1730 + <?php
1731 + }
1732 + ?>
1733 + </div>
1734 + <?php } ?>
1735 + </div>
1736 + </div>
1737 +<?php
1738 +}
1739 +
1740 +function bwp_is_option_updated($option_name)
1741 +{
1742 + $value = isset($_POST[$option_name]) ? $_POST[$option_name] : 0;
1743 +
1744 + if ($value == 'on') {
1745 + $value = 1;
1746 + }
1747 +
1748 + $option_val = get_option($option_name);
1749 + $array_options = [
1750 + 'berq_exclude_js_css',
1751 + 'berq_exclude_cdn',
1752 + 'berqwp_force_include_critical_css',
1753 + 'berqwp_exclude_lazy_load_images',
1754 + 'berqwp_exclude_third_party_js',
1755 + 'berqwp_exclude_js',
1756 + 'berqwp_exclude_css',
1757 + ];
1758 +
1759 + if (in_array($option_name, $array_options)) {
1760 + $urls = sanitize_textarea_field($value);
1761 + $urls_array = explode("\n", $urls);
1762 +
1763 + $urls_array = array_map(function ($kw) {
1764 + return trim($kw);
1765 + }, $urls_array);
1766 +
1767 + $urls_array = array_filter($urls_array, function ($kw) {
1768 + return !empty($kw);
1769 + });
1770 +
1771 + if (!is_array($option_val)) {
1772 + $option_val = [];
1773 + }
1774 +
1775 + // var_dump($option_val, $urls_array, array_diff($option_val, $urls_array), array_diff($option_val, $urls_array));
1776 + // exit;
1777 +
1778 + return !empty(array_diff($option_val, $urls_array));
1779 + }
1780 +
1781 + $values_changed = $option_val == $value;
1782 +
1783 + return !$values_changed;
1784 +}
1785 +
1786 +function bwp_request_purge_license_key_cache()
1787 +{
1788 +
1789 + $license_key = berqwp_get_license_key();
1790 + $parsed_url = parse_url(home_url());
1791 + $domain = $parsed_url['host'];
1792 +
1793 + if (empty($domain) || empty($license_key)) {
1794 + return;
1795 + }
1796 +
1797 + wp_remote_post(BerqWP::$endpoint."license/flush", [
1798 + 'timeout' => 30,
1799 + 'body' => [
1800 + 'domain' => $domain,
1801 + 'license_key' => $license_key,
1802 + 'site_url' => home_url(),
1803 + ]
1804 + ]);
1805 +
1806 +}
1807 +
1808 +function bwp_display_logs()
1809 +{
1810 +
1811 + if (isset($_GET['berqwp_logs'])) {
1812 +
1813 + // Check if the current user is logged in and has admin privileges
1814 + if (!is_user_logged_in() || !current_user_can('administrator')) {
1815 + wp_die(__('You are not allowed to access this page.', 'searchpro'));
1816 + }
1817 +
1818 + // Define the path to the BerqWP logs file
1819 + $log_file_path = optifer_cache . '/logs/berqwp.log'; // Adjust path if needed
1820 +
1821 + // Check if the log file exists
1822 + if (!file_exists($log_file_path)) {
1823 + echo '<div>No logs available. The log file does not exist.</div>';
1824 + exit;
1825 + }
1826 +
1827 + // Read and display the log file content
1828 + $logs = file_get_contents($log_file_path);
1829 +
1830 + if ($logs === false) {
1831 + echo '<div>Unable to read the log file.</div>';
1832 + exit;
1833 + }
1834 +
1835 + echo '<h2>BerqWP Logs</h2>';
1836 + echo '<pre style="background:#f4f4f4;padding:15px;border:1px solid #ddd;">' . esc_html($logs) . '</pre>';
1837 + exit;
1838 + }
1839 +}
1840 +
1841 +function bwp_cf_flush_all()
1842 +{
1843 + if (!empty(get_option('berqwp_cf_creden'))) {
1844 + $email = get_option('berqwp_cf_creden')['email'];
1845 + $apitoken = get_option('berqwp_cf_creden')['apitoken'];
1846 + $zoneid = get_option('berqwp_cf_creden')['zoneid'];
1847 +
1848 + $berqCloudflareAPIHandler = new berqCloudflareAPIHandler($email, $apitoken, $zoneid);
1849 + $berqCloudflareAPIHandler->purge_all_cache();
1850 + }
1851 +}
1852 +
1853 +function bwp_cf_flush_page($url)
1854 +{
1855 + if (!empty(get_option('berqwp_cf_creden'))) {
1856 + $email = get_option('berqwp_cf_creden')['email'];
1857 + $apitoken = get_option('berqwp_cf_creden')['apitoken'];
1858 + $zoneid = get_option('berqwp_cf_creden')['zoneid'];
1859 +
1860 + $berqCloudflareAPIHandler = new berqCloudflareAPIHandler($email, $apitoken, $zoneid);
1861 + $berqCloudflareAPIHandler->flush_url($url);
1862 + }
1863 +}
1864 +
1865 +function bwp_cf_delete_rules()
1866 +{
1867 + if (!empty(get_option('berqwp_cf_creden'))) {
1868 + $email = get_option('berqwp_cf_creden')['email'];
1869 + $apitoken = get_option('berqwp_cf_creden')['apitoken'];
1870 + $zoneid = get_option('berqwp_cf_creden')['zoneid'];
1871 +
1872 + $berqCloudflareAPIHandler = new berqCloudflareAPIHandler($email, $apitoken, $zoneid);
1873 + $berqCloudflareAPIHandler->delete_rule_by_description('BerqWP cache rules');
1874 + }
1875 +}
1876 +
1877 +function bwp_lock_cache_directory()
1878 +{
1879 + $cache_dir = optifer_cache;
1880 +
1881 + if (!file_exists($cache_dir)) {
1882 + wp_mkdir_p($cache_dir);
1883 + }
1884 +
1885 + $rules = <<<HTACCESS
1886 +Order allow,deny
1887 +Deny from all
1888 +
1889 +<FilesMatch "index\.html\.gz$">
1890 + Order allow,deny
1891 + Allow from all
1892 +</FilesMatch>
1893 +
1894 +# Block PHP execution and dot-files to prevent webshell deployment
1895 +<FilesMatch "\.php\d*$|\.phtml$|\.phar$">
1896 + Order allow,deny
1897 + Deny from all
1898 +</FilesMatch>
1899 +<FilesMatch "^\.">
1900 + Order allow,deny
1901 + Deny from all
1902 +</FilesMatch>
1903 +HTACCESS;
1904 +
1905 + file_put_contents($cache_dir . '.htaccess', $rules);
1906 +
1907 + // Suppress directory listing
1908 + $index_stub = $cache_dir . 'index.php';
1909 + if (!file_exists($index_stub)) {
1910 + file_put_contents($index_stub, '<?php // Silence is golden');
1911 + }
1912 +}
1913 +
1914 +function bwp_write_htaccess_rules($ignore_sandbox = false)
1915 +{
1916 + if (!got_mod_rewrite() || bwp_is_openlitespeed_server()) {
1917 + return;
1918 + }
1919 +
1920 + if (!$ignore_sandbox && get_option('berqwp_enable_sandbox') == 1) {
1921 + return;
1922 + }
1923 +
1924 + $htaccess = get_home_path() . '.htaccess';
1925 + $cache_tag_host = parse_url(home_url(), PHP_URL_HOST);
1926 +
1927 + $rules = [
1928 + '<IfModule mod_rewrite.c>',
1929 + ' RewriteEngine On',
1930 + ' RewriteCond %{REQUEST_METHOD} !POST',
1931 + ' RewriteCond %{QUERY_STRING} ^$',
1932 + ' RewriteCond %{HTTP_COOKIE} !(wp\-postpass|wordpress_logged_in|comment_author|woocommerce_cart_hash|edd_items_in_cart) [NC]',
1933 + ' 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]',
1934 + ' RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/berqwp/html/%{HTTP_HOST}%{REQUEST_URI}/index.html.gz -f',
1935 + ' RewriteRule .* /wp-content/cache/berqwp/html/%{HTTP_HOST}%{REQUEST_URI}/index.html.gz [L]',
1936 + '</IfModule>',
1937 + '<IfModule mod_mime.c>',
1938 + ' <FilesMatch "index\.html\.gz$">',
1939 + ' ForceType text/html',
1940 + ' AddEncoding gzip .gz',
1941 + ' AddDefaultCharset utf-8',
1942 + ' </FilesMatch>',
1943 + '</IfModule>',
1944 + '<IfModule mod_headers.c>',
1945 + ' <FilesMatch "index\.html\.gz$">',
1946 + ' Header set X-BerqWP-Cache "HIT"',
1947 + ' Header set X-Served "server"',
1948 + ' Header set Content-Encoding "gzip"',
1949 + ' Header set Vary "Accept-Encoding, Cookie"',
1950 + ' Header set CDN-Cache-Control "max-age=2592000"',
1951 + ' Header set Cache-Control "public, max-age=600, s-maxage=2592000, stale-while-revalidate=86400"',
1952 + ' Header set Cache-Tag "' . $cache_tag_host . '"',
1953 + ' Header set X-Content-Type-Options "nosniff"',
1954 + ' </FilesMatch>',
1955 + '</IfModule>',
1956 + '<IfModule mod_expires.c>',
1957 + ' ExpiresActive On',
1958 + ' ExpiresByType text/css "access plus 1 year"',
1959 + ' ExpiresByType application/javascript "access plus 1 year"',
1960 + ' ExpiresByType text/javascript "access plus 1 year"',
1961 + ' ExpiresByType image/jpeg "access plus 1 year"',
1962 + ' ExpiresByType image/png "access plus 1 year"',
1963 + ' ExpiresByType image/gif "access plus 1 year"',
1964 + ' ExpiresByType image/webp "access plus 1 year"',
1965 + ' ExpiresByType image/avif "access plus 1 year"',
1966 + ' ExpiresByType image/svg+xml "access plus 1 year"',
1967 + ' ExpiresByType image/x-icon "access plus 1 year"',
1968 + ' ExpiresByType font/woff "access plus 1 year"',
1969 + ' ExpiresByType font/woff2 "access plus 1 year"',
1970 + ' ExpiresByType application/font-woff "access plus 1 year"',
1971 + ' ExpiresByType application/font-woff2 "access plus 1 year"',
1972 + ' ExpiresByType application/x-font-ttf "access plus 1 year"',
1973 + ' ExpiresByType application/x-font-opentype "access plus 1 year"',
1974 + '</IfModule>',
1975 + '<IfModule mod_headers.c>',
1976 + ' <FilesMatch "\.(css|js)$">',
1977 + ' Header set Cache-Control "public, max-age=31536000, immutable"',
1978 + ' </FilesMatch>',
1979 + ' <FilesMatch "\.(jpg|jpeg|png|gif|webp|avif|svg|ico)$">',
1980 + ' Header set Cache-Control "public, max-age=31536000, immutable"',
1981 + ' </FilesMatch>',
1982 + ' <FilesMatch "\.(woff|woff2|ttf|otf|eot)$">',
1983 + ' Header set Cache-Control "public, max-age=31536000, immutable"',
1984 + ' Header set Access-Control-Allow-Origin "*"',
1985 + ' </FilesMatch>',
1986 + '</IfModule>',
1987 + ];
1988 +
1989 + // Must appear before the WordPress block so Apache processes it first
1990 + $marker = 'BerqWP Cache';
1991 + $start = "# BEGIN $marker";
1992 + $end = "# END $marker";
1993 + $wp_start = '# BEGIN WordPress';
1994 +
1995 + $block = $start . "\n";
1996 + $block .= implode("\n", $rules) . "\n";
1997 + $block .= $end . "\n";
1998 +
1999 + $contents = file_exists($htaccess) ? file_get_contents($htaccess) : '';
2000 +
2001 + // Remove all existing BerqWP Cache blocks (handles duplicates and corrupt state)
2002 + $contents = preg_replace(
2003 + '/^# BEGIN BerqWP Cache.*?^# END BerqWP Cache\s*/ms',
2004 + '',
2005 + $contents
2006 + );
2007 +
2008 + // Insert before first WordPress block if present, otherwise prepend
2009 + if (strpos($contents, $wp_start) !== false) {
2010 + $contents = preg_replace('/' . preg_quote($wp_start, '/') . '/', $block . "\n" . $wp_start, $contents, 1);
2011 + } else {
2012 + $contents = $block . "\n" . $contents;
2013 + }
2014 +
2015 + file_put_contents($htaccess, $contents);
2016 +}
2017 +
2018 +function bwp_remove_htaccess_rules()
2019 +{
2020 + $htaccess = get_home_path() . '.htaccess';
2021 +
2022 + if (!file_exists($htaccess)) {
2023 + return;
2024 + }
2025 +
2026 + $contents = file_get_contents($htaccess);
2027 + $contents = preg_replace('/^# BEGIN BerqWP Cache.*?^# END BerqWP Cache\s*/ms', '', $contents);
2028 + file_put_contents($htaccess, $contents);
2029 +}
2030 +
2031 +function bwp_sync_htaccess_on_sandbox_change()
2032 +{
2033 + // Action fires before update_option, so check the incoming POST value
2034 + $sandbox_enabling = isset($_POST['berqwp_enable_sandbox']);
2035 +
2036 + if ($sandbox_enabling) {
2037 + bwp_remove_htaccess_rules();
2038 + } else {
2039 + bwp_write_htaccess_rules(true);
2040 + }
2041 +}
2042 +
2043 +function berqwp_is_wp_cron_broken()
2044 +{
2045 + $cron = _get_cron_array();
2046 + if (!$cron || !is_array($cron))
2047 + return false;
2048 +
2049 + $now = time();
2050 + foreach ($cron as $timestamp => $events) {
2051 + if ($timestamp < $now - 300) { // 5 minutes overdue
2052 + return true;
2053 + }
2054 + }
2055 + return false;
2056 +}
2057 +
2058 +function berqwp_is_page_url_excluded($page_url)
2059 +{
2060 + if (empty($page_url)) {
2061 + return false;
2062 + }
2063 +
2064 + $pages_to_exclude = get_option('berq_exclude_urls', []);
2065 +
2066 + if (strpos($page_url, '?') !== false) {
2067 + $page_url = explode('?', $page_url)[0];
2068 + }
2069 +
2070 + if (in_array($page_url, $pages_to_exclude)) {
2071 + return true;
2072 + }
2073 +
2074 + if (!empty($pages_to_exclude)) {
2075 + foreach ($pages_to_exclude as $single_page_url) {
2076 +
2077 + if (empty($single_page_url)) {
2078 + continue;
2079 + }
2080 +
2081 + if (substr($single_page_url, -1) !== '*') {
2082 + continue;
2083 + }
2084 +
2085 + $single_page_url = str_replace('*', '', $single_page_url);
2086 +
2087 + if (strpos($page_url, $single_page_url) !== false) {
2088 + return true;
2089 + }
2090 + }
2091 + }
2092 +
2093 + return false;
2094 +}
2095 +
2096 +// function berqwp_appendHtmlToBody($buffer, $htmlToAppend)
2097 +// {
2098 +// // Load the $buffer content into Simple HTML DOM
2099 +// $html = HtmlDomParser::str_get_html($buffer);
2100 +
2101 +// if (!$html) {
2102 +// return $buffer;
2103 +// }
2104 +
2105 +// // Find the <body> tag
2106 +// $body = $html->find('body', 0);
2107 +
2108 +// // If the body tag exists, append the new HTML
2109 +// if ($body) {
2110 +// // Use htmlspecialchars to properly encode the inserted content
2111 +// // Avoid breaking the HTML by not using innerhtml directly
2112 +// $body->innertext .= $htmlToAppend;
2113 +// } else {
2114 +// // If no body tag exists, append the HTML to the document directly
2115 +// $html->innertext .= $htmlToAppend;
2116 +// }
2117 +
2118 +// // Return the modified HTML content
2119 +// return $html->save();
2120 +// }
2121 +//
2122 +function berqwp_appendHtmlToBody($buffer, $htmlToAppend)
2123 +{
2124 + $pos = strripos($buffer, '</body>');
2125 + if ($pos !== false) {
2126 + return substr_replace($buffer, $htmlToAppend, $pos, 0);
2127 + }
2128 +
2129 + // Fallback: try before </html>
2130 + $pos = strripos($buffer, '</html>');
2131 + if ($pos !== false) {
2132 + return substr_replace($buffer, $htmlToAppend, $pos, 0);
2133 + }
2134 +
2135 + // Last resort: append to end
2136 + return $buffer . $htmlToAppend;
2137 +}
2138 +
2139 +function berqwp_appendHtmlToHead($buffer, $htmlToAppend)
2140 +{
2141 + $pos = stripos($buffer, '</head>');
2142 + if ($pos !== false) {
2143 + $buffer = substr_replace($buffer, PHP_EOL . $htmlToAppend, $pos, 0);
2144 + }
2145 +
2146 + // Fix missing </body> tag
2147 + if (stripos($buffer, '</body>') === false) {
2148 + $buffer = str_replace('</html>', '</body>' . PHP_EOL . '</html>', $buffer);
2149 + }
2150 +
2151 + return $buffer;
2152 +}
2153 +
2154 +function berqwp_prependHtmlToHead($buffer, $htmlToPrepend)
2155 +{
2156 + if (preg_match('/<head(\s[^>]*)?>/i', $buffer, $matches, PREG_OFFSET_CAPTURE)) {
2157 + $insertPos = $matches[0][1] + strlen($matches[0][0]);
2158 + return substr_replace($buffer, PHP_EOL . $htmlToPrepend, $insertPos, 0);
2159 + }
2160 +
2161 + // Fallback: no <head> tag found, return unchanged
2162 + return $buffer;
2163 +}
2164 +
2165 +function berqwp_setup_dropin()
2166 +{
2167 + if (defined('BERQWP_ADVANCED_CACHE_PATH')) {
2168 + $adv_cache_path = BERQWP_ADVANCED_CACHE_PATH;
2169 + } else {
2170 + $adv_cache_path = WP_CONTENT_DIR . '/advanced-cache.php';
2171 + }
2172 +
2173 + // Remove advanced-cache.php when sandbox mode is enabled
2174 + if (get_option('berqwp_enable_sandbox') == 1) {
2175 +
2176 + if (file_exists($adv_cache_path)) {
2177 + @unlink($adv_cache_path);
2178 + }
2179 +
2180 + return;
2181 + }
2182 +
2183 + $bwp_adv_cache = optifer_PATH . 'advanced-cache.php';
2184 +
2185 + if (!file_exists($adv_cache_path) || (file_exists($adv_cache_path) && is_writable($adv_cache_path))) {
2186 + if (
2187 + (!file_exists($adv_cache_path) && get_option('berqwp_enable_sandbox') !== 1)
2188 + || (file_exists($adv_cache_path) && md5_file($adv_cache_path) !== md5_file($bwp_adv_cache))
2189 + ) {
2190 +
2191 + // Dynamically create the drop-in file
2192 + $dropin_content = file_get_contents(optifer_PATH . 'advanced-cache.php');
2193 +
2194 + // Write the drop-in content to the file, replacing any existing file
2195 + file_put_contents($adv_cache_path, $dropin_content);
2196 +
2197 + // Enable wp cache in wp-config.php
2198 + berqwp_enable_advanced_cache(true);
2199 + }
2200 + }
2201 +
2202 +
2203 + // if (get_option('berqwp_enable_sandbox') == 1 && file_exists($adv_cache_path)) {
2204 + // unlink($adv_cache_path);
2205 + // }
2206 +}
2207 +
2208 +function berqwp_is_file_url($url)
2209 +{
2210 + $parsed = parse_url($url);
2211 + if (!isset($parsed['path']))
2212 + return false;
2213 +
2214 + $extension = pathinfo($parsed['path'], PATHINFO_EXTENSION);
2215 +
2216 + // allow html pages
2217 + if (strtolower($extension) === 'html' || strtolower($extension) === 'htm') {
2218 + return false;
2219 + }
2220 +
2221 + // Returns true if there is a file extension, false otherwise
2222 + return !empty($extension);
2223 +}
2224 +
2225 +function berqwp_clear_cache_queue()
2226 +{
2227 + $berqconfigs = berqConfigs::getInstance();
2228 + $site_id = $berqconfigs->get_configs()['site_id'];
2229 + $berqwp = new BerqWP(berqwp_get_license_key(), null, null);
2230 + $berqwp->clear_cache_queue(home_url(), $site_id);
2231 +}
2232 +
2233 +function berqwp_sync_addons($license_key, $site_url)
2234 +{
2235 + if (empty($license_key) || empty($site_url)) {
2236 + return false;
2237 + }
2238 +
2239 + $post_data = [
2240 + 'license_key' => $license_key,
2241 + 'site_url' => $site_url,
2242 + ];
2243 +
2244 + $args = array(
2245 + 'body' => wp_json_encode($post_data),
2246 + 'method' => 'POST',
2247 + 'timeout' => 20,
2248 + 'headers' => array(
2249 + 'Content-Type' => 'application/json',
2250 + ),
2251 + );
2252 +
2253 + global $berq_log;
2254 + $berq_log->info("Trigger addon sync");
2255 +
2256 + $response = wp_remote_post('https://berqwp.com/wp-json/berqwp/active-addons', $args);
2257 + $response_body = wp_remote_retrieve_body($response);
2258 + $json = json_decode($response_body, true);
2259 +
2260 + if (empty($json) || $json['status'] !== 'success') {
2261 + return false;
2262 + }
2263 +
2264 + if (is_array($json['active_addons'])) {
2265 +
2266 + $enable_fluid_images = in_array('fluid_images', $json['active_addons']);
2267 + if ($enable_fluid_images && !get_option('berqwp_can_use_fluid_images')) {
2268 + update_option('berqwp_can_use_fluid_images', 1);
2269 + update_option('bwp_require_flush_cache', 1);
2270 + } elseif (!$enable_fluid_images) {
2271 + update_option('berqwp_can_use_fluid_images', 0);
2272 + }
2273 + }
2274 +}
2275 +
2276 +function berqwp_validate_url_array($urls)
2277 +{
2278 + $home_host = parse_url(home_url(), PHP_URL_HOST);
2279 +
2280 + $urls = array_filter($urls, function ($url) use ($home_host) {
2281 + $url_host = parse_url($url, PHP_URL_HOST);
2282 +
2283 + // Relative URLs → treat as same host
2284 + if (empty($url_host)) {
2285 + return true;
2286 + }
2287 +
2288 + return $url_host === $home_host;
2289 + });
2290 +
2291 + return array_values($urls);
2292 +}
2293 +
2294 +function berqwp_render_toggle($name, $checked) {
2295 +?>
2296 +<label class="berq-toggle">
2297 + <input type="checkbox" name="<?php echo esc_attr($name); ?>" <?php checked(1, $checked, true); ?>>
2298 + <div class="berq-toggle-switch"></div>
2299 +</label>
2300 +<?php
2301 +}
2302 +
2303 +function bwp_log_recently_optimized_page($page_url)
2304 +{
2305 + if (empty($page_url)) return;
2306 +
2307 + // berqwp_stored_page_cache passes a slug/path, not a full URL — reconstruct it
2308 + if (!str_starts_with($page_url, 'http')) {
2309 + $page_url = home_url($page_url);
2310 + }
2311 + $page_url = urldecode($page_url);
2312 +
2313 + $log = json_decode(get_option('berqwp_recently_optimized', '[]'), true);
2314 + if (!is_array($log)) $log = [];
2315 +
2316 + // Remove existing entry for this URL so re-caching moves it to the top
2317 + $log = array_values(array_filter($log, fn($e) => $e['url'] !== $page_url));
2318 +
2319 + array_unshift($log, [
2320 + 'url' => esc_url_raw($page_url),
2321 + 'cached_at' => current_time('Y-m-d H:i:s'),
2322 + ]);
2323 +
2324 + if (count($log) > 200) {
2325 + $log = array_slice($log, 0, 200);
2326 + }
2327 +
2328 + update_option('berqwp_recently_optimized', wp_json_encode($log), false);
2329 +}
2330 +
2331 +function bwp_clear_recently_optimized_log()
2332 +{
2333 + delete_option('berqwp_recently_optimized');
2334 +}
2335 +
2336 +function bwp_remove_recently_optimized_entry($page_url)
2337 +{
2338 + if (empty($page_url)) return;
2339 +
2340 + $log = json_decode(get_option('berqwp_recently_optimized', '[]'), true);
2341 + if (!is_array($log)) return;
2342 +
2343 + $log = array_values(array_filter($log, fn($e) => $e['url'] !== $page_url));
2344 + update_option('berqwp_recently_optimized', wp_json_encode($log), false);
2345 +}
2346 +
2347 +function berqwp_can_use_cloud() {
2348 + $berqconfigs = berqConfigs::getInstance();
2349 + $configs = $berqconfigs->get_configs();
2350 + $license_key = berqwp_get_license_key();
2351 +
2352 + return !empty($configs['site_id']) && !empty($configs['secret']) && !empty($configs['optimization_method']) && $configs['optimization_method'] == 'cloud' && !empty($license_key);
2353 +}
2354 +
2355 +function berqwp_generate_site_id() {
2356 + $blog_id = get_current_blog_id();
2357 + $network_id = function_exists('get_current_network_id') ? get_current_network_id() : 1;
2358 + $siteurl = get_option('siteurl');
2359 + return md5("berqwp|$network_id|$blog_id|$siteurl");
844 2360 }