PluginProbe
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript / 4.1.20
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript v4.1.20
4.1.20 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 All 174 releases
searchpro / inc / cache / class-berqcache.php

class-berqcache.php in BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript 4.1.20, at inc/cache/class-berqcache.php

1,072 lines 37.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH'))
3 exit;
4
5 use BerqWP\BerqWP;
6
7 if (!class_exists('berqCache')) {
8 class berqCache
9 {
10 public static $instance = null;
11
12 function __construct()
13 {
14
15 $this->process_migration();
16
17 add_filter('berqwp_ignored_urls_params', [$this, 'ingore_tracking_params']);
18
19 add_action('template_redirect', [$this, 'queue_page'], 11);
20
21 if (!isset($_GET['bwp_preload'])) {
22 add_action('wp', [$this, 'html_cache'], 2);
23 }
24
25 // Clear page cache on update
26 add_action('save_post', [$this, 'clear_cache_on_post_update'], 10, 3);
27
28 // // Automatic cache warmup
29 // // add_action('init', [$this, 'warmup_home']);
30 // add_action('berqwp_flush_all_cache', [$this, 'warmup_home']);
31 // add_action('warmup_cache_quickly', 'warmup_cache_by_url');
32 // add_action('bwp_warmup_sitemap', [$this, 'warmup_sitemap']);
33 // add_action('berqwp_flush_all_cache', [$this, 'request_warmup_cache']);
34 // add_action('berqwp_cache_warmup', [$this, 'request_warmup_cache']);
35
36 // Delete cache files when the mode changes
37 // add_action('berqwp_before_update_optimization_mode', [$this, 'delete_cache_files']);
38 add_action('berqwp_on_update_optimization_mode', [$this, 'delete_cache_files']);
39
40 // Reverse proxy cache support
41 add_action('berqwp_stored_page_cache', [$this, 'flush_reverse_proxy_cache']);
42 add_action('berqwp_flush_all_cache', ['berqReverseProxyCache', 'flush_all']);
43 add_action('berqwp_flush_page_cache', [$this, 'flush_reverse_proxy_cache']);
44
45 // Clear cache warmup lock after storing the cache
46 add_action('berqwp_stored_page_cache', 'bwp_clear_warmup_lock');
47
48 // Log recently optimized pages
49 add_action('berqwp_stored_page_cache', 'bwp_log_recently_optimized_page', 20, 1);
50 add_action('berqwp_flush_all_cache', 'bwp_clear_recently_optimized_log');
51 add_action('berqwp_flush_page_cache', 'bwp_remove_recently_optimized_entry', 10, 1);
52
53 add_action('init', [$this, 'bypass_cache']);
54
55 // add_action('init', [$this, 'bypass_cache']);
56
57 // Flush cache when there's a new comment
58 add_action('wp_set_comment_status', [$this, 'handle_new_comment'], 10, 2);
59
60 // Store cache without any need for the rest api
61 add_action('init', 'bwp_webhook');
62
63 // Handle request new cache request
64 add_action('init', 'bwp_handle_request_cache');
65
66 // Flush cache when theme changes
67 add_action('switch_theme', [$this, 'delete_cache_files']);
68
69 // Flush critical css when theme changes
70 add_action('switch_theme', [$this, 'purge_critical_css_cache']);
71
72 // Flush critical css when custimizer additional css is updated
73 add_action('customize_save_css', [$this, 'purge_critical_css_cache']);
74
75 // Request cache when a post is published
76 // clear_cache_on_post_update and handle_post_status_update almost do the same thing
77 // add_action( 'transition_post_status', [$this, 'handle_post_status_update'], 10, 3 );
78
79 add_action('send_headers', [$this, 'brust_cache_for_loggedin']);
80
81 // Purge home page when new post is published
82 add_action('transition_post_status', [$this, 'purge_home'], 10, 3);
83
84 // flush cloudflare edge cache
85 add_action('berqwp_stored_page_cache', [$this, 'flush_cf_page']);
86 add_action('berqwp_flush_page_cache', [$this, 'flush_cf_page']);
87 add_action('berqwp_flush_all_cache', 'bwp_cf_flush_all');
88 add_action('berqwp_on_update_sandbox_mode', 'bwp_cf_flush_all');
89 add_action('berqwp_deactivate_plugin', 'bwp_cf_delete_rules');
90 add_action('berqwp_activate_plugin', [$this, 'check_cf_rules']);
91
92 // Apache htaccess cache rules (skip on LiteSpeed — remove any existing rules)
93 add_action('berqwp_activate_plugin', 'bwp_write_htaccess_rules');
94 add_action('berqwp_flush_all_cache', 'bwp_write_htaccess_rules');
95 add_action('berqwp_flush_all_cache', 'bwp_delete_php_files_in_cache');
96 add_action('berqwp_deactivate_plugin', 'bwp_remove_htaccess_rules');
97
98 // Keep the dropin's cached permalink convention in sync with WordPress
99 add_action('init', 'bwp_sync_permalink_config');
100 add_action('update_option_permalink_structure', 'bwp_sync_permalink_config');
101 add_action('berqwp_activate_plugin', 'bwp_sync_permalink_config');
102
103 if (bwp_is_openlitespeed_server()) {
104 add_action('berqwp_activate_plugin', 'bwp_remove_htaccess_rules');
105 }
106
107 add_action('berqwp_on_update_sandbox_mode', 'bwp_sync_htaccess_on_sandbox_change');
108
109 // Clear queue list on cloud
110 add_action('berqwp_deactivate_plugin', 'berqwp_clear_cache_queue');
111
112 // Edit post type list custom links
113 $bwp_post_types = get_option('berqwp_optimize_post_types');
114
115 if (is_admin() && !empty($bwp_post_types)) {
116 foreach ($bwp_post_types as $post_type) {
117 add_filter("{$post_type}_row_actions", [$this, 'post_type_action_links'], 10, 2);
118 }
119 }
120
121 // detect when theme/plugin is installed or updated
122 add_action( 'upgrader_process_complete', [$this, 'process_updates'], 10, 2 );
123
124 // handle menu update
125 add_action( 'wp_update_nav_menu', [$this, 'handle_menu_update'], 10, 2 );
126
127 // handle customizer save
128 add_action( 'customize_save', [$this, 'handle_customizer_update'] );
129
130 }
131
132 static function getInstance() {
133
134 if (self::$instance === null) {
135 $instance = new berqCache();
136 self::$instance = $instance;
137 return $instance;
138 }
139
140 return self::$instance;
141 }
142
143 function handle_customizer_update( $wp_customize ) {
144
145 global $berq_log;
146 $berq_log->info("Customizer updated");
147
148 $this->flush_all();
149
150 }
151
152 function handle_menu_update( $menu_id, $menu_data = null ) {
153
154 global $berq_log;
155 $berq_log->info("Site menu updated");
156
157 $this->flush_all();
158
159 }
160
161 function flush_all() {
162
163 global $berq_log;
164 $berq_log->info("Flushing everything");
165
166 if (berqwp_can_use_cloud()) {
167
168 // flush critical css
169 $this->purge_critical_css_cache();
170
171 // stale cdn
172 self::stale_cloud_assets();
173
174 }
175
176 // clear cache
177 $this->delete_cache_files();
178 }
179
180 function process_updates( WP_Upgrader $upgrader, array $hook_extra ) {
181
182 if (!berqwp_can_use_cloud()) {
183 return;
184 }
185
186 global $berq_log;
187 $berq_log->info("Processing updates");
188
189 self::stale_cloud_assets();
190 $this->purge_critical_css_cache();
191
192 // trigger cache warmup
193 do_action('berqwp_cache_warmup');
194
195 }
196
197 static function stale_cloud_assets() {
198 if (!berqwp_can_use_cloud()) {
199 return;
200 }
201
202 global $berq_log;
203 $berq_log->info("Marking cloud assets stale");
204
205 $berqwp = new BerqWP(berqwp_get_license_key(), null, null);
206 $parsed_url = wp_parse_url(home_url());
207 $domain = $parsed_url['host'];
208
209 // mark cdn assets stale
210 $berqwp->cdn_stale_assets($domain);
211
212 // flush all critical css cache
213 $berqwp->purge_critilclcss($domain);
214 }
215
216 function process_migration() {
217 $raw_home = get_option('home');
218
219 if (defined('WP_HOME')) {
220 $raw_home = WP_HOME;
221 }
222
223 // detect migration when home changes
224 if (get_option('berqwp_raw_home', $raw_home) !== $raw_home) {
225 global $berq_log;
226 $berq_log->info('Raw home url change detected, flushing all cache');
227
228 if (get_option('berqwp_raw_home', $raw_home) !== null) {
229 $berq_log->info('Home url change detected, flushing all cache');
230 }
231
232 // regenerate site id
233 $berqconfigs = berqConfigs::getInstance();
234 $blog_id = get_current_blog_id();
235 $network_id = function_exists('get_current_network_id') ? get_current_network_id() : 1;
236 $siteurl = get_option('siteurl');
237 $site_id = md5("berqwp|$network_id|$blog_id|$siteurl");
238
239 $berqconfigs->update_configs(['site_id' => $site_id, 'secret' => '']);
240
241
242 // Flush critical css
243 $parsed_url = wp_parse_url(home_url());
244 $domain = $parsed_url['host'];
245 $berqwp = new BerqWP(berqwp_get_license_key(), null, null);
246 $berqwp->purge_critilclcss($domain);
247
248 // Flush page cache
249 $this->delete_cache_files();
250
251 update_option('berqwp_raw_home', $raw_home);
252 delete_transient('berq_lic_response_cache');
253 delete_transient('berqwp_lic_response_cache');
254 }
255 }
256
257 function post_type_action_links($actions, $post)
258 {
259
260 $page_url = get_permalink($post->ID);
261 $url = wp_nonce_url(admin_url('admin-post.php?action=berq_purge_page&uri=' . urlencode($page_url)), 'berq_purge_page_action');
262
263 $actions['berqwp_flush_cache'] = '<a href="' . esc_url($url) . '">Flush Cache</a>';
264
265 $url = wp_nonce_url(admin_url('admin-post.php?action=berq_request_cache&uri=' . urlencode($page_url)), 'berq_request_cache_action');
266
267 $actions['berqwp_force_cache'] = '<a href="' . esc_url($url) . '">Force Cache</a>';
268
269 return $actions;
270 }
271
272 function check_cf_rules()
273 {
274 if (!empty(get_option('berqwp_cf_creden'))) {
275 $email = get_option('berqwp_cf_creden')['email'];
276 $apitoken = get_option('berqwp_cf_creden')['apitoken'];
277 $zoneid = get_option('berqwp_cf_creden')['zoneid'];
278 $berqCloudflareAPIHandler = new berqCloudflareAPIHandler($email, $apitoken, $zoneid);
279
280 if ($berqCloudflareAPIHandler->verify_credentials()) {
281 $berqCloudflareAPIHandler->add_rule();
282 $berqCloudflareAPIHandler->purge_all_cache();
283 return;
284 }
285
286 delete_option('berqwp_cf_creden');
287 }
288 }
289
290 function flush_author_cache($post_id)
291 {
292 // Bail out on autosaves and revisions
293 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
294 return;
295 if (wp_is_post_revision($post_id))
296 return;
297
298 $post = get_post($post_id);
299 if (!$post)
300 return;
301
302 global $berq_log;
303
304 // Get current author ID
305 $current_author_id = $post->post_author;
306
307 // Get original author ID before any potential changes
308 $original_post = wp_get_post_revision($post_id);
309 $original_author_id = $original_post ? $original_post->post_author : $current_author_id;
310
311 // Collect all author IDs that need flushing
312 $author_ids = array_unique([$current_author_id, $original_author_id]);
313
314 foreach ($author_ids as $author_id) {
315 // Skip invalid author IDs
316 if (!$author_id || !get_userdata($author_id))
317 continue;
318
319 // Get author archive URL
320 $author_link = get_author_posts_url($author_id);
321 if (!is_wp_error($author_link) && !empty($author_link)) {
322 $berq_log->info("Purging author cache: $author_link");
323 self::purge_page($author_link);
324
325 // Handle translations for multilingual author archives
326 $translation_urls = apply_filters('berqwp_page_translation_urls', [], $author_link);
327 if (!empty($translation_urls)) {
328 foreach ($translation_urls as $url) {
329 $berq_log->info("Purging author translation cache: $url");
330 self::purge_page($url);
331 }
332 }
333 }
334 }
335 }
336
337 function flush_post_taxonomy_cache($post_id)
338 {
339 // Bail out on autosaves and revisions.
340 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
341 return;
342 }
343 if (wp_is_post_revision($post_id)) {
344 return;
345 }
346
347 $post = get_post($post_id);
348 if (!$post) {
349 return;
350 }
351
352 global $berq_log;
353
354 // Get all taxonomies registered for this post type.
355 $taxonomies = get_object_taxonomies($post->post_type);
356 if (!empty($taxonomies)) {
357 // Clear the object term cache for the post.
358 clean_object_term_cache($post_id, $taxonomies);
359
360 // Loop through each taxonomy.
361 foreach ($taxonomies as $taxonomy) {
362
363 if (!in_array($taxonomy, get_option('berqwp_optimize_taxonomies'))) {
364 continue;
365 }
366
367 // Get all terms for this post in the current taxonomy.
368 $terms = get_the_terms($post_id, $taxonomy);
369 if (empty($terms) || is_wp_error($terms)) {
370 continue;
371 }
372
373 foreach ($terms as $term) {
374 // Clear the term cache for the original term.
375 clean_object_term_cache($term->term_id, $taxonomy);
376
377 // Collect terms to purge: original term and its ancestors (if hierarchical)
378 $terms_to_purge = array($term);
379
380 // Check if taxonomy is hierarchical to process ancestors
381 if (is_taxonomy_hierarchical($taxonomy)) {
382 $ancestor_ids = get_ancestors($term->term_id, $taxonomy, 'taxonomy');
383 foreach ($ancestor_ids as $ancestor_id) {
384 $ancestor_term = get_term($ancestor_id, $taxonomy);
385 if ($ancestor_term && !is_wp_error($ancestor_term)) {
386 $terms_to_purge[] = $ancestor_term;
387 }
388 }
389 }
390
391 // Process each term (original and ancestors)
392 foreach ($terms_to_purge as $term_to_purge) {
393 $term_link = get_term_link($term_to_purge);
394 if (is_wp_error($term_link)) {
395 continue;
396 }
397
398 $berq_log->info("Purging cache for term $term_link");
399 self::purge_page($term_link);
400
401 // Handle translations
402 $translation_urls = apply_filters('berqwp_page_translation_urls', array(), $term_link);
403 if (!empty($translation_urls)) {
404 foreach ($translation_urls as $url) {
405 $berq_log->info("Purging taxonomy translation for $url");
406 self::purge_page($url);
407 }
408 }
409 }
410 }
411 }
412 }
413 }
414
415 function purge_critical_css_cache()
416 {
417 $parsed_url = wp_parse_url(home_url());
418 $domain = $parsed_url['host'];
419 $berqwp = new BerqWP(berqwp_get_license_key(), null, null);
420 $berqwp->purge_critilclcss($domain);
421 }
422
423 function flush_cf_page($slug = '')
424 {
425 if (empty($slug)) {
426 $slug = '/';
427 }
428 $url = home_url($slug);
429 bwp_cf_flush_page($url);
430 }
431
432 function purge_home($new_status, $old_status, $post)
433 {
434
435 $can_flush_cache = apply_filters('berqwp_can_flush_home_cache_on_post_update', true);
436
437 if (!$can_flush_cache) {
438 return;
439 }
440
441 if ($new_status == 'draft' && $old_status == 'draft') {
442 return;
443 }
444
445 if ($new_status == 'auto-draft') {
446 return;
447 }
448
449 if ($new_status == 'trash') {
450 return;
451 }
452
453 if ($new_status == 'publish' && $old_status == 'publish') {
454 return;
455 }
456
457 // if ($old_status == 'new' && $new_status == 'draft') {
458 // return;
459 // }
460
461 // if statement skips when scheduled post publishes
462 // with admin wp cron request
463 // if (!is_admin()) {
464 // $berq_log->info('Trasition post status admin' . ' ' . $new_status);
465 // return;
466 // }
467
468 $post_types = apply_filters('berqwp_purge_home_post_types', ['post']);
469
470 if (in_array($post->post_type, $post_types)) {
471 global $berq_log;
472 $berq_log->info('Purging homepage. Triggered by post type: ' . $post->post_type . ' ' . $old_status . ' ' . $new_status);
473 $home_url = home_url('/');
474 self::purge_page($home_url);
475 warmup_cache_by_url($home_url, true);
476 }
477
478 $blog_page_id = get_option('page_for_posts');
479
480 if ($blog_page_id) {
481
482 $blog_url = get_permalink($blog_page_id);
483
484 global $berq_log;
485 $berq_log->info('Purging blog page: ' . $blog_url);
486
487 self::purge_page($blog_url);
488 warmup_cache_by_url($blog_url);
489 }
490 }
491
492 function brust_cache_for_loggedin()
493 {
494 if (is_user_logged_in()) {
495 // Add Vary: Cookie header to differentiate cached versions for logged-in users
496 header('Vary: Accept-Encoding, Cookie');
497 // header("Cache-Control: no-cache, no-store, must-revalidate");
498 // header("Pragma: no-cache");
499 // header("Expires: 0");
500 }
501 }
502
503 function handle_post_status_update($new_status, $old_status, $post)
504 {
505 // Get the post types that should be optimized from BerqWP settings
506 $post_types = get_option('berqwp_optimize_post_types');
507
508 // Get the published post URL
509 $post_url = get_permalink($post);
510
511 // Only proceed if the post is being published (from any status to 'publish')
512 if ('publish' === $new_status && 'publish' !== $old_status) {
513
514 // Check if the post type is in the list of types to be optimized
515 if (in_array($post->post_type, $post_types)) {
516
517 // We need path with query parameters
518 $parsed_url = parse_url($post_url);
519 $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
520 $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
521 $path_with_query = $path . $query;
522
523 if (berqwp_is_slug_excludable($path_with_query)) {
524 return;
525 }
526
527 global $berq_log;
528 $berq_log->info("Post status updated $post_url");
529
530 if (bwp_can_optimize_page_url($post_url)) {
531 warmup_cache_by_url($post_url);
532 }
533
534 self::purge_page($post_url, true);
535
536 $this->flush_post_taxonomy_cache($post->ID);
537 $this->flush_author_cache($post->ID);
538 }
539 }
540 }
541
542 public static function delete_page_cache_files($page_url)
543 {
544 $cache_file = bwp_get_cache_dir() . bwp_build_cache_path($page_url) . '/index.html.gz';
545
546 if (file_exists($cache_file)) {
547 unlink($cache_file);
548 }
549 }
550
551 public static function purge_page($page_url, $flush_criticalcss = false)
552 {
553
554 if (!berqwp_can_use_cloud()) {
555 $flush_criticalcss = false;
556 }
557
558 $page_url = strtolower($page_url);
559
560 // $page_path = bwp_intersect_str(home_url(), $page_path);
561 $slug = bwp_url_into_path($page_url);
562
563 self::delete_page_cache_files($page_url);
564
565 do_action('berqwp_flush_page_cache', $slug);
566
567 if ($flush_criticalcss) {
568 $berqwp = new BerqWP(berqwp_get_license_key(), null, null);
569 $berqwp->purge_criticlecss_url($page_url);
570 }
571
572 bwp_cf_flush_page(home_url($slug));
573 }
574
575 function handle_new_comment($comment_id, $comment_status)
576 {
577 if ($comment_status === 'approve') {
578 $comment = get_comment($comment_id);
579 $post_id = $comment->comment_post_ID;
580 $post_url = get_permalink($post_id);
581
582 self::purge_page($post_url);
583
584 global $berq_log;
585 $berq_log->info("New comment added, deleting cache for $post_url");
586 }
587 }
588
589 function bypass_cache()
590 {
591 if (
592 isset($_GET['nocache'])
593 || isset($_GET['bwp_preload'])
594 // || isset($_GET['creating_cache'])
595 || berqDetectCrawler::is_crawler() ||
596 (get_option('berqwp_enable_sandbox') == 1 && !isset($_GET['berqwp']) && !is_admin() && !isset($_POST))
597 ) {
598
599 add_filter('berqwp_bypass_cache', function () {
600 return true;
601 });
602
603 // if (berqReverseProxyCache::is_reverse_proxy_cache_enabled()) {
604 berqReverseProxyCache::bypass();
605 // }
606
607 }
608 }
609
610 function flush_reverse_proxy_cache($slug = '/.*')
611 {
612
613 if (empty($slug)) {
614 $slug = '/';
615 }
616
617 // if ($slug == '/') {
618 // $slug = '';
619 // }
620
621 $page_url = home_url($slug);
622 $host = !empty($_SERVER['HTTP_HOST']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_HOST'])) : '';
623 berqReverseProxyCache::purge_cache($page_url);
624 }
625
626 function ingore_tracking_params($tracking_params)
627 {
628 $tracking_params = array_merge($tracking_params, ignoreParams::$query_params);
629 return $tracking_params;
630 }
631
632 function clear_cache_on_post_update($post_id, $post, $update)
633 {
634
635 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
636 return;
637 }
638
639 // if (!$update) {
640 // return;
641 // }
642
643 $can_flush_cache = apply_filters('berqwp_can_flush_cache_on_post_update', true);
644
645 if (!$can_flush_cache) {
646 return;
647 }
648
649 // If this is just a revision, don't run the function.
650 if (wp_is_post_revision($post_id)) {
651 return;
652 }
653
654 // prevents scheduled post public
655 // via wp cron
656 // if (!is_admin()) {
657 // return;
658 // }
659
660 $post_type = get_post_type($post_id);
661 $post_url = get_permalink($post_id);
662
663 // We need path with query parameters
664 $parsed_url = parse_url($post_url);
665 $path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
666 $query = isset($parsed_url['query']) ? '?' . $parsed_url['query'] : '';
667 $path_with_query = $path . $query;
668
669 if (berqwp_is_slug_excludable($path_with_query)) {
670 return;
671 }
672
673 // Potentially cachable post types
674 $cachable_post_type_names = get_post_types(array(
675 'public' => true,
676 ), 'names');
677 unset($cachable_post_type_names['attachment']);
678
679 if (!in_array($post_type, $cachable_post_type_names)) {
680 return;
681 }
682
683 global $berq_log;
684 $berq_log->info("Post updated [Post type - $post_type]: $post_url $post->post_status");
685
686 self::purge_page($post_url, true);
687
688 if (bwp_can_optimize_page_url($post_url)) {
689 warmup_cache_by_url($post_url);
690 }
691
692 $translation_urls = apply_filters('berqwp_page_translation_urls', [], $post_url);
693
694 if (!empty($translation_urls)) {
695 foreach ($translation_urls as $url) {
696
697 $berq_log->info("Purging translation for $post_url");
698 self::purge_page($url, true);
699 }
700 }
701
702 $this->flush_post_taxonomy_cache($post_id);
703 $this->flush_author_cache($post_id);
704 }
705
706 function flush_cdn()
707 {
708 $parsed_url = wp_parse_url(home_url());
709 $domain = $parsed_url['host'];
710
711 $args = [
712 'timeout' => 30,
713 'sslverify' => false,
714 'body' => ['flush_cdn' => $domain, 'license_key' => berqwp_get_license_key()]
715 ];
716
717 wp_remote_post('https://boost.berqwp.com/photon/', $args);
718
719 // Flush cache
720 $this->delete_cache_files();
721
722 // clear local static files
723
724 $dir = optifer_cache . '/static/';
725
726 if (! is_dir($dir)) {
727 return;
728 }
729
730 $files = glob(rtrim($dir, '/') . '/*');
731
732 foreach ($files as $file) {
733 if (is_file($file)) {
734 unlink($file);
735 }
736 }
737
738 update_option('berqwp_uploaded_assets', [], false);
739
740 do_action('berqwp_purge_cdn');
741 }
742
743 function delete_cache_files($flush_all_sites = false)
744 {
745 global $berq_log;
746 $berq_log->info("Flushing all cache.");
747
748 // Define the cache directory
749 $cache_directory = bwp_get_cache_dir();
750
751 if (is_multisite() && $flush_all_sites) {
752 $cache_directory = optifer_cache . '/html/';
753 }
754
755 // Delete all cache files within the directory
756 berqwp_unlink_recursive($cache_directory);
757
758 // Delete external CSS cache
759 $external_cache_dir = optifer_cache . 'external/';
760 if (is_dir($external_cache_dir)) {
761 berqwp_unlink_recursive($external_cache_dir);
762 }
763
764 delete_transient('berqwp_warmup_running');
765 delete_transient('cache_warmup_in_progress');
766 delete_transient('berqwp_doing_cache_warmup');
767
768 // Remove require cache warning
769 update_option('bwp_require_flush_cache', 0);
770
771 do_action('berqwp_flush_all_cache');
772 }
773
774 static function should_cache() {
775 // Check if the current user is logged in and only allow GET requests
776 if (is_user_logged_in() || $_SERVER['REQUEST_METHOD'] !== 'GET') {
777 return false;
778 }
779
780 if (isset($_GET['creating_cache'])) {
781 return false;
782 }
783
784 if (is_admin() || is_preview() || is_404() || is_search()) {
785 return false;
786 }
787
788 if (defined('DOING_CRON') && DOING_CRON) {
789 return false;
790 }
791
792 if (defined('DOING_AJAX') && DOING_AJAX) {
793 return false;
794 }
795
796 if (defined('REST_REQUEST') && REST_REQUEST) {
797 return false;
798 }
799
800 if (php_sapi_name() === 'cli' || defined('WP_CLI')) {
801 return false;
802 }
803
804 if (!bwp_is_webpage()) {
805 return false;
806 }
807
808 if (!bwp_pass_cookie_requirement()) {
809 return false;
810 }
811
812 $berqconfigs = berqConfigs::getInstance();
813 $configs = $berqconfigs->get_configs();
814
815 if (empty($configs['optimization_method'])) {
816 return false;
817 }
818
819 if (berqwp_can_use_cloud()) {
820
821 if (empty(berqwp_get_license_key())) {
822 return false;
823 }
824
825 // if (!bwp_pass_account_requirement()) {
826 // return false;
827 // }
828
829 }
830
831
832 $bypass_cache = apply_filters('berqwp_bypass_cache', false);
833
834 if ($bypass_cache) {
835 return false;
836 }
837
838 return true;
839 }
840
841 static function get_page_url() {
842 $page_url = bwp_get_request_url();
843
844 // For sitemaps
845 if (strpos($page_url, '.xml') !== false || strpos($page_url, '.xsl') !== false) {
846 return;
847 }
848
849 // Return if page is excluded from cache
850 $current_page_url = bwp_get_request_url();
851
852 if (strpos($current_page_url, '?') !== false) {
853 $current_page_url = explode('?', $current_page_url)[0];
854 }
855
856 if (berqwp_is_page_url_excluded($current_page_url)) {
857 return;
858 }
859
860 // Remove ignored params from the slug
861 // $slug = berqwp_remove_ignore_params($slug_uri);
862 $page_url = berqwp_remove_ignore_params($page_url);
863
864 if (get_option('berqwp_enable_sandbox') == 1 && isset($_GET['berqwp'])) {
865 $page_url = explode('?berqwp', $page_url)[0];
866 } elseif (get_option('berqwp_enable_sandbox') == 1 && !isset($_GET['creating_cache'])) {
867 return false;
868 }
869
870 if (berqwp_is_slug_excludable($page_url)) {
871 return false;
872 }
873
874 return $page_url;
875 }
876
877 static function queue_page($page_url = null) {
878
879
880 if (empty($page_url)) {
881
882 if (!self::should_cache()) {
883 return;
884 }
885
886 $page_url = self::get_page_url();
887 }
888
889 if (empty($page_url)) {
890 return false;
891 }
892
893 // Disable cache for unknown query parameters
894 if (strpos($page_url, '?') !== false) {
895 return false;
896 }
897
898 if (!berqwp_can_use_cloud()) {
899 return false;
900 }
901
902 $status_code = http_response_code();
903
904 if ($status_code !== 200) {
905 return false;
906 }
907
908 // berqHeartbeat::add_queue($page_url);
909 warmup_cache_by_url($page_url);
910 }
911
912 static function miss_cache_headers() {
913 header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0', true);
914 header('CDN-Cache-Control: no-store', true); // Cloudflare
915 header('Surrogate-Control: no-store', true); // Varnish
916 header('X-Accel-Expires: 0', true); // Nginx FastCGI
917 header("X-BerqWP-Cache: MISS");
918 }
919
920 function html_cache()
921 {
922
923 // Bypass cache for Photon
924 if (!empty($_COOKIE['berqwpnocache'])) {
925 self::miss_cache_headers();
926 return;
927 }
928
929 if (!self::should_cache()) {
930 self::miss_cache_headers();
931 return;
932 }
933
934 $page_url = self::get_page_url();
935
936 if (empty($page_url)) {
937 self::miss_cache_headers();
938 return;
939 }
940
941 // Disable cache for unknown query parameters
942 if (strpos($page_url, '?') !== false) {
943 self::miss_cache_headers();
944 return;
945 }
946
947
948 // Redirect non-canonical URLs (wrong trailing slash) the same way WordPress would,
949 // before ever touching the cache — works for both trailing-slash and non-trailing-slash
950 // permalink structures.
951 $canonical_url = bwp_canonicalize_page_url($page_url);
952 if ($canonical_url !== $page_url) {
953 wp_safe_redirect($canonical_url, 301);
954 exit();
955 }
956
957 if (is_singular()) {
958 $post_type = get_post_type();
959
960 if (empty($post_type) || !in_array($post_type, get_option('berqwp_optimize_post_types'))) {
961 self::miss_cache_headers();
962 return;
963 }
964 } elseif (is_archive()) {
965 $queried_object = get_queried_object();
966
967 if ($queried_object instanceof WP_Term && !empty($queried_object->taxonomy)) {
968 $current_taxonomy = $queried_object->taxonomy;
969
970 if (!in_array($current_taxonomy, get_option('berqwp_optimize_taxonomies'))) {
971 self::miss_cache_headers();
972 return;
973 }
974 }
975 }
976
977
978 $status_code = http_response_code();
979
980 if ($status_code !== 200) {
981 self::miss_cache_headers();
982 return;
983 }
984
985 $berqconfigs = berqConfigs::getInstance();
986 $configs = $berqconfigs->get_configs();
987 $cache_key = md5($page_url);
988 $cache_directory = bwp_get_cache_dir();
989
990 $cache_file = $cache_directory . bwp_build_cache_path($page_url) . '/index.html.gz';
991 $cache_max_life = file_exists($cache_file) ? @filemtime($cache_file) + $configs['cache_lifespan'] : null;
992
993 if (file_exists($cache_file) && $cache_max_life > time()) {
994 header_remove('Content-Encoding');
995
996 $lastModified = filemtime($cache_file);
997 $etag = md5_file($cache_file);
998 header('ETag: ' . $etag);
999 header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $lastModified) . ' GMT');
1000 header('X-File-Size: ' . filesize($cache_file), true);
1001 header('Content-Type: text/html; charset=utf-8');
1002 header("X-served: WP Hook");
1003 header('Vary: Accept-Encoding, Cookie');
1004 header("X-BerqWP-Cache: HIT");
1005
1006 if ((isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lastModified) || (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] === $etag)) {
1007 // The client's cache is still valid based on Last-Modified, respond with a 304 Not Modified
1008 header('HTTP/1.1 304 Not Modified');
1009 // header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
1010 // header("Expires: 0");
1011 // header('Cache-Control: no-cache, must-revalidate');
1012
1013 header('Cache-Control: public, max-age=600, s-maxage=2592000, stale-while-revalidate=86400', true);
1014 header('cdn-cache-control: max-age=2592000');
1015 header('Cache-Tag: ' . wp_parse_url(home_url())['host']);
1016
1017 exit();
1018 }
1019
1020 // Prevent PHP/Apache from re-compressing the already-gzipped cache file
1021 if (ini_get('zlib.output_compression')) {
1022 ini_set('zlib.output_compression', 'Off');
1023 }
1024
1025 while (ob_get_level()) {
1026 ob_end_clean();
1027 }
1028
1029 header('Cache-Control: public, max-age=600, s-maxage=2592000, stale-while-revalidate=86400', true);
1030 header('cdn-cache-control: max-age=2592000');
1031 header('Cache-Tag: ' . wp_parse_url(home_url())['host']);
1032 // header("Content-Security-Policy: script-src 'self' blob: 'unsafe-inline'");
1033 header('Content-Encoding: gzip', true);
1034 header('Content-Length: ' . filesize($cache_file), true);
1035 readfile($cache_file);
1036 exit();
1037 }
1038
1039 self::miss_cache_headers();
1040
1041 self::purge_page($page_url);
1042
1043 if (!berqwp_can_use_cloud()) {
1044 try {
1045
1046 $berqPageOptimizer = new berqPageOptimizer();
1047 $berqPageOptimizer->set_slug(bwp_url_into_path($page_url));
1048 $berqPageOptimizer->set_page($page_url);
1049 $berqPageOptimizer->start_cache();
1050 unset($berqPageOptimizer);
1051
1052 } catch (Exception $e) {
1053 global $berq_log;
1054 $berq_log->error($e->getMessage());
1055 return;
1056 } catch (Throwable $e) {
1057 global $berq_log;
1058 $berq_log->error($e->getMessage());
1059 return;
1060 }
1061
1062 }
1063
1064 return;
1065 }
1066
1067 }
1068
1069 // $cache = new berqCache();
1070 $cache = berqCache::getInstance();
1071 }
1072