PluginProbe
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript / 4.1.16
BerqWP – All-In-One Optimization for Core Web Vitals, Cache, CDN, Images, CSS & JavaScript v4.1.16
4.1.16 4.1.15 4.1.14 4.1.13 4.1.12 4.1.11 4.1.10 4.0.30 4.0.29 4.0.28 4.0.27 4.0.26 4.0.24 4.0.25 4.0.23 4.0.22 4.0.21 4.0.19 4.0.18 4.0.17 4.0.16 1.9.3 1.9.4 1.9.5 1.9.6 All 170 releases
searchpro / inc / cache / class-berqcache.php

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

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