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