PluginProbe
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score / 3.6.3
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score v3.6.3
trunk 1.0 1.0.1 1.1 1.1.1 1.1.2 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1 2.1.1 2.1.2 2.2 2.2.1 All 69 releases
← All changes | includes/classes/Preloader.php +183 -17 2.13.6.3 View file →
@@ -9,8 +9,9 @@
9 9
10 10 use PoweredCache\Async\CachePreloader;
11 11 use function PoweredCache\Utils\permalink_structure_has_trailingslash;
12 12 use function PoweredCache\Utils\site_cache_dir;
13 +use const PoweredCache\Constants\DEFERRED_PRELOAD_QUEUE_CRON_NAME;
13 14
14 15 /**
15 16 * Class Preloader
16 17 */
@@ -29,8 +30,15 @@
29 30 */
30 31 private $cache_preloader;
31 32
32 33 /**
34 + * Tracks whether we’ve added any URLs this request
35 + *
36 + * @var $queue_dirty
37 + */
38 + private $queue_dirty = false;
39 +
40 + /**
33 41 * Return an instance of the current class
34 42 *
35 43 * @return Preloader
36 44 * @since 1.0
@@ -51,8 +59,10 @@
51 59 * Setup routine
52 60 */
53 61 public function setup() {
54 62 $this->settings = \PoweredCache\Utils\get_settings();
63 + add_filter( 'wp_resource_hints', [ $this, 'dns_prefetch' ], 10, 2 );
64 + add_filter( 'wp_resource_hints', [ $this, 'preconnect_resources' ], 10, 2 );
55 65
56 66 // bail if the preload not activated
57 67 if ( ! $this->settings['enable_cache_preload'] ) {
58 68 return;
@@ -57,10 +67,9 @@
57 67 if ( ! $this->settings['enable_cache_preload'] ) {
58 68 return;
59 69 }
60 70
61 - $this->cache_preloader = CachePreloader::factory();
62 - add_filter( 'wp_resource_hints', [ $this, 'dns_prefetch' ], 10, 2 );
71 + $this->get_preloader();
63 72
64 73 /**
65 74 * Page cache needs to be activated to get benefits of preloading
66 75 */
@@ -71,10 +80,12 @@
71 80 add_action( 'admin_bar_menu', [ $this, 'admin_bar_menu' ] );
72 81 add_action( 'admin_post_powered_cache_preload_cache', [ $this, 'start_preload' ] );
73 82 add_action( 'powered_cache_purge_all_cache', [ $this, 'setup_preload_queue' ] );
74 83 add_action( 'powered_cache_clean_site_cache_dir', [ $this, 'setup_preload_queue' ] );
75 - add_action( 'powered_cache_advanced_cache_purge_post', [ $this, 'add_purged_urls_to_preload_queue' ], 10, 2 );
84 + add_action( 'powered_cache_advanced_cache_purge_post', [ $this, 'deferred_preload_queue' ], 10, 2 );
76 85 add_action( 'powered_cache_expired_files_deleted', [ $this, 'add_expired_urls_to_preload_queue' ], 10, 2 );
86 + add_action( DEFERRED_PRELOAD_QUEUE_CRON_NAME, [ $this, 'add_purged_urls_to_preload_queue' ], 10, 2 );
87 + add_action( 'shutdown', [ $this, 'dispatch_preload_queue' ], 0 );
77 88 }
78 89
79 90 /**
80 91 * Preload Admin bar menu
@@ -101,13 +112,27 @@
101 112 )
102 113 );
103 114 }
104 115
116 +
105 117 /**
118 + * Get the instance of CachePreloader
119 + *
120 + * @return CachePreloader
121 + */
122 + private function get_preloader() {
123 + if ( ! $this->cache_preloader ) {
124 + $this->cache_preloader = CachePreloader::factory();
125 + }
126 +
127 + return $this->cache_preloader;
128 + }
129 +
130 + /**
106 131 * Add preloading items to queue
107 132 */
108 133 public function start_preload() {
109 - if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'powered_cache_preload_cache' ) ) {
134 + if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'powered_cache_preload_cache' ) ) { // phpcs:ignore
110 135 wp_nonce_ays( '' );
111 136 }
112 137
113 138 if ( POWERED_CACHE_IS_NETWORK && ! current_user_can( 'manage_network' ) ) {
@@ -121,8 +146,10 @@
121 146 wp_safe_redirect( esc_url_raw( $redirect_url ) );
122 147 exit;
123 148 }
124 149
150 + \PoweredCache\Utils\log( sprintf( 'Preload triggered from admin bar.' ) );
151 +
125 152 $this->setup_preload_queue();
126 153
127 154 $redirect_url = add_query_arg( 'pc_action', 'start_preload', wp_get_referer() );
128 155 wp_safe_redirect( esc_url_raw( $redirect_url ) );
@@ -133,9 +160,9 @@
133 160 * Setup preload
134 161 */
135 162 public function setup_preload_queue() {
136 163 // cancel existing process before populating
137 - $this->cache_preloader->cancel_process();
164 + $this->get_preloader()->cancel_process();
138 165
139 166 if ( POWERED_CACHE_IS_NETWORK ) {
140 167 $sites = get_sites( [ 'fields' => 'ids' ] );
141 168 foreach ( $sites as $site_id ) {
@@ -147,10 +174,8 @@
147 174 } else {
148 175 $this->populate_preload_queue();
149 176 }
150 177
151 - $this->cache_preloader->save()->dispatch();
152 -
153 178 if ( $this->settings['enable_sitemap_preload'] && function_exists( '\PoweredCachePremium\Utils\preload_sitemap' ) ) {
154 179 \PoweredCachePremium\Utils\preload_sitemap();
155 180 }
156 181 }
@@ -196,14 +221,46 @@
196 221 $preload_urls = array_merge( $preload_urls, $public_tax_term_urls );
197 222 \PoweredCache\Utils\log( sprintf( 'Public tax terms added to preload queue. ' ) );
198 223 }
199 224
225 + /**
226 + * Filters preload urls before sending to queue
227 + *
228 + * @hook populate_preload_queue_urls
229 + *
230 + * @param {array} $preload_urls The list of preload urls
231 + *
232 + * @return {array} New value.
233 + * @since 2.4
234 + */
235 + $preload_urls = apply_filters( 'populate_preload_queue_urls', $preload_urls );
236 +
200 237 foreach ( $preload_urls as $url ) {
201 - $this->cache_preloader->push_to_queue( $url );
238 + $this->add_url_to_preload_queue( $url );
202 239 }
203 240 }
204 241
242 + /**
243 + * Add URLs to preload queue with a delay
244 + *
245 + * @param int $post_id Post ID
246 + * @param array $urls The URL list of the related pages that will be preloaded
247 + *
248 + * @since 3.6
249 + */
250 + public function deferred_preload_queue( $post_id, $urls ) {
251 + \PoweredCache\Utils\log( sprintf( 'Post ID %d purged from cache, adding related URLs to preload queue with a delay.', $post_id ) );
252 + wp_schedule_single_event(
253 + time() + 10,
254 + DEFERRED_PRELOAD_QUEUE_CRON_NAME,
255 + [
256 + 'post_id' => $post_id,
257 + 'urls' => $urls,
258 + ]
259 + );
260 + }
205 261
262 +
206 263 /**
207 264 * Add related pages to preload queue when the cache got cleared
208 265 *
209 266 * @param int $post_id Post ID
@@ -211,18 +268,23 @@
211 268 *
212 269 * @since 2.0
213 270 */
214 271 public function add_purged_urls_to_preload_queue( $post_id, $urls ) {
272 + $post_url = get_permalink( $post_id );
273 +
274 + // include post itself all the time
275 + if ( ! empty( $post_url ) ) {
276 + $this->add_url_to_preload_queue( $post_url );
277 + }
278 +
215 279 if ( ! $urls ) {
216 280 return;
217 281 }
218 282
219 283 foreach ( $urls as $url ) {
220 - $this->cache_preloader->push_to_queue( $url );
221 - \PoweredCache\Utils\log( sprintf( 'Pushed to preload queue [add_purged_urls_to_preload_queue]: %s', $url ) );
284 + $this->add_url_to_preload_queue( $url );
222 285 }
223 286
224 - $this->cache_preloader->save()->dispatch();
225 287 }
226 288
227 289 /**
228 290 * Requeue deleted URLs
@@ -266,13 +328,11 @@
266 328 foreach ( $expired_urls as $url ) {
267 329 if ( $has_trailingslash ) {
268 330 $url = trailingslashit( $url );
269 331 }
270 - $this->cache_preloader->push_to_queue( $url );
271 - \PoweredCache\Utils\log( sprintf( 'Pushed to preload queue [add_expired_urls_to_preload_queue]: %s', $url ) );
332 + $this->add_url_to_preload_queue( $url );
272 333 }
273 334
274 - $this->cache_preloader->save()->dispatch();
275 335 }
276 336
277 337 /**
278 338 * Prep. public post urls for preload queue
@@ -446,8 +506,9 @@
446 506 * @param array $urls URLs to print for resource hints.
447 507 * @param string $relation_type The relation type the URLs are printed for, e.g. 'preconnect' or 'prerender'.
448 508 *
449 509 * @return array $urls resource hints
510 + * @since 2.2 "preconnect" hint split from dns prefetch
450 511 */
451 512 public function dns_prefetch( $urls, $relation_type ) {
452 513 $domains = $this->get_prefetch_dns();
453 514 if ( $domains && is_array( $domains ) ) {
@@ -452,11 +513,30 @@
452 513 $domains = $this->get_prefetch_dns();
453 514 if ( $domains && is_array( $domains ) ) {
454 515 foreach ( $domains as $domain ) {
455 516 if ( 'dns-prefetch' === $relation_type ) {
517 + $domain = str_replace( [ 'http://', 'https://' ], '//', $domain );
456 518 $urls[] = $domain;
457 519 }
520 + }
521 + }
458 522
523 + return $urls;
524 + }
525 +
526 + /**
527 + * Add "preconnect" hint for critical resources
528 + *
529 + * @param array $urls URLs
530 + * @param string $relation_type the type of hint
531 + *
532 + * @return array $urls Resource list
533 + * @since 2.2
534 + */
535 + public function preconnect_resources( $urls, $relation_type ) {
536 + $domains = $this->get_preconnect_resources();
537 + if ( $domains && is_array( $domains ) ) {
538 + foreach ( $domains as $domain ) {
459 539 if ( 'preconnect' === $relation_type ) {
460 540 $parsed = wp_parse_url( $domain );
461 541 if ( empty( $parsed['scheme'] ) ) {
462 542 $domain = set_url_scheme( $domain );
@@ -494,9 +574,33 @@
494 574 */
495 575 return apply_filters( 'powered_cache_prefetch_dns', $prefetch_dns );
496 576 }
497 577
578 + /**
579 + * Get the list of preconnect domains
580 + *
581 + * @return mixed|void
582 + * @since 2.2
583 + */
584 + public function get_preconnect_resources() {
585 + $settings = \PoweredCache\Utils\get_settings();
498 586
587 + $preconnect_resources = preg_split( '#(\r\n|\r|\n)#', $settings['preconnect_resource'], - 1, PREG_SPLIT_NO_EMPTY );
588 +
589 + /**
590 + * Filters Preconnect resource list.
591 + *
592 + * @hook powered_cache_preconnect_resource
593 + *
594 + * @param {array} $preconnect_resources The list of prefetch domains.
595 + *
596 + * @return {array} New value.
597 + * @since 2.2
598 + */
599 + return apply_filters( 'powered_cache_preconnect_resource', $preconnect_resources );
600 + }
601 +
602 +
499 603 /**
500 604 * Make preload request
501 605 *
502 606 * @param string $url Target URL
@@ -539,9 +643,9 @@
539 643 * @since 2.0
540 644 */
541 645 do_action( 'powered_cache_preload_http_request', $url, $args );
542 646
543 - \PoweredCache\Utils\log( sprintf( 'Preloading...%s: %s', $url, print_r( $args, true ) ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
647 + \PoweredCache\Utils\log( sprintf( 'Processing..: %s', $url ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
544 648
545 649 return wp_remote_get( esc_url_raw( $url ), $args );
546 650 }
547 651
@@ -555,14 +659,29 @@
555 659 * Filters wait time between preload requests.
556 660 *
557 661 * @hook powered_cache_preload_request_interval
558 662 *
559 - * @param {int} $delay Delay time in milliseconds.
663 + * @param {int} $delay Delay time in microseconds.
560 664 *
561 665 * @return {int} New value.
562 666 * @since 2.0
563 667 */
564 - usleep( absint( apply_filters( 'powered_cache_preload_request_interval', $delay ) ) );
668 + $delay = absint( apply_filters( 'powered_cache_preload_request_interval', $delay ) );
669 +
670 + // Convert the delay to seconds and microseconds
671 + $seconds = intdiv( $delay, 1000000 ); // Get full seconds
672 + $microseconds = $delay % 1000000; // Get remaining microseconds
673 +
674 + // Use sleep() for full second delays
675 + if ( $seconds > 0 ) {
676 + sleep( $seconds );
677 + }
678 +
679 + // Use usleep() for remaining microseconds
680 + // sleeping more than 1 seconds may not be supported by the operating system with usleep
681 + if ( $microseconds > 0 ) {
682 + usleep( $microseconds );
683 + }
565 684 }
566 685
567 686
568 687 /**
@@ -581,7 +700,54 @@
581 700 * @return {string} New value.
582 701 * @since 2.0
583 702 */
584 703 return apply_filters( 'powered_cache_preload_mobile_user_agent', 'Powered Cache Preloader mobile iPhone' );
704 + }
705 +
706 + /**
707 + * Add a URL to the preload queue with optional filtering.
708 + *
709 + * @param string $url The URL to add to the preload queue.
710 + *
711 + * @since 3.4
712 + */
713 + protected function add_url_to_preload_queue( $url ) {
714 + /**
715 + * Filters whether a URL should be added to the preload queue.
716 + *
717 + * @hook powered_cache_preload_add_url_to_queue
718 + *
719 + * @param {boolean} $preload Whether to preload the URL. Default true.
720 + * @param {string} $url The URL to be preloaded.
721 + *
722 + * @return {boolean} Whether to preload the URL.
723 + * @since 3.4
724 + */
725 + $do_preload = apply_filters( 'powered_cache_preload_add_url_to_queue', true, $url );
726 +
727 + if ( $do_preload ) {
728 + $this->get_preloader()->push_to_queue( $url );
729 + $this->queue_dirty = true;
730 + \PoweredCache\Utils\log( sprintf( 'URL added to preload queue : %s', $url ) );
731 + } else {
732 + \PoweredCache\Utils\log( sprintf( 'URL skipped from preload queue: %s', $url ) );
733 + }
734 + }
735 +
736 + /**
737 + * Dispatch the preload queue if it has been modified.
738 + *
739 + * @return void
740 + * @since 3.6
741 + */
742 + public function dispatch_preload_queue() {
743 + if ( ! $this->queue_dirty ) {
744 + return;
745 + }
746 +
747 + // This will serialize the queue into the DB and fire off the async request
748 + $this->get_preloader()->save()->dispatch();
749 +
750 + \PoweredCache\Utils\log( 'Dispatched preload queue.' );
585 751 }
586 752
587 753 }