PluginProbe
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript / 4.0.16
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript v4.0.16
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
searchpro / inc / helper-functions.php

helper-functions.php in BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript 4.0.16, at inc/helper-functions.php

2,262 lines 67.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use BerqWP\BerqWP;
4 use voku\helper\HtmlDomParser;
5
6 if (!defined('ABSPATH'))
7 exit;
8
9 // ==========================================
10 // Multisite Network Option Helpers
11 // ==========================================
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('bqwp_hide_feedback_notice', true, 60 * 60);
87 set_transient('berqwp_redirect', true, 1);
88 }
89 update_option('berqwp_sync_addons', true);
90 do_action('berqwp_activate_plugin');
91 }
92
93 function berqwp_is_slug_excludable($slug)
94 {
95 // Allow empty slug
96 // if (empty($slug)) {
97 // return true;
98 // }
99
100 $exclude_items = [
101 "favicon.ico",
102 "moderation-hash=",
103 "elementor_library=",
104 "add_to_wishlist=",
105 "robots.txt",
106 ".php",
107 "run_warmup=",
108 "et-compare-page=",
109 "add_to_compare=",
110 "min_price=",
111 "max_price=",
112 "view_mode=",
113 "view_mode_smart=",
114 "et_columns-count=",
115 "add_to_wishlist=",
116 "et-wishlist-page=",
117 "remove_wishlist=",
118 "stock_status=",
119 "page_id=",
120 "?p=",
121 "add-to-cart=",
122 "remove_item=",
123 "cart_item_key=",
124 "quantity=",
125 "my-account=",
126 "lost-password=",
127 "reset-password=",
128 "order-pay=",
129 "order-received=",
130 "view-order=",
131 "?s=",
132 "&s=",
133 "orderby=",
134 "product_tag=",
135 "product_cat=",
136 "min_price=",
137 "max_price=",
138 "rating=",
139 "filter_",
140 "edd_action=",
141 "download_id=",
142 "bbp_=",
143 "bbp-search=",
144 "&bp_=",
145 "?bp_=",
146 "?action=",
147 "&action=",
148 "gf_page=",
149 "gf_token=",
150 "gform_submit=",
151 "wordfence_logHuman=",
152 "wordfence_lh=",
153 "wordfence_syncAttackData=",
154 "?elementor=",
155 "&elementor=",
156 "?ld_=",
157 "&ld_=",
158 "lesson_id=",
159 "quiz_id=",
160 "wpforms=",
161 "?ref=",
162 "&ref=",
163 "?aff=",
164 "&aff=",
165 "?llms_=",
166 "&llms_=",
167 "lesson_id=",
168 "course_id=",
169 "vc_editable=true",
170 "et_fb=1",
171 "et_fb_edit",
172 "rcp_action=",
173 "member_id=",
174 "give_action=",
175 "donation_id=",
176 "giveDonationFormInIframe=",
177 "tribe-bar-date=",
178 "tribe_eventcategory=",
179 "tribe_paged=",
180 "tribe_organizer=",
181 "tribe_venue=",
182 "job_id=",
183 "job_applications=",
184 "job_alerts=",
185 "mepr-process=",
186 "mepr-transaction=",
187 "mepr_coupon=",
188 "popmake=",
189 "pum_form_sub=",
190 "pum_action=",
191 "ngg_page=",
192 "gallery_id=",
193 "pid=",
194 "wp_simple_pay=",
195 "sp_dont_optimize=",
196 "remove_from_wishlist=",
197 "action=yith-woocompare",
198 "?amp=",
199 "&amp=",
200 "?noamp=",
201 "&noamp=",
202 "subscription_id=",
203 "renewal_order=",
204 "edd_bk=",
205 "wpgmza=",
206 "poll_id=",
207 "pollresult=",
208 "swpquery=",
209 "swpengine=",
210 "monsterinsights=",
211 "defender=",
212 "wdf_scan=",
213 "wc_bookings_field=",
214 "wc_bookings_calendar=",
215 "?na=",
216 "&na=",
217 "?newsletter=",
218 "&newsletter=",
219 "affwp_ref=",
220 "affwp_campaign=",
221 "hmwp_token=",
222 "/page/",
223 "/search/",
224 "?",
225 "/embed",
226 "/view-order/",
227 "/redirect/",
228 "/elementskit-content/",
229 ];
230
231 $exclude_items = apply_filters('berqwp_exclude_slug_match', $exclude_items);
232
233 foreach ($exclude_items as $item) {
234 if (strpos($slug, $item) !== false) {
235 return true;
236 }
237 }
238
239 return false;
240 }
241
242 function berqwp_get_page_params($page_url, $is_forced = false)
243 {
244
245 if (empty($page_url)) {
246 return;
247 }
248
249 $page_slug = bwp_url_into_path($page_url);
250 $key = '';
251 $berqconfigs = berqConfigs::getInstance();
252 $berqwp_configs = $berqconfigs->get_configs();
253
254 $optimization_mode = get_option('berq_opt_mode');
255
256 if ($optimization_mode == 4) {
257 $optimization_mode = 'aggressive';
258 } elseif ($optimization_mode == 3) {
259 $optimization_mode = 'blaze';
260 } elseif ($optimization_mode == 2) {
261 $optimization_mode = 'medium';
262 } elseif ($optimization_mode == 1) {
263 $optimization_mode = 'basic';
264 }
265
266 // Data to send as POST parameters
267 $post_data = array(
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
306 );
307
308 if (!get_option('berqwp_can_use_fluid_images')) {
309 $post_data['fluid_images'] = 0;
310 }
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
325 return $post_data;
326 }
327
328 function bwp_pass_account_requirement()
329 {
330 global $berq_log;
331 $berqWP = \berqWP::getInstance();
332
333 $license_key = berqwp_get_license_key();
334
335 if (empty($license_key)) {
336 return false;
337 }
338
339 global $berq_log;
340 // $berq_log->info("License key check from bwp_pass_account_requirement function.");
341
342 $key_response = $berqWP->verify_license_key($license_key);
343
344 if (empty($key_response->product_ref)) {
345 return false;
346 }
347
348 if ($key_response->result !== 'success' || $key_response->status !== 'active') {
349 // $berq_log->error("account requirement: license verification failed");
350 return false;
351 }
352
353 if ($key_response->product_ref == 'Free Account' && bwp_cached_pages_count() >= 10) {
354 return false;
355 }
356
357 if ($key_response->product_ref == 'Starter' && bwp_cached_pages_count() >= 100) {
358 return false;
359 }
360
361 return true;
362 }
363
364 function warmup_cache_by_url($page_url, $is_forced = false, $async = false)
365 {
366
367 if (!berqwp_can_use_cloud()) {
368 return;
369 }
370
371 if (empty($page_url)) {
372 return;
373 }
374
375 if (empty(berqwp_get_license_key())) {
376 return;
377 }
378
379 if (berq_is_localhost() && !defined('BERQWP_ALLOW_LOCALHOST')) {
380 return;
381 }
382
383 if (berq_is_localhost() && defined('BERQWP_ALLOW_LOCALHOST') && BERQWP_ALLOW_LOCALHOST === false) {
384 return;
385 }
386
387 $page_url = strtolower($page_url);
388
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']) {
393 return;
394 }
395
396 // Avoid caching file URLs e.g .php
397 // Allow .html
398 if (berqwp_is_file_url($page_url)) {
399 return;
400 }
401
402 // We don't want to cache page URL with query params
403 if (strpos($page_url, '?') !== false) {
404 return;
405 }
406
407 // Return if page url or page path (slug) is excluded
408 if (!bwp_can_optimize_page_url($page_url)) {
409 return;
410 }
411
412 global $berq_log;
413 $berq_log->info('warming page: ' . $page_url);
414
415 // Prepare post data for this page
416 $post_data = berqwp_get_page_params($page_url, $is_forced);
417
418 $berqwp = new BerqWP(get_option('berqwp_license_key'), null, optifer_cache);
419 $timeout = 30;
420
421 if ($async) {
422 $timeout = 1;
423 }
424
425 $berqwp->request_cache($post_data, $timeout);
426 }
427
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';
432
433 return file_exists($cache_file);
434 }
435
436 function bwp_cache_current_page()
437 {
438 global $bwp_current_page, $berq_log;
439
440 // $berq_log->info('Shutdown hook fired.');
441
442 if (empty($bwp_current_page)) {
443 return;
444 }
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);
488 $cache_file = $cache_directory . $cache_key . '.html';
489
490 if (file_exists($cache_file)) {
491 $buffer = file_get_contents($cache_file);
492
493 if (!empty($buffer)) {
494 $html = berqwp_str_get_html($buffer);
495
496 if ($html !== false) {
497 $style_tag = $html->find('style#berqwp-critical-css', 0);
498
499 if ($style_tag === null) {
500 return true;
501 }
502 }
503 }
504 }
505
506 return false;
507 }
508
509 function berq_is_localhost()
510 {
511 $whitelist = array('127.0.0.1', '::1');
512
513 if (in_array($_SERVER['REMOTE_ADDR'], $whitelist)) {
514 return true;
515 }
516
517 return false;
518 }
519
520 function berqwp_remove_ignore_params($slug)
521 {
522 // List of tracking parameters to remove
523 $tracking_params = get_option('berq_ignore_urls_params', []);
524
525 $tracking_params = apply_filters('berqwp_ignored_urls_params', $tracking_params);
526
527 // Parse the provided slug
528 $url_parts = parse_url($slug);
529
530 // Get the current URL parameters
531 $url_params = array();
532 if (isset($url_parts['query'])) {
533 parse_str($url_parts['query'], $url_params);
534 }
535
536 // Remove specified tracking parameters from the URL
537 foreach ($tracking_params as $param) {
538 $param = trim($param);
539 if (isset($url_params[$param])) {
540 unset($url_params[$param]);
541 }
542 }
543
544 // Build the new query string
545 $new_query_string = http_build_query($url_params);
546
547 // Reconstruct the URL with the new query string
548 $updated_url = $url_parts['scheme'] . "://" . $url_parts['host'] . $url_parts['path'];
549 if (!empty($new_query_string)) {
550 $updated_url .= '?' . $new_query_string;
551 }
552
553 return $updated_url;
554 }
555
556 function berqwp_is_sub_dir_wp()
557 {
558 // // remove http
559 // $site_url = explode('//', home_url())[1];
560 // $break_slash = explode('/', $site_url);
561
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
589 }
590
591 function berqwp_current_page_cache_file()
592 {
593 $slug_uri = $_SERVER['REQUEST_URI'];
594
595 // if wordpress is installed in a sub directory
596 if (berqwp_is_sub_dir_wp()) {
597 // Parse strings to extract paths
598 $path1 = explode('/', parse_url(home_url(), PHP_URL_PATH));
599 $path2 = explode('/', parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
600
601 // Find the common part of the paths
602 $commonPath = implode('/', array_intersect($path1, $path2));
603
604 // Subtract the common part from the first string
605 $slug_uri = str_replace($commonPath, '', $_SERVER['REQUEST_URI']);
606 }
607
608 // Return if page is excluded from cache
609 $pages_to_exclude = get_option('berq_exclude_urls', []);
610
611 if (in_array(get_site_url() . $slug_uri, $pages_to_exclude)) {
612 return;
613 }
614
615
616 $slug = berqwp_remove_ignore_params($slug_uri);
617
618 if (isset($_GET['creating_cache'])) {
619 return;
620 }
621
622 if (get_option('berqwp_enable_sandbox') == 1 && isset($_GET['berqwp'])) {
623 $slug = explode('?berqwp', $slug_uri)[0];
624 } elseif (get_option('berqwp_enable_sandbox') == 1 && !isset($_GET['creating_cache'])) {
625 return;
626 }
627
628
629 // Attempt to retrieve the cached HTML from the cache directory
630 $cache_directory = bwp_get_cache_dir();
631
632 // Generate a unique cache key based on the current page URL
633 $cache_key = md5($slug);
634 $cache_file = $cache_directory . $cache_key . '.html';
635
636 return $cache_file;
637 }
638
639 function berqwp_get_LCP_details($url, $device = 'mobile')
640 {
641 $google_pagespeed_api_url = "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=$url&strategy=$device ";
642
643 // Send a GET request to the Google PageSpeed Insights API
644 // $response = wp_remote_get($google_pagespeed_api_url, array('timeout' => 60));
645 $response = bwp_wp_remote_get($google_pagespeed_api_url, array('timeout' => 60));
646
647 if (is_wp_error($response)) {
648 return 'Error: ' . $response->get_error_message();
649 }
650
651 // Convert the JSON response to a PHP array
652 $body = wp_remote_retrieve_body($response);
653 $output = json_decode($body, true);
654
655 // Get the LCP data
656 return $output['lighthouseResult']['audits']['largest-contentful-paint-element']['details']['items'][0]['items'][0]['node'];
657 }
658
659 function berqwp_enable_advanced_cache($status)
660 {
661 global $berq_log;
662
663 // Get wp-config.php path
664 $configFilePath = defined('BERQWP_WP_CONFIG') ? BERQWP_WP_CONFIG : ABSPATH . 'wp-config.php';
665
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 }
671
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 }
677
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"));
681
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]);
715 } else {
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 }
720
721 // Rebuild the file content
722 $newContent = implode("", $lines);
723 $tempFile = $configFilePath . '.tmp';
724
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 }
730
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;
736 }
737
738 $berq_log->info("wp-config.php updated successfully.");
739 return true;
740 }
741
742 // Copied from Nginx Helper plugin
743 // function berqwp_unlink_recursive($dir)
744 // {
745
746 // if (!is_dir($dir)) {
747 // return;
748 // }
749
750 // $dh = opendir($dir);
751
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;
775 }
776
777 $files = new RecursiveIteratorIterator(
778 new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
779 RecursiveIteratorIterator::CHILD_FIRST
780 );
781
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 }
791 }
792 }
793
794 return rmdir($dir); // remove the root directory itself
795 }
796
797 function berqwp_get_last_modified_timestamp()
798 {
799 global $post;
800
801 // Check if it's a single post or page
802 if (is_singular()) {
803 return get_the_modified_time('U', $post->ID); // 'U' format parameter returns Unix timestamp
804 }
805
806 // Check if it's a taxonomy term
807 if (is_tax() || is_category() || is_tag()) {
808 $term = get_queried_object(); // Get the current term object
809
810 // For tags, get the last modified date of the most recent post associated with the tag
811 if (is_tag()) {
812 $args = array(
813 'tag_id' => $term->term_id,
814 'posts_per_page' => 1,
815 'orderby' => 'modified',
816 'order' => 'DESC',
817 'fields' => 'ids', // Return only post IDs to reduce overhead
818 );
819 $posts = get_posts($args);
820 if ($posts) {
821 $latest_post_id = $posts[0];
822 return get_the_modified_time('U', $latest_post_id); // 'U' format parameter returns Unix timestamp
823 }
824 }
825
826 // For category archives, get the last modified date of the most recent post within the category
827 if (is_category()) {
828 $args = array(
829 'category' => $term->term_id,
830 'posts_per_page' => 1,
831 'orderby' => 'modified',
832 'order' => 'DESC',
833 'fields' => 'ids', // Return only post IDs to reduce overhead
834 );
835 $posts = get_posts($args);
836 if ($posts) {
837 $latest_post_id = $posts[0];
838 return get_the_modified_time('U', $latest_post_id); // 'U' format parameter returns Unix timestamp
839 }
840 }
841
842 return strtotime($term->modified); // Convert modified date to timestamp
843 }
844
845 // Check if it's an archive
846 if (is_archive()) {
847 // For other archives
848 $archive_id = get_queried_object_id(); // Get the ID of the current archive
849 $archive = get_post($archive_id); // Get the archive post object
850 return strtotime($archive->post_modified); // Convert modified date to timestamp
851 }
852
853 // For other cases (fallback)
854 return false;
855 }
856
857 function bwp_is_gzip_supported()
858 {
859 return function_exists('gzencode') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false;
860 }
861
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;
890 }
891
892 function bwp_wp_remote_get($url, $args = array())
893 {
894 // Default arguments
895 $defaults = array(
896 'headers' => array(
897 'User-Agent' => 'BerqWP Bot', // Customize user agent if needed
898 ),
899 );
900
901 // Merge provided arguments with defaults
902 $args = wp_parse_args($args, $defaults);
903
904 if (empty($args['timeout'])) {
905 $args['timeout'] = 30;
906 }
907
908 // Initialize cURL session
909 $ch = curl_init();
910
911 // Set the URL
912 curl_setopt($ch, CURLOPT_URL, $url);
913
914 // Set to return the transfer as a string
915 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
916
917 // Set timeout in seconds
918 curl_setopt($ch, CURLOPT_TIMEOUT, $args['timeout']);
919
920 // Set the user-agent
921 curl_setopt($ch, CURLOPT_USERAGENT, $args['headers']['User-Agent']);
922
923 // Include header in the output
924 curl_setopt($ch, CURLOPT_HEADER, true);
925
926 // Execute the request
927 $response = curl_exec($ch);
928
929 // Check for errors
930 if (curl_errno($ch)) {
931 $error_message = curl_error($ch);
932 curl_close($ch);
933 return new WP_Error('curl_error', $error_message);
934 }
935
936 // Close cURL session
937 curl_close($ch);
938
939 // Separate headers and body
940 list($headers, $body) = explode("\r\n\r\n", $response, 2);
941
942 // Parse headers into array
943 $header_lines = explode("\r\n", $headers);
944 $headers = array();
945 foreach ($header_lines as $line) {
946 $parts = explode(':', $line, 2);
947 if (count($parts) == 2) {
948 $headers[trim($parts[0])] = trim($parts[1]);
949 }
950 }
951
952 // Construct response array similar to wp_remote_get
953 $response = array(
954 'headers' => $headers,
955 'body' => $body,
956 'response' => array(
957 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
958 'message' => curl_getinfo($ch, CURLINFO_HTTP_CODE),
959 ),
960 'cookies' => array(),
961 'filename' => '',
962 );
963
964 return $response;
965 }
966
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;
980 }
981
982 function verify_request_origin($request)
983 {
984 // Check the referrer header to ensure the request is coming from the same site
985 $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
986 $site_url = get_site_url();
987
988 // Optionally, check the origin header
989 $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
990
991 // Ensure the request comes from the same site
992 if (strpos($referrer, $site_url) !== 0 && strpos($origin, $site_url) !== 0) {
993 return new WP_Error('rest_forbidden', esc_html__('You cannot access this resource.', 'searchpro'), array('status' => 403));
994 }
995
996 // Ensure the origin is a subdomain of berqwp.com
997 if (!preg_match('/^https?:\/\/([a-z0-9-]+\.)?berqwp\.com$/', $origin)) {
998 return new WP_Error('rest_forbidden', esc_html__('You cannot access this resource.', 'searchpro'), array('status' => 403));
999 }
1000
1001 return true;
1002 }
1003
1004 function berq_rest_permission_callback(WP_REST_Request $request)
1005 {
1006 // Get the nonce from the request
1007 $nonce = $request->get_header('X-WP-Nonce');
1008 $hash = $request->get_header('X-berqwp-key-hash');
1009
1010 if ($hash == md5(berqwp_get_license_key())) {
1011 return true;
1012 }
1013
1014 // Verify the nonce
1015 if (!wp_verify_nonce($nonce, 'wp_rest')) {
1016 return new WP_Error('rest_invalid_nonce', __('Invalid nonce', 'searchpro'), array('status' => 403));
1017 }
1018
1019 return true; // Return true to allow the request
1020 }
1021
1022 function berq_rest_verify_license_callback(WP_REST_Request $request)
1023 {
1024 $license_key_hash = sanitize_text_field($request->get_param('license_key_hash'));
1025 $license_key = berqwp_get_license_key();
1026
1027 if (empty($license_key_hash) || empty($license_key) || $license_key_hash !== md5($license_key)) {
1028 global $berq_log;
1029 $berq_log->error("Exiting... Invalid license key.");
1030 return new WP_Error('rest_invalid_nonce', __('Invalid license key', 'searchpro'), array('status' => 403));
1031 }
1032
1033 return true; // Return true to allow the request
1034 }
1035
1036 function bwp_dash_notification($msg = '', $status = 'warning')
1037 {
1038 ?>
1039 <div class="berqwp-notification <?php echo esc_attr($status) ?>">
1040 <?php
1041
1042 echo "<div class='icon'>";
1043 if ($status == 'warning') {
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>';
1045 } elseif ($status == 'error') {
1046 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 0c53 0 96 43 96 96l0 3.6c0 15.7-12.7 28.4-28.4 28.4l-135.1 0c-15.7 0-28.4-12.7-28.4-28.4l0-3.6c0-53 43-96 96-96zM41.4 105.4c12.5-12.5 32.8-12.5 45.3 0l64 64c.7 .7 1.3 1.4 1.9 2.1c14.2-7.3 30.4-11.4 47.5-11.4l112 0c17.1 0 33.2 4.1 47.5 11.4c.6-.7 1.2-1.4 1.9-2.1l64-64c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3l-64 64c-.7 .7-1.4 1.3-2.1 1.9c6.2 12 10.1 25.3 11.1 39.5l64.3 0c17.7 0 32 14.3 32 32s-14.3 32-32 32l-64 0c0 24.6-5.5 47.8-15.4 68.6c2.2 1.3 4.2 2.9 6 4.8l64 64c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0l-63.1-63.1c-24.5 21.8-55.8 36.2-90.3 39.6L272 240c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 239.2c-34.5-3.4-65.8-17.8-90.3-39.6L86.6 502.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3l64-64c1.9-1.9 3.9-3.4 6-4.8C101.5 367.8 96 344.6 96 320l-64 0c-17.7 0-32-14.3-32-32s14.3-32 32-32l64.3 0c1.1-14.1 5-27.5 11.1-39.5c-.7-.6-1.4-1.2-2.1-1.9l-64-64c-12.5-12.5-12.5-32.8 0-45.3z"/></svg>';
1047 } elseif ($status == 'info') {
1048 echo '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M96 64c0-17.7-14.3-32-32-32S32 46.3 32 64l0 256c0 17.7 14.3 32 32 32s32-14.3 32-32L96 64zM64 480a40 40 0 1 0 0-80 40 40 0 1 0 0 80z"/></svg>';
1049 } else {
1050 return;
1051 }
1052 echo "</div>";
1053 echo esc_html($msg);
1054 ?>
1055 </div>
1056 <?php
1057 }
1058
1059 function bwp_can_warmup_cache($identifier)
1060 {
1061
1062 if (get_transient('bwp_warmup_lock_' . md5($identifier)) === false) {
1063
1064 set_transient('bwp_warmup_lock_' . md5($identifier), true, 100);
1065 return true;
1066 }
1067
1068 return false;
1069 }
1070
1071 function bwp_clear_warmup_lock($slug)
1072 {
1073 delete_transient('bwp_warmup_lock_' . md5($slug));
1074 }
1075
1076 function bwp_extractUrlsFromCss($cssContent)
1077 {
1078 $urls = [];
1079 $pattern = '/url\((.*?)\)/i';
1080
1081 preg_match_all($pattern, $cssContent, $matches);
1082
1083 if (!empty($matches[1])) {
1084 foreach ($matches[1] as $match) {
1085 // Trim any surrounding quotes and whitespace
1086 $urls[] = trim($match, '\'" ');
1087 }
1088 }
1089
1090 return $urls;
1091 }
1092
1093 function bwp_getBaseUrl($fileUrl)
1094 {
1095 // Parse the URL and get its components
1096 $parsedUrl = parse_url($fileUrl);
1097 $scheme = isset($parsedUrl['scheme']) ? $parsedUrl['scheme'] . '://' : '';
1098 $host = isset($parsedUrl['host']) ? $parsedUrl['host'] : '';
1099 $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
1100
1101 // Remove the file name from the path to get the base URL
1102 $basePath = preg_replace('/\/[^\/]+$/', '/', $path);
1103
1104 // Construct the base URL
1105 return $scheme . $host . $basePath;
1106 }
1107
1108 function bwp_rel2abs($rel, $base)
1109 {
1110 /* return if already absolute URL */
1111 if (parse_url($rel, PHP_URL_SCHEME) != '')
1112 return $rel;
1113
1114 /* queries and anchors */
1115 if ($rel[0] == '#' || $rel[0] == '?')
1116 return $base . $rel;
1117
1118 /* parse base URL and convert to local variables:
1119 $scheme, $host, $path */
1120 extract(parse_url($base));
1121
1122 /* remove non-directory element from path */
1123 $path = preg_replace('#/[^/]*$#', '', $path);
1124
1125 /* destroy path if relative url points to root */
1126 if ($rel[0] == '/')
1127 $path = '';
1128
1129 /* dirty absolute URL */
1130 $abs = "$host$path/$rel";
1131
1132 /* replace '//' or '/./' or '/foo/../' with '/' */
1133 $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
1134 for ($n = 1; $n > 0; $abs = preg_replace($re, '/', $abs, -1, $n)) {
1135 }
1136
1137 /* absolute URL is ready! */
1138 return $scheme . '://' . $abs;
1139 }
1140
1141 function update_image_url_extension($image_url, $file_extension)
1142 {
1143 $url_arr = explode('.', $image_url);
1144 $last_index = count($url_arr) - 1;
1145
1146 // Extract the file extension
1147 $current_file_extension = pathinfo($image_url, PATHINFO_EXTENSION);
1148
1149 $url_arr[$last_index] = str_replace("$current_file_extension", $file_extension, $url_arr[$last_index]);
1150 $new_image_url = implode('.', $url_arr);
1151
1152 return $new_image_url;
1153 }
1154
1155 if (!function_exists('str_contains')) {
1156 function str_contains(string $haystack, string $needle): bool
1157 {
1158 return strpos($haystack, $needle) !== false;
1159 }
1160 }
1161
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
1172 // Allow cache busting by passing $force_check = true
1173 // if ($force_check) {
1174 // delete_transient($transient_key);
1175 // }
1176
1177 if ($short_live) {
1178 $transient_key = "berqwp_connection_status_sl";
1179 }
1180
1181 // Check if the result is cached
1182 $cached_status = get_transient($transient_key);
1183
1184 if ($cached_status) {
1185 return $cached_status;
1186 }
1187
1188 // Perform the actual REST API check
1189 $response = wp_safe_remote_get('https://boost.berqwp.com/photon/?connection_test=1&url=' . bwp_admin_home_url('/?utm_source=' . time()), ['timeout' => 60]);
1190
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 // );
1197 } else {
1198 $body = wp_remote_retrieve_body($response);
1199
1200 if ($body == 'pingpong') {
1201 $result = array(
1202 'status' => 'success',
1203 'message' => 'Your website is accessible by BerqWP server.',
1204 );
1205 } else {
1206 $result = array(
1207 'status' => 'error',
1208 'message' => 'BerqWP server is unable to access your website, please whitelist our server IP address.',
1209 );
1210 }
1211 }
1212
1213 if ($short_live) {
1214 set_transient($transient_key, $result, 60 * 5);
1215 } else {
1216 set_transient($transient_key, $result, 60 * 60 * 24);
1217 }
1218
1219 return $result;
1220 }
1221
1222 function bwp_sendPostRequestInBackground($url, $params)
1223 {
1224 $userAgent = 'BerqWP';
1225 $urlParts = parse_url($url);
1226
1227 // Ensure we have a valid path and handle query strings
1228 $path = isset($urlParts['path']) ? $urlParts['path'] : '/';
1229 if (isset($urlParts['query'])) {
1230 $path .= '?' . $urlParts['query'];
1231 }
1232
1233 $postString = http_build_query($params);
1234
1235 $host = $urlParts['host'];
1236 $scheme = isset($urlParts['scheme']) ? $urlParts['scheme'] : 'http';
1237 $port = ($scheme === 'https') ? 443 : 80;
1238 $transport = ($scheme === 'https') ? 'ssl://' : '';
1239
1240 $request = "POST $path HTTP/1.1\r\n";
1241 $request .= "Host: $host\r\n";
1242 $request .= "User-Agent: $userAgent\r\n";
1243 $request .= "Content-Type: application/x-www-form-urlencoded\r\n";
1244 $request .= "Content-Length: " . strlen($postString) . "\r\n";
1245 $request .= "Connection: Close\r\n\r\n";
1246 $request .= $postString;
1247
1248 $fp = fsockopen($transport . $host, $port, $errno, $errstr, 30);
1249
1250 if ($fp) {
1251 fwrite($fp, $request);
1252 fclose($fp); // Close immediately to prevent waiting for the response
1253 } else {
1254 // If fsockopen fails, fallback to wp_remote_post
1255 $args = array(
1256 'timeout' => 0.01,
1257 'headers' => array(
1258 'User-Agent' => $userAgent,
1259 ),
1260 'body' => $params
1261 );
1262
1263 wp_remote_post($url, $args);
1264 }
1265 }
1266
1267 function bwp_is_webpage()
1268 {
1269 $headers = headers_list();
1270 $contentType = '';
1271
1272 foreach ($headers as $header) {
1273 if (stripos($header, 'Content-Type') !== false) {
1274 $contentType = $header;
1275 break;
1276 }
1277 }
1278
1279 if (stripos($contentType, 'text/html') !== false) {
1280 return true;
1281 }
1282
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
1485 if ($query->have_posts()) {
1486 $sitemap_urls = [];
1487
1488 if (!isset($_GET['configs_only'])) {
1489
1490 if (get_option('show_on_front') !== 'page') {
1491 $sitemap_urls[] = home_url('/');
1492 }
1493
1494 // Loop through the posts and generate URLs
1495 while ($query->have_posts()) {
1496 $query->the_post();
1497
1498 $post_id = get_the_ID();
1499 $post_type = get_post_field( 'post_type', $post_id );
1500 $url = get_permalink( $post_id );
1501
1502 // Fallback for MB CPTs whose rewrite rules aren't loaded (post type not registered)
1503 if ( strpos( $url, '?' ) !== false && isset( $rewrite_map[ $post_type ] ) ) {
1504 $post_name = get_post_field( 'post_name', $post_id );
1505 $url = trailingslashit( home_url( '/' . $rewrite_map[ $post_type ] . '/' . $post_name ) );
1506 }
1507
1508 $translation_urls = apply_filters('berqwp_page_translation_urls', [], $url);
1509
1510 if (!bwp_can_optimize_page_url($url)) {
1511 continue;
1512 }
1513
1514 if (!in_array($url, $sitemap_urls)) {
1515 $sitemap_urls[] = $url;
1516 }
1517
1518 if (!empty($translation_urls)) {
1519 foreach ($translation_urls as $page_url) {
1520 if (!bwp_can_optimize_page_url($page_url)) {
1521 continue;
1522 }
1523
1524 if (!in_array($page_url, $sitemap_urls)) {
1525 $sitemap_urls[] = $page_url;
1526 }
1527 }
1528 }
1529 }
1530 }
1531
1532 // Return response with pagination info
1533 $response = array(
1534 'paged' => $paged,
1535 'post_params' => $post_params,
1536 'total_pages' => $total_pages,
1537 'total_posts' => $total_posts,
1538 'urls' => $sitemap_urls,
1539 );
1540
1541 echo json_encode($response);
1542 } else {
1543 // If no posts found
1544 echo json_encode(array('error' => 'No posts found'));
1545 }
1546
1547 // Clean up
1548 wp_reset_postdata();
1549 exit;
1550 }
1551 }
1552
1553 function bwp_show_account()
1554 {
1555 if (!defined('BERQWP_HIDE_ACCOUNT')) {
1556 return true;
1557 }
1558
1559 if (defined('BERQWP_HIDE_ACCOUNT') && BERQWP_HIDE_ACCOUNT) {
1560 return false;
1561 }
1562
1563 return true;
1564 }
1565
1566 function bwp_show_docs()
1567 {
1568
1569 if (!defined('BERQWP_HIDE_DOCS')) {
1570 return true;
1571 }
1572
1573 if (defined('BERQWP_HIDE_DOCS') && BERQWP_HIDE_DOCS) {
1574 return false;
1575 }
1576
1577 return true;
1578 }
1579
1580 function bwp_admin_home_url($relative_path = '')
1581 {
1582 $home_url = home_url();
1583
1584 if (class_exists('TRP_Translate_Press')) {
1585 $trp = TRP_Translate_Press::get_trp_instance();
1586 $trp_settings = get_option('trp_settings', array());
1587 $default_lang = $trp_settings['default-language'];
1588 $url_converter = $trp->get_component('url_converter');
1589 $url_slugs = $trp_settings['url-slugs'];
1590
1591 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) {
1592 // var_dump($trp_settings);
1593 return $home_url . '/' . $url_slugs[$default_lang] . $relative_path;
1594 }
1595 }
1596
1597 return $home_url . $relative_path;
1598 }
1599
1600 function bwp_intersect_str($str1, $str2)
1601 {
1602 $arr = explode('/', $str1);
1603 $last_item = $arr[count($arr) - 1]; // Get last item from $arr
1604 $arr2 = explode('/', $str2);
1605
1606 if (!empty($arr2) && strpos($str2, $last_item) !== false) {
1607
1608 for ($i = 1; $i < count($arr2); $i++) {
1609 if (!empty($arr2[$i]) && $arr2[$i] == $last_item) {
1610 unset($arr2[$i]);
1611 }
1612 }
1613
1614 $str2 = implode('/', $arr2);
1615 }
1616
1617 return $str2;
1618 }
1619
1620 function bwp_is_tab($tab_id)
1621 {
1622 $default_tab = 'dashboard';
1623
1624 if (!empty($_GET['tab_id'])) {
1625 if (sanitize_text_field($_GET['tab_id']) == $tab_id) {
1626 // echo ' style="display:block" ';
1627 echo ' style="visibility:visible;opacity:1;height:auto;" ';
1628 } else {
1629 // echo ' style="display:none" ';
1630 echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;" ';
1631 }
1632 } else {
1633
1634 if ($tab_id == $default_tab) {
1635 // echo ' style="display:block" ';
1636 echo ' style="visibility:visible;opacity:1;height:auto;" ';
1637 } else {
1638 // echo ' style="display:none" ';
1639 echo ' style="visibility:hidden;opacity:0;height:0;overflow:hidden;" ';
1640 }
1641 }
1642 }
1643
1644 function bwp_is_tab_nav($tab_id)
1645 {
1646 $default_tab = 'dashboard';
1647
1648 if (!empty($_GET['tab_id'])) {
1649 if (sanitize_text_field($_GET['tab_id']) == $tab_id) {
1650 echo ' active ';
1651 }
1652 } else {
1653
1654 if ($tab_id == $default_tab) {
1655 echo ' active ';
1656 }
1657 }
1658 }
1659
1660 function bwp_notice($status = '', $title = null, $message = null, $btn = [], $dismissible = false)
1661 {
1662 ?>
1663 <div
1664 class="bwp-notice <?php echo 'status-' . esc_attr($status); ?> <?php echo $dismissible ? 'dismissible' : ''; ?> <?php echo empty($title) ? 'no-title' : ''; ?>">
1665 <?php if ($dismissible) { ?>
1666 <div class="close"><svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px"
1667 fill="#000">
1668 <path
1669 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" />
1670 </svg></div>
1671 <?php } ?>
1672
1673 <div class="icon"><svg width="30" height="30" viewBox="0 0 24 24" fill="#fff" xmlns="http://www.w3.org/2000/svg">
1674 <path fill-rule="evenodd" clip-rule="evenodd"
1675 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 fill="#1f72ff" />
1677 </svg></div>
1678 <div class="content">
1679 <div class="status-tag"><?php esc_html_e($status, 'searchpro'); ?></div>
1680 <?php if (!empty($title)) { ?>
1681 <h5><?php echo wp_kses_post(__($title, 'searchpro')); ?></h5>
1682 <?php } ?>
1683
1684 <?php if (!empty($message)) { ?>
1685 <?php echo wp_kses_post(__($message, 'searchpro')); ?>
1686 <?php } ?>
1687
1688 <?php if (!empty($btn) && is_array($btn)) { ?>
1689 <div class="bwp-notice-btn">
1690 <?php
1691 foreach ($btn as $bwp_btn) {
1692 if (empty($bwp_btn['target'])) {
1693 $bwp_btn['target'] = '';
1694 }
1695
1696 if (empty($bwp_btn['href'])) {
1697 $bwp_btn['href'] = '';
1698 }
1699
1700 if (empty($bwp_btn['classes'])) {
1701 $bwp_btn['classes'] = '';
1702 }
1703
1704 if (empty($bwp_btn['text'])) {
1705 $bwp_btn['text'] = '';
1706 }
1707 ?>
1708 <a target="<?php echo esc_attr($bwp_btn['target']) ?? ''; ?>"
1709 href="<?php echo esc_attr($bwp_btn['href']) ?? ''; ?>"
1710 class="bwp-btn <?php echo esc_attr($bwp_btn['classes']) ?? ''; ?>">
1711 <?php echo esc_html__($bwp_btn['text'], 'searchpro') ?? ''; ?>
1712 </a>
1713 <?php
1714 }
1715 ?>
1716 </div>
1717 <?php } ?>
1718 </div>
1719 </div>
1720 <?php
1721 }
1722
1723 function bwp_is_option_updated($option_name)
1724 {
1725 $value = isset($_POST[$option_name]) ? $_POST[$option_name] : 0;
1726
1727 if ($value == 'on') {
1728 $value = 1;
1729 }
1730
1731 $option_val = get_option($option_name);
1732 $array_options = [
1733 'berq_exclude_js_css',
1734 'berq_exclude_cdn',
1735 'berqwp_force_include_critical_css',
1736 'berqwp_exclude_lazy_load_images',
1737 'berqwp_exclude_third_party_js',
1738 'berqwp_exclude_js',
1739 'berqwp_exclude_css',
1740 ];
1741
1742 if (in_array($option_name, $array_options)) {
1743 $urls = sanitize_textarea_field($value);
1744 $urls_array = explode("\n", $urls);
1745
1746 $urls_array = array_map(function ($kw) {
1747 return trim($kw);
1748 }, $urls_array);
1749
1750 $urls_array = array_filter($urls_array, function ($kw) {
1751 return !empty($kw);
1752 });
1753
1754 if (!is_array($option_val)) {
1755 $option_val = [];
1756 }
1757
1758 // var_dump($option_val, $urls_array, array_diff($option_val, $urls_array), array_diff($option_val, $urls_array));
1759 // exit;
1760
1761 return !empty(array_diff($option_val, $urls_array));
1762 }
1763
1764 $values_changed = $option_val == $value;
1765
1766 return !$values_changed;
1767 }
1768
1769 function bwp_request_purge_license_key_cache()
1770 {
1771
1772 $license_key = berqwp_get_license_key();
1773 $parsed_url = parse_url(home_url());
1774 $domain = $parsed_url['host'];
1775
1776 if (empty($domain) || empty($license_key)) {
1777 return;
1778 }
1779
1780 wp_remote_post(BerqWP::$endpoint."license/flush", [
1781 'timeout' => 30,
1782 'body' => [
1783 'domain' => $domain,
1784 'license_key' => $license_key,
1785 'site_url' => home_url(),
1786 ]
1787 ]);
1788
1789 }
1790
1791 function bwp_display_logs()
1792 {
1793
1794 if (isset($_GET['berqwp_logs'])) {
1795
1796 // Check if the current user is logged in and has admin privileges
1797 if (!is_user_logged_in() || !current_user_can('administrator')) {
1798 wp_die(__('You are not allowed to access this page.', 'berqwp'));
1799 }
1800
1801 // Define the path to the BerqWP logs file
1802 $log_file_path = optifer_cache . '/logs/berqwp.log'; // Adjust path if needed
1803
1804 // Check if the log file exists
1805 if (!file_exists($log_file_path)) {
1806 echo '<div>No logs available. The log file does not exist.</div>';
1807 exit;
1808 }
1809
1810 // Read and display the log file content
1811 $logs = file_get_contents($log_file_path);
1812
1813 if ($logs === false) {
1814 echo '<div>Unable to read the log file.</div>';
1815 exit;
1816 }
1817
1818 echo '<h2>BerqWP Logs</h2>';
1819 echo '<pre style="background:#f4f4f4;padding:15px;border:1px solid #ddd;">' . esc_html($logs) . '</pre>';
1820 exit;
1821 }
1822 }
1823
1824 function bwp_cf_flush_all()
1825 {
1826 if (!empty(get_option('berqwp_cf_creden'))) {
1827 $email = get_option('berqwp_cf_creden')['email'];
1828 $apitoken = get_option('berqwp_cf_creden')['apitoken'];
1829 $zoneid = get_option('berqwp_cf_creden')['zoneid'];
1830
1831 $berqCloudflareAPIHandler = new berqCloudflareAPIHandler($email, $apitoken, $zoneid);
1832 $berqCloudflareAPIHandler->purge_all_cache();
1833 }
1834 }
1835
1836 function bwp_cf_flush_page($url)
1837 {
1838 if (!empty(get_option('berqwp_cf_creden'))) {
1839 $email = get_option('berqwp_cf_creden')['email'];
1840 $apitoken = get_option('berqwp_cf_creden')['apitoken'];
1841 $zoneid = get_option('berqwp_cf_creden')['zoneid'];
1842
1843 $berqCloudflareAPIHandler = new berqCloudflareAPIHandler($email, $apitoken, $zoneid);
1844 $berqCloudflareAPIHandler->flush_url($url);
1845 }
1846 }
1847
1848 function bwp_cf_delete_rules()
1849 {
1850 if (!empty(get_option('berqwp_cf_creden'))) {
1851 $email = get_option('berqwp_cf_creden')['email'];
1852 $apitoken = get_option('berqwp_cf_creden')['apitoken'];
1853 $zoneid = get_option('berqwp_cf_creden')['zoneid'];
1854
1855 $berqCloudflareAPIHandler = new berqCloudflareAPIHandler($email, $apitoken, $zoneid);
1856 $berqCloudflareAPIHandler->delete_rule_by_description('BerqWP cache rules');
1857 }
1858 }
1859
1860 function bwp_lock_cache_directory()
1861 {
1862 $cache_dir = optifer_cache;
1863
1864 if (!file_exists($cache_dir)) {
1865 wp_mkdir_p($cache_dir);
1866 }
1867
1868 $rules = <<<HTACCESS
1869 Order allow,deny
1870 Deny from all
1871
1872 <FilesMatch "index\.html\.gz$">
1873 Order allow,deny
1874 Allow from all
1875 </FilesMatch>
1876 HTACCESS;
1877
1878 file_put_contents($cache_dir . '.htaccess', $rules);
1879 }
1880
1881 function bwp_write_htaccess_rules($ignore_sandbox = false)
1882 {
1883 if (!got_mod_rewrite() || bwp_is_openlitespeed_server()) {
1884 return;
1885 }
1886
1887 if (!$ignore_sandbox && get_option('berqwp_enable_sandbox') == 1) {
1888 return;
1889 }
1890
1891 $htaccess = get_home_path() . '.htaccess';
1892 $rules = [
1893 '<IfModule mod_rewrite.c>',
1894 ' RewriteEngine On',
1895 ' RewriteCond %{REQUEST_METHOD} !POST',
1896 ' RewriteCond %{QUERY_STRING} ^$',
1897 ' RewriteCond %{HTTP_COOKIE} !(wp\-postpass|wordpress_logged_in|comment_author|woocommerce_cart_hash|edd_items_in_cart) [NC]',
1898 ' RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/berqwp/html/%{HTTP_HOST}%{REQUEST_URI}/index.html.gz -f',
1899 ' RewriteRule .* /wp-content/cache/berqwp/html/%{HTTP_HOST}%{REQUEST_URI}/index.html.gz [L]',
1900 '</IfModule>',
1901 '<IfModule mod_mime.c>',
1902 ' <FilesMatch "index\.html\.gz$">',
1903 ' ForceType text/html',
1904 ' AddEncoding gzip .gz',
1905 ' </FilesMatch>',
1906 '</IfModule>',
1907 '<IfModule mod_headers.c>',
1908 ' <FilesMatch "index\.html\.gz$">',
1909 ' Header set X-Served "server"',
1910 ' </FilesMatch>',
1911 '</IfModule>',
1912 ];
1913
1914 // Must appear before the WordPress block so Apache processes it first
1915 $marker = 'BerqWP Cache';
1916 $start = "# BEGIN $marker";
1917 $end = "# END $marker";
1918 $wp_start = '# BEGIN WordPress';
1919
1920 $block = $start . "\n";
1921 $block .= implode("\n", $rules) . "\n";
1922 $block .= $end . "\n";
1923
1924 $contents = file_exists($htaccess) ? file_get_contents($htaccess) : '';
1925
1926 // Remove all existing BerqWP Cache blocks (handles duplicates and corrupt state)
1927 $contents = preg_replace(
1928 '/^# BEGIN BerqWP Cache.*?^# END BerqWP Cache\s*/ms',
1929 '',
1930 $contents
1931 );
1932
1933 // Insert before first WordPress block if present, otherwise prepend
1934 if (strpos($contents, $wp_start) !== false) {
1935 $contents = preg_replace('/' . preg_quote($wp_start, '/') . '/', $block . "\n" . $wp_start, $contents, 1);
1936 } else {
1937 $contents = $block . "\n" . $contents;
1938 }
1939
1940 file_put_contents($htaccess, $contents);
1941 }
1942
1943 function bwp_remove_htaccess_rules()
1944 {
1945 $htaccess = get_home_path() . '.htaccess';
1946
1947 if (!file_exists($htaccess)) {
1948 return;
1949 }
1950
1951 $contents = file_get_contents($htaccess);
1952 $contents = preg_replace('/^# BEGIN BerqWP Cache.*?^# END BerqWP Cache\s*/ms', '', $contents);
1953 file_put_contents($htaccess, $contents);
1954 }
1955
1956 function bwp_sync_htaccess_on_sandbox_change()
1957 {
1958 // Action fires before update_option, so check the incoming POST value
1959 $sandbox_enabling = isset($_POST['berqwp_enable_sandbox']);
1960
1961 if ($sandbox_enabling) {
1962 bwp_remove_htaccess_rules();
1963 } else {
1964 bwp_write_htaccess_rules(true);
1965 }
1966 }
1967
1968 function berqwp_is_wp_cron_broken()
1969 {
1970 $cron = _get_cron_array();
1971 if (!$cron || !is_array($cron))
1972 return false;
1973
1974 $now = time();
1975 foreach ($cron as $timestamp => $events) {
1976 if ($timestamp < $now - 300) { // 5 minutes overdue
1977 return true;
1978 }
1979 }
1980 return false;
1981 }
1982
1983 function berqwp_is_page_url_excluded($page_url)
1984 {
1985 if (empty($page_url)) {
1986 return false;
1987 }
1988
1989 $pages_to_exclude = get_option('berq_exclude_urls', []);
1990
1991 if (strpos($page_url, '?') !== false) {
1992 $page_url = explode('?', $page_url)[0];
1993 }
1994
1995 if (in_array($page_url, $pages_to_exclude)) {
1996 return true;
1997 }
1998
1999 if (!empty($pages_to_exclude)) {
2000 foreach ($pages_to_exclude as $single_page_url) {
2001
2002 if (empty($single_page_url)) {
2003 continue;
2004 }
2005
2006 if (substr($single_page_url, -1) !== '*') {
2007 continue;
2008 }
2009
2010 $single_page_url = str_replace('*', '', $single_page_url);
2011
2012 if (strpos($page_url, $single_page_url) !== false) {
2013 return true;
2014 }
2015 }
2016 }
2017
2018 return false;
2019 }
2020
2021 // function berqwp_appendHtmlToBody($buffer, $htmlToAppend)
2022 // {
2023 // // Load the $buffer content into Simple HTML DOM
2024 // $html = HtmlDomParser::str_get_html($buffer);
2025
2026 // if (!$html) {
2027 // return $buffer;
2028 // }
2029
2030 // // Find the <body> tag
2031 // $body = $html->find('body', 0);
2032
2033 // // If the body tag exists, append the new HTML
2034 // if ($body) {
2035 // // Use htmlspecialchars to properly encode the inserted content
2036 // // Avoid breaking the HTML by not using innerhtml directly
2037 // $body->innertext .= $htmlToAppend;
2038 // } else {
2039 // // If no body tag exists, append the HTML to the document directly
2040 // $html->innertext .= $htmlToAppend;
2041 // }
2042
2043 // // Return the modified HTML content
2044 // return $html->save();
2045 // }
2046 //
2047 function berqwp_appendHtmlToBody($buffer, $htmlToAppend)
2048 {
2049 $pos = strripos($buffer, '</body>');
2050 if ($pos !== false) {
2051 return substr_replace($buffer, $htmlToAppend, $pos, 0);
2052 }
2053
2054 // Fallback: try before </html>
2055 $pos = strripos($buffer, '</html>');
2056 if ($pos !== false) {
2057 return substr_replace($buffer, $htmlToAppend, $pos, 0);
2058 }
2059
2060 // Last resort: append to end
2061 return $buffer . $htmlToAppend;
2062 }
2063
2064 function berqwp_appendHtmlToHead($buffer, $htmlToAppend)
2065 {
2066 $pos = stripos($buffer, '</head>');
2067 if ($pos !== false) {
2068 $buffer = substr_replace($buffer, PHP_EOL . $htmlToAppend, $pos, 0);
2069 }
2070
2071 // Fix missing </body> tag
2072 if (stripos($buffer, '</body>') === false) {
2073 $buffer = str_replace('</html>', '</body>' . PHP_EOL . '</html>', $buffer);
2074 }
2075
2076 return $buffer;
2077 }
2078
2079 function berqwp_prependHtmlToHead($buffer, $htmlToPrepend)
2080 {
2081 if (preg_match('/<head(\s[^>]*)?>/i', $buffer, $matches, PREG_OFFSET_CAPTURE)) {
2082 $insertPos = $matches[0][1] + strlen($matches[0][0]);
2083 return substr_replace($buffer, PHP_EOL . $htmlToPrepend, $insertPos, 0);
2084 }
2085
2086 // Fallback: no <head> tag found, return unchanged
2087 return $buffer;
2088 }
2089
2090 function berqwp_setup_dropin()
2091 {
2092 if (defined('BERQWP_ADVANCED_CACHE_PATH')) {
2093 $adv_cache_path = BERQWP_ADVANCED_CACHE_PATH;
2094 } else {
2095 $adv_cache_path = WP_CONTENT_DIR . '/advanced-cache.php';
2096 }
2097
2098 // Remove advanced-cache.php when sandbox mode is enabled
2099 if (get_option('berqwp_enable_sandbox') == 1) {
2100
2101 if (file_exists($adv_cache_path)) {
2102 @unlink($adv_cache_path);
2103 }
2104
2105 return;
2106 }
2107
2108 $bwp_adv_cache = optifer_PATH . 'advanced-cache.php';
2109
2110 if (!file_exists($adv_cache_path) || (file_exists($adv_cache_path) && is_writable($adv_cache_path))) {
2111 if (
2112 (!file_exists($adv_cache_path) && get_option('berqwp_enable_sandbox') !== 1)
2113 || (file_exists($adv_cache_path) && md5_file($adv_cache_path) !== md5_file($bwp_adv_cache))
2114 ) {
2115
2116 // Dynamically create the drop-in file
2117 $dropin_content = file_get_contents(optifer_PATH . 'advanced-cache.php');
2118
2119 // Write the drop-in content to the file, replacing any existing file
2120 file_put_contents($adv_cache_path, $dropin_content);
2121
2122 // Enable wp cache in wp-config.php
2123 berqwp_enable_advanced_cache(true);
2124 }
2125 }
2126
2127
2128 // if (get_option('berqwp_enable_sandbox') == 1 && file_exists($adv_cache_path)) {
2129 // unlink($adv_cache_path);
2130 // }
2131 }
2132
2133 function berqwp_is_file_url($url)
2134 {
2135 $parsed = parse_url($url);
2136 if (!isset($parsed['path']))
2137 return false;
2138
2139 $extension = pathinfo($parsed['path'], PATHINFO_EXTENSION);
2140
2141 // allow html pages
2142 if (strtolower($extension) === 'html' || strtolower($extension) === 'htm') {
2143 return false;
2144 }
2145
2146 // Returns true if there is a file extension, false otherwise
2147 return !empty($extension);
2148 }
2149
2150 function berqwp_clear_cache_queue()
2151 {
2152 $berqconfigs = berqConfigs::getInstance();
2153 $site_id = $berqconfigs->get_configs()['site_id'];
2154 $berqwp = new BerqWP(berqwp_get_license_key(), null, null);
2155 $berqwp->clear_cache_queue(home_url(), $site_id);
2156 }
2157
2158 function berqwp_sync_addons($license_key, $site_url)
2159 {
2160 if (empty($license_key) || empty($site_url)) {
2161 return false;
2162 }
2163
2164 $post_data = [
2165 'license_key' => $license_key,
2166 'site_url' => $site_url,
2167 ];
2168
2169 $args = array(
2170 'body' => wp_json_encode($post_data),
2171 'method' => 'POST',
2172 'timeout' => 20,
2173 'headers' => array(
2174 'Content-Type' => 'application/json',
2175 ),
2176 );
2177
2178 global $berq_log;
2179 $berq_log->info("Trigger addon sync");
2180
2181 $response = wp_remote_post('https://berqwp.com/wp-json/berqwp/active-addons', $args);
2182 $response_body = wp_remote_retrieve_body($response);
2183 $json = json_decode($response_body, true);
2184
2185 if (empty($json) || $json['status'] !== 'success') {
2186 return false;
2187 }
2188
2189 if (is_array($json['active_addons'])) {
2190
2191 $enable_fluid_images = in_array('fluid_images', $json['active_addons']);
2192 if ($enable_fluid_images && !get_option('berqwp_can_use_fluid_images')) {
2193 update_option('berqwp_can_use_fluid_images', 1);
2194 update_option('bwp_require_flush_cache', 1);
2195 } elseif (!$enable_fluid_images) {
2196 update_option('berqwp_can_use_fluid_images', 0);
2197 }
2198 }
2199 }
2200
2201 function berqwp_validate_url_array($urls)
2202 {
2203 $home_host = parse_url(home_url(), PHP_URL_HOST);
2204 $home_scheme = parse_url(home_url(), PHP_URL_SCHEME);
2205
2206 $urls = array_filter($urls, function ($url) use ($home_host) {
2207 $url_host = parse_url($url, PHP_URL_HOST);
2208
2209 // Relative URLs → treat as same host
2210 if (empty($url_host)) {
2211 return true;
2212 }
2213
2214 return $url_host === $home_host;
2215 });
2216
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;
2244 }
2245
2246 function berqwp_render_toggle($name, $checked) {
2247 ?>
2248 <label class="berq-toggle">
2249 <input type="checkbox" name="<?php echo esc_attr($name); ?>" <?php checked(1, $checked, true); ?>>
2250 <div class="berq-toggle-switch"></div>
2251 </label>
2252 <?php
2253 }
2254
2255 function berqwp_can_use_cloud() {
2256 $berqconfigs = berqConfigs::getInstance();
2257 $configs = $berqconfigs->get_configs();
2258 $license_key = berqwp_get_license_key();
2259
2260 return !empty($configs['site_id']) && !empty($configs['secret']) && !empty($configs['optimization_method']) && $configs['optimization_method'] == 'cloud' && !empty($license_key);
2261 }
2262