PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / trunk
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization vtrunk
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / functions.php
nitropack Last commit date
assets 3 days ago classes 3 days ago languages 1 month ago nitropack-sdk 2 weeks ago view 3 days ago batcache-compat.php 1 year ago constants.php 3 days ago functions.php 3 days ago helpers.php 1 year ago main.php 3 days ago readme.txt 3 days ago uninstall.php 7 months ago
functions.php
2782 lines
1 <?php
2
3 defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
4
5 use NitroPack\WordPress\Settings\TestMode;
6
7 $np_basePath = dirname( __FILE__ ) . '/';
8 require_once $np_basePath . 'nitropack-sdk/autoload.php';
9 require_once $np_basePath . 'constants.php';
10
11 $np_originalRequestCookies = $_COOKIE;
12 $np_customExpirationTimes = array();
13 $np_queriedObj = NULL;
14 $np_loggedPurges = array();
15 $np_loggedInvalidations = array();
16 $np_integrationSetupEvent = "muplugins_loaded";
17
18 function nitropack_is_logged_in() {
19 $nitro = get_nitropack_sdk();
20 $useAccountOverride = $nitro !== NULL && $nitro->isStatefulCacheSatisfied( "account" );
21 if ( $useAccountOverride ) {
22 return false;
23 }
24
25 //used for previewing the site while logged in
26 if ( ! empty( $_GET['previewmode'] ) ) {
27 return false;
28 }
29
30 $loginCookies = array( defined( 'NITROPACK_LOGGED_IN_COOKIE' ) ? NITROPACK_LOGGED_IN_COOKIE : ( defined( 'LOGGED_IN_COOKIE' ) ? LOGGED_IN_COOKIE : '' ) );
31 foreach ( $loginCookies as $loginCookie ) {
32 if ( ! empty( $_COOKIE[ $loginCookie ] ) ) {
33 $parts = explode( '|', urldecode( $_COOKIE[ $loginCookie ] ) );
34 if ( count( $parts ) < 3 ) {
35 continue; // Invalid cookie
36 }
37
38 return time() <= (int) $parts[1];
39 }
40 }
41 $cookieStr = implode( "|", array_keys( $_COOKIE ) );
42
43 return strpos( $cookieStr, "wordpress_logged_in_" ) !== false;
44 }
45
46 function nitropack_passes_cookie_requirements() {
47 $isUserLoggedIn = nitropack_is_logged_in();
48 $cookieStr = implode( "|", array_keys( $_COOKIE ) );
49 $safeCookie = (
50 ( strpos( $cookieStr, "comment_author" ) === false || ! ! get_nitropack()->setDisabledReason( "comment author" ) )
51 && ( strpos( $cookieStr, "wp-postpass_" ) === false || ! ! get_nitropack()->setDisabledReason( "password protected page" ) )
52 );
53
54 $isItemsInCart = ! empty( $_COOKIE["woocommerce_items_in_cart"] );
55 $useCartOverride = nitropack_is_cart_cache_active();
56
57 if ( $isUserLoggedIn ) {
58 get_nitropack()->setDisabledReason( "logged in" );
59 }
60
61 if ( $isItemsInCart && ! $useCartOverride ) {
62 get_nitropack()->setDisabledReason( "items in cart" );
63 }
64
65 // allow registering filters to "nitropack_passes_cookie_requirements"
66 return apply_filters( "nitropack_passes_cookie_requirements", $safeCookie && ( ! $isItemsInCart || $useCartOverride ) && ( ! $isUserLoggedIn ) );
67 }
68
69 function nitropack_activate() {
70 nitropack_set_wp_cache_const( true );
71
72 $htaccessFile = nitropack_trailingslashit( NITROPACK_DATA_DIR ) . ".htaccess";
73 if ( ! file_exists( $htaccessFile ) && get_nitropack()->initDataDir() ) {
74 file_put_contents( $htaccessFile, "deny from all" );
75 }
76
77 $pluginHtaccessFile = nitropack_trailingslashit( NITROPACK_PLUGIN_DATA_DIR ) . ".htaccess";
78 if ( ! file_exists( $pluginHtaccessFile ) && get_nitropack()->initPluginDataDir() ) {
79 file_put_contents( $pluginHtaccessFile, "deny from all" ); // TODO: Convert this to use the Filesystem abstraction for better Redis support
80 }
81 $advanced_cache = new \NitroPack\WordPress\AdvancedCache\AdvancedCache();
82 $advanced_cache->install_advanced_cache();
83
84 // Htaccess mods need to happen after installing the advanced cache file so the healthcheck can execute fast
85 nitropack_set_htaccess_rules( true );
86
87 try {
88 do_action( 'nitropack_integration_purge_all' );
89 } catch (\Exception $e) {
90 // Exception while signaling our 3rd party integration addons to purge their cache
91 }
92
93 if ( get_nitropack()->isConnected() ) {
94 nitropack_event( "enable_extension" );
95 // Refresh needed to make sure we have the latest config
96 get_nitropack()->settings->set_required_settings();
97 } else {
98 setcookie( "nitropack_after_activate_notice", 1, time() + 3600 );
99 }
100
101 if ( function_exists( "opcache_reset" ) ) {
102 opcache_reset();
103 }
104 ( new \NitroPack\WordPress\Cron() )->schedule_events();
105
106 // Avoid redirecting when bulk activating plugins
107 if (
108 ( isset( $_REQUEST['action'] ) && 'activate-selected' === $_REQUEST['action'] ) &&
109 ( isset( $_POST['checked'] ) && count( $_POST['checked'] ) > 1 ) ) {
110 return;
111 }
112 add_option( 'nitropack-activation-redirect', wp_get_current_user()->ID );
113
114 }
115
116 function nitropack_activation_redirect() {
117 if ( defined( 'DOING_AJAX' ) || defined( 'WP_CLI' ) ) {
118 return;
119 }
120 global $pagenow;
121 $allowed_pages = [ 'plugins.php', 'plugin-install.php' ];
122 if ( ! in_array( $pagenow, $allowed_pages, true ) ) {
123 return;
124 }
125 // Make sure it's the correct user
126 if ( intval( get_option( 'nitropack-activation-redirect', false ) ) === wp_get_current_user()->ID ) {
127 delete_option( 'nitropack-activation-redirect' );
128 wp_safe_redirect( admin_url( 'admin.php?page=nitropack' ) );
129 exit;
130 }
131 }
132 add_action( 'admin_init', 'nitropack_activation_redirect' );
133
134 function nitropack_deactivate() {
135 nitropack_set_htaccess_rules( false );
136 nitropack_set_wp_cache_const( false );
137 $advanced_cache = new \Nitropack\WordPress\AdvancedCache\AdvancedCache();
138 $advanced_cache->uninstall_advanced_cache();
139
140 try {
141 do_action( 'nitropack_integration_purge_all' );
142 } catch (\Exception $e) {
143 // Exception while signaling our 3rd party integration addons to purge their cache
144 }
145
146 if ( get_nitropack()->isConnected() ) {
147 nitropack_event( "disable_extension" );
148 }
149
150 if ( function_exists( "opcache_reset" ) ) {
151 opcache_reset();
152 }
153 // Unscheduling events from the cron.
154 \NitroPack\WordPress\Cron::unschedule_events();
155 }
156
157
158
159 function nitropack_set_wp_cache_const( $status ) {
160 if ( \NitroPack\Integration\Hosting\Flywheel::detect() ) { // Flywheel: This is configured throught the FW control panel
161 return true;
162 }
163
164 if ( \NitroPack\Integration\Hosting\Pressable::detect() ) { // Pressable: We need to deal with Batcache here
165 return nitropack_set_batcache_compat( $status );
166 }
167
168 $configFilePath = nitropack_get_wpconfig_path();
169 if ( ! $configFilePath )
170 return false;
171
172 $newVal = sprintf( "define( 'WP_CACHE', %s /* Modified by NitroPack */ );\n", ( $status ? "true" : "false" ) );
173 $replacementVal = sprintf( " %s /* Modified by NitroPack */ ", ( $status ? "true" : "false" ) );
174 $lines = file( $configFilePath );
175
176 if ( empty( $lines ) )
177 return false;
178
179 $wpCacheFound = false;
180 $phpOpeningTagLine = false;
181
182 foreach ( $lines as $lineIndex => &$line ) {
183 if ( strpos( $line, "<?php" ) !== false && strpos( $line, "?>" ) === false ) {
184 $phpOpeningTagLine = $lineIndex;
185 }
186
187 if ( ! $wpCacheFound && preg_match( "/define\s*\(\s*['\"](.*?)['\"].?,(.*?)\)/", $line, $matches ) ) {
188 if ( $matches[1] == "WP_CACHE" ) {
189 $line = str_replace( $matches[2], $replacementVal, $line );
190 $wpCacheFound = true;
191 }
192 }
193
194 if ( $phpOpeningTagLine !== false && $wpCacheFound !== false )
195 break;
196 }
197
198 if ( ! $wpCacheFound ) {
199 if ( ! $status )
200 return true; // No need to modify the file at all
201
202 if ( $phpOpeningTagLine !== false ) {
203 array_splice( $lines, $phpOpeningTagLine + 1, 0, [ $newVal ] );
204 } else {
205 array_unshift( $lines, "<?php " . trim( $newVal ) . " ?>\n" );
206 }
207 }
208
209 return WP_DEBUG ? file_put_contents( $configFilePath, implode( "", $lines ) ) : @file_put_contents( $configFilePath, implode( "", $lines ) );
210 }
211
212 function nitropack_set_htaccess_rules( $status ) {
213 if ( ! apply_filters( 'nitropack_should_modify_htaccess', false ) )
214 return true;
215
216 $htaccessFilePath = nitropack_get_htaccess_path();
217 if ( ! $htaccessFilePath )
218 return false;
219
220 $htaccessBackupFilePath = $htaccessFilePath . ".nitrobackup";
221 $backupExists = WP_DEBUG ? file_exists( $htaccessBackupFilePath ) : @file_exists( $htaccessBackupFilePath );
222 if ( ! $backupExists ) {
223 $isBackupSuccess = WP_DEBUG ? copy( $htaccessFilePath, $htaccessBackupFilePath ) : @copy( $htaccessFilePath, $htaccessBackupFilePath );
224 if ( ! $isBackupSuccess )
225 return false;
226 }
227
228 $lines = file( $htaccessFilePath );
229 $linesBackup = $lines;
230
231 if ( empty( $lines ) )
232 return false; // We might want to remove this check
233
234 // Remove the old LiteSpeed rules. We need to do this because LiteSpeed's rules are not compatible with NitroPack's rules.
235 if ( $status ) {
236
237 $nitroLsOpenLine = false;
238 $nitroLsCloseLine = false;
239
240 foreach ( $lines as $lineIndex => &$line ) {
241 if ( trim( $line ) == "# BEGIN LSCACHE" ) {
242 $nitroLsOpenLine = $lineIndex;
243 }
244
245 if ( trim( $line ) == "# END LSCACHE" ) {
246 $nitroLsCloseLine = $lineIndex;
247 }
248 }
249
250 if ( $nitroLsOpenLine !== false && $nitroLsCloseLine !== false && $nitroLsCloseLine > $nitroLsOpenLine ) {
251
252 array_splice( $lines, $nitroLsOpenLine, $nitroLsCloseLine - $nitroLsOpenLine + 1 );
253 }
254 }
255
256 $nitroOpenLine = false;
257 $nitroCloseLine = false;
258
259 foreach ( $lines as $lineIndex => &$line ) {
260 if ( trim( $line ) == "# BEGIN NITROPACK" ) {
261 $nitroOpenLine = $lineIndex;
262 }
263
264 if ( trim( $line ) == "# END NITROPACK" ) {
265 $nitroCloseLine = $lineIndex;
266 }
267 }
268
269 $nitroLines = [];
270
271 if ( // We either didn't find the NitroPack markers or we found both in the correct order
272 ( $nitroOpenLine === false && $nitroCloseLine === false ) ||
273 ( $nitroOpenLine !== false && $nitroCloseLine !== false && $nitroCloseLine > $nitroOpenLine )
274 ) {
275 $nitroLines[] = "# BEGIN NITROPACK";
276 if ( $status ) {
277 $rules = apply_filters( "nitropack_htaccess_rules", [] );
278
279 if ( is_string( $rules ) ) {
280 $rules = explode( "\n", $rules );
281 }
282
283 if ( is_array( $rules ) ) {
284 $nitroLines = array_merge( $nitroLines, $rules );
285 }
286 }
287 $nitroLines[] = "# END NITROPACK";
288 $nitroLines = array_map( function ( $line ) {
289 return trim( $line ) . "\n";
290 }, $nitroLines );
291
292 // Begin .htaccess modification
293 $offset = $nitroOpenLine !== false ? $nitroOpenLine : 0;
294 $length = $nitroOpenLine !== false ? $nitroCloseLine - $nitroOpenLine + 1 : 0;
295 array_splice( $lines, $offset, $length, $nitroLines );
296 $writeResult = WP_DEBUG ? file_put_contents( $htaccessFilePath, implode( "", $lines ) ) : @file_put_contents( $htaccessFilePath, implode( "", $lines ) );
297 if ( $writeResult ) {
298 $homeUrl = NULL;
299 $siteConfig = get_nitropack()->getSiteConfig();
300
301 if ( $siteConfig && ! empty( $siteConfig["home_url"] ) ) {
302 $homeUrl = $siteConfig["home_url"];
303 } else if ( function_exists( get_home_url() ) ) {
304 $homeUrl = get_home_url();
305 }
306
307 if ( $homeUrl ) {
308 $homeUrl .= ( strpos( $homeUrl, "?" ) === false ? "?" : "&" ) . "nitroHealthcheck=1";
309 try {
310 $client = new \NitroPack\HttpClient\HttpClient( $homeUrl );
311 $client->timeout = 5;
312 $client->setHeader( "Accept", "text/html" );
313 $client->fetch();
314 if ( $client->getStatusCode() != 200 ) {
315 // Restore the initial version of the file
316 WP_DEBUG ? file_put_contents( $htaccessFilePath, implode( "", $linesBackup ) ) : @file_put_contents( $htaccessFilePath, implode( "", $linesBackup ) );
317 return false;
318 }
319 } catch (\Exception $e) {
320 return false;
321 // Unfortunately we can't be certain whether an issue appeared due to the .htaccess mods
322 // There are no known cases of this happening, so it's fairly safe to assume that all is fine
323 // There are server setups which do not allow loopback requests, which is the more likely reason to end up here
324 // However we can't be certain which one it is, so we are taking the safer approach
325 }
326 } else {
327 return false;
328 }
329 }
330 return $writeResult;
331 }
332
333 return true;
334 }
335
336 function nitropack_set_batcache_compat( $status ) {
337 $currentCompatStatus = defined( "NITROPACK_BATCACHE_COMPAT" ) && NITROPACK_BATCACHE_COMPAT;
338 if ( $currentCompatStatus === $status )
339 return true;
340
341 $configFilePath = nitropack_get_wpconfig_path();
342 if ( ! $configFilePath )
343 return false;
344
345 $batCacheFilePath = NITROPACK_PLUGIN_DIR . "batcache-compat.php";
346 $compatInclude = sprintf( "if (file_exists(\"%s\")) { require_once \"%s\"; } // NitroPack compatibility with Batcache\n", $batCacheFilePath, $batCacheFilePath );
347 $lines = file( $configFilePath );
348
349 if ( empty( $lines ) )
350 return false;
351
352 foreach ( $lines as $lineIndex => &$line ) {
353 if ( preg_match( "/nitropack.*?batcache/i", $line ) ) {
354 $line = "//REMOVE AT FILTER";
355 }
356 }
357
358 $newLines = array_filter( $lines, function ( $line ) {
359 return $line != "//REMOVE AT FILTER";
360 } );
361
362 if ( $status ) {
363 $phpOpeningTagLine = false;
364
365 unset( $line );
366 foreach ( $newLines as $lineIndex => $line ) {
367 if ( strpos( $line, "<?php" ) !== false && strpos( $line, "?>" ) === false ) {
368 $phpOpeningTagLine = $lineIndex;
369 break;
370 }
371 }
372
373 if ( $phpOpeningTagLine !== false ) {
374 array_splice( $newLines, $phpOpeningTagLine + 1, 0, [ $compatInclude ] );
375 } else {
376 array_unshift( $newLines, "<?php " . trim( $compatInclude ) . " ?>\n" );
377 }
378 }
379
380 return WP_DEBUG ? file_put_contents( $configFilePath, implode( "", $newLines ) ) : @file_put_contents( $configFilePath, implode( "", $newLines ) );
381 }
382
383 function is_valid_nitropack_webhook() {
384 return ! empty( $_GET["nitroWebhook"] ) && ! empty( $_GET["token"] ) && nitropack_validate_webhook_token( $_GET["token"] );
385 }
386
387 function is_valid_nitropack_beacon() {
388 if ( ! isset( $_POST["nitroBeaconUrl"] ) || ! isset( $_POST["nitroBeaconHash"] ) )
389 return false;
390
391 $siteConfig = nitropack_get_site_config();
392 if ( ! $siteConfig || empty( $siteConfig["siteSecret"] ) )
393 return false;
394
395
396 if ( function_exists( "hash_hmac" ) && function_exists( "hash_equals" ) ) {
397 $url = base64_decode( $_POST["nitroBeaconUrl"] );
398 $cookiesJson = ! empty( $_POST["nitroBeaconCookies"] ) ? base64_decode( $_POST["nitroBeaconCookies"] ) : ""; // We need to fall back to empty string to remain backwards compatible. Otherwise cache files invalidated before an upgrade will never get updated :(
399 $layout = ! empty( $_POST["layout"] ) ? $_POST["layout"] : "";
400 $localHash = hash_hmac( "sha512", $url . $cookiesJson . $layout, $siteConfig["siteSecret"] );
401 return hash_equals( $_POST["nitroBeaconHash"], $localHash );
402 } else {
403 return ! empty( $_POST["nitroBeaconUrl"] );
404 }
405 }
406
407 function nitropack_handle_beacon() {
408 global $np_originalRequestCookies;
409 if ( ! defined( "NITROPACK_BEACON_HANDLED" ) ) {
410 define( "NITROPACK_BEACON_HANDLED", 1 );
411 } else {
412 return;
413 }
414
415 $siteConfig = nitropack_get_site_config();
416 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) && ! empty( $_POST["nitroBeaconUrl"] ) ) {
417 $url = base64_decode( $_POST["nitroBeaconUrl"] );
418
419 if ( ! empty( $_POST["nitroBeaconCookies"] ) ) {
420 $np_originalRequestCookies = json_decode( base64_decode( $_POST["nitroBeaconCookies"] ), true );
421 }
422
423 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Beacon request received for URL: ' . $url );
424
425 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"], $url ) ) {
426 try {
427
428 $hasLocalCache = $nitro->hasLocalCache( false );
429 $needsHeartbeat = nitropack_is_heartbeat_needed();
430 $proxyPurgeOnly = ! empty( $_POST["proxyPurgeOnly"] );
431 $layout = ! empty( $_POST["layout"] ) ? $_POST["layout"] : "default";
432 $output = "";
433
434 if ( ! $proxyPurgeOnly ) {
435 if ( ! $hasLocalCache ) {
436 nitropack_header( "X-Nitro-Beacon: FORWARD" );
437 try {
438 $hasCache = $nitro->hasRemoteCache( $layout, false ); // Download the new cache file
439 $hasLocalCache = $hasCache;
440 $output = sprintf( "Cache %s", $hasCache ? "fetched" : "requested" );
441 } catch (\Exception $e) {
442 // not a critical error, do nothing
443 }
444 } else {
445 nitropack_header( "X-Nitro-Beacon: SKIP" );
446 $output = sprintf( "Cache exists already" );
447 }
448 }
449
450 if ( $hasLocalCache || $proxyPurgeOnly/* || $needsHeartbeat*/ ) { // proxyPurgeOnly is set for unsupported browsers, in which case we need to purge the cache regardless of the existence of local NP cache
451 nitropack_header( "X-Nitro-Proxy-Purge: true" );
452 $nitro->purgeProxyCache( $url );
453 do_action( 'nitropack_integration_purge_url', $url );
454 }
455
456 \NitroPack\ModuleHandler::onShutdown( function () use ($output) {
457 echo $output;
458 } );
459 } catch (Exception $e) {
460 // not a critical error, do nothing
461 }
462 }
463 }
464 \NitroPack\ModuleHandler::onCriticalInit( function () {
465 exit;
466 } );
467 }
468
469 /**
470 * Handle NitroPack webhooks
471 *
472 * @return void
473 */
474 /**
475 * Handles the NitroPack webhook request
476 *
477 * @return void
478 */
479 function nitropack_handle_webhook() {
480 if ( defined( 'NITROPACK_DEBUG_MODE' ) ) {
481 do_action( 'nitropack_debug_webhook', $_REQUEST );
482 }
483 if ( ! defined( "NITROPACK_WEBHOOK_HANDLED" ) ) {
484 define( "NITROPACK_WEBHOOK_HANDLED", 1 );
485 } else {
486 return;
487 }
488
489 $siteConfig = nitropack_get_site_config();
490 if ( $siteConfig && $siteConfig["webhookToken"] == $_GET["token"] ) {
491 switch ( $_GET["nitroWebhook"] ) {
492 case "config":
493 nitropack_fetch_config();
494 get_nitropack()->resetSdkInstances(); // This is needed in order to obtain a new SDK instance with the fresh config
495 nitropack_set_htaccess_rules( true );
496 if ( null !== $nitro = get_nitropack_sdk() ) {
497 $nitro->purgeProxyCache();
498 }
499 do_action( 'nitropack_integration_purge_all' );
500 break;
501 case "cache_ready":
502 if ( isset( $_POST['url'] ) ) {
503 $urls = array( $_POST['url'] );
504 } elseif ( isset( $_POST['urls'] ) ) {
505 $urls = $_POST['urls'];
506 } else {
507 $urls = array();
508 }
509 if ( ! empty( $urls ) ) {
510 $readyUrls = [];
511 foreach ( $urls as $url ) {
512 $readyUrl = nitropack_sanitize_url_input( $url );
513 if ( $readyUrl ) {
514 $readyUrls[] = $readyUrl;
515 }
516 }
517
518 if ( $readyUrls && null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"], $readyUrls[0] ) ) {
519 $hasCache = $nitro->hasRemoteCacheMulti( $readyUrls, "default", false ); // Download the new cache file
520 foreach ( $readyUrls as $readyUrl ) {
521 $nitro->purgeProxyCache( $readyUrl );
522 do_action( 'nitropack_integration_purge_url', $readyUrl );
523 }
524 }
525 }
526 break;
527 case "cache_clear":
528 if ( isset( $_POST['url'] ) ) {
529 $urls = array( $_POST['url'] );
530 } elseif ( isset( $_POST['urls'] ) ) {
531 $urls = $_POST['urls'];
532 }
533
534 $proxyPurgeOnly = ! empty( $_POST["proxyPurgeOnly"] );
535 $doAction = ! empty( $_POST['useInvalidate'] )
536 ? static function ( $url = null ) {
537 nitropack_sdk_invalidate_local( $url );
538 }
539 : static function ( $url = null ) {
540 nitropack_sdk_purge_local( $url );
541 };
542
543 if ( ! empty( $_POST["url"] ) ) {
544 $urls = is_array( $_POST["url"] ) ? $_POST["url"] : array( $_POST["url"] );
545 foreach ( $urls as $url ) {
546 $sanitizedUrl = nitropack_sanitize_url_input( $url );
547 if ( $proxyPurgeOnly ) {
548 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
549 $nitro->purgeProxyCache( $sanitizedUrl );
550 }
551 do_action( 'nitropack_integration_purge_url', $sanitizedUrl );
552 } else {
553 $doAction( $sanitizedUrl );
554 }
555 }
556 } else {
557 if ( $proxyPurgeOnly ) {
558 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
559 $nitro->purgeProxyCache();
560 }
561 do_action( 'nitropack_integration_purge_all' );
562 } else {
563 $doAction();
564 nitropack_sdk_delete_backlog();
565 }
566 }
567 break;
568 }
569 }
570 \NitroPack\ModuleHandler::onCriticalInit( function () {
571 nitropack_json_and_exit( array(
572 "type" => "success",
573 ) );
574 } );
575 }
576
577 function nitropack_sanitize_url_input( $url ) {
578 $result = NULL;
579 if ( ! function_exists( "esc_url" ) ) {
580 $sanitizedUrl = filter_var( $url, FILTER_SANITIZE_URL );
581 if ( $sanitizedUrl !== false && filter_var( $sanitizedUrl, FILTER_VALIDATE_URL ) !== false ) {
582 $result = $sanitizedUrl;
583 }
584 } else if ( $validatedUrl = esc_url( $url, array( "http", "https" ), "notdisplay" ) ) {
585 $result = $validatedUrl;
586 }
587
588 return $result;
589 }
590
591 function nitropack_is_amp_page() {
592 return ( function_exists( 'amp_is_request' ) && amp_is_request() && ! get_nitropack()->setDisabledReason( "amp page" ) ) ||
593 ( function_exists( 'ampforwp_is_amp_endpoint' ) && ampforwp_is_amp_endpoint() && ! get_nitropack()->setDisabledReason( "amp page" ) );
594 }
595
596 function nitropack_passes_page_requirements( $detectIfNoCachedResult = true ) {
597 static $cachedResult = NULL;
598 $reduceCheckoutChecks = defined( "NITROPACK_REDUCE_CHECKOUT_CHECKS" ) && NITROPACK_REDUCE_CHECKOUT_CHECKS;
599 $reduceCartChecks = defined( "NITROPACK_REDUCE_CART_CHECKS" ) && NITROPACK_REDUCE_CART_CHECKS;
600
601 if ( $cachedResult === NULL && $detectIfNoCachedResult ) {
602
603 $cachedResult = ! (
604 ( is_404() && ! get_nitropack()->setDisabledReason( "404" ) ) ||
605 ( is_preview() && ! get_nitropack()->setDisabledReason( "preview page" ) ) ||
606 ( is_feed() && ! get_nitropack()->setDisabledReason( "feed" ) ) ||
607 ( is_comment_feed() && ! get_nitropack()->setDisabledReason( "comment feed" ) ) ||
608 ( is_trackback() && ! get_nitropack()->setDisabledReason( "trackback" ) ) ||
609 ( nitropack_is_logged_in() && ! get_nitropack()->setDisabledReason( "logged in" ) ) ||
610 ( is_search() && ! get_nitropack()->setDisabledReason( "search" ) ) ||
611 ( nitropack_is_ajax() && ! get_nitropack()->setDisabledReason( "ajax" ) ) ||
612 ( nitropack_is_post() && ! get_nitropack()->setDisabledReason( "post request" ) ) ||
613 ( nitropack_is_xmlrpc() && ! get_nitropack()->setDisabledReason( "xmlrpc" ) ) ||
614 ( nitropack_is_robots() && ! get_nitropack()->setDisabledReason( "robots" ) ) ||
615 nitropack_is_amp_page() ||
616 ! nitropack_is_allowed_request() ||
617 ( nitropack_is_wp_cron() && ! get_nitropack()->setDisabledReason( "doing cron" ) ) || // CRON request
618 ( nitropack_is_wp_cli() ) || // CLI request
619 ( defined( 'WC_PLUGIN_FILE' ) && ( is_page( 'cart' ) || ( ! $reduceCartChecks && is_cart() ) ) && ! get_nitropack()->setDisabledReason( "cart page" ) ) || // WooCommerce
620 ( defined( 'WC_PLUGIN_FILE' ) && ( is_page( 'checkout' ) || ( ! $reduceCheckoutChecks && is_checkout() ) ) && ! get_nitropack()->setDisabledReason( "checkout page" ) ) || // WooCommerce
621 ( defined( 'WC_PLUGIN_FILE' ) && is_account_page() && ! get_nitropack()->setDisabledReason( "account page" ) ) // WooCommerce
622 );
623 }
624
625 return $cachedResult;
626 }
627
628 function nitropack_is_home() {
629 if ( 'posts' == get_option( 'show_on_front' ) ) {
630 return is_front_page() || is_home();
631 } else {
632 return is_front_page();
633 }
634 }
635
636 function nitropack_is_blogindex() {
637 return is_home();
638 }
639
640 function nitropack_is_archive() {
641 return apply_filters( "nitropack_is_archive_page", is_author() || is_archive() );
642 }
643
644 /* We have a lot of requests with these GET parameters that we want to ignore */
645 function nitropack_get_ignored_get_params() {
646 $urls = [ 'shop_order', 'shop_order_refund', 'revisionPreview' ];
647 return $urls;
648 }
649 function nitropack_is_allowed_request() {
650 global $np_queriedObj;
651 $CPTOptimization = NitroPack\WordPress\Settings\CPTOptimization::getInstance();
652 $cacheableObjectTypes = $CPTOptimization->nitropack_get_cacheable_object_types();
653 if ( is_array( $cacheableObjectTypes ) ) {
654 if ( nitropack_is_home() ) {
655 if ( ! in_array( 'home', $cacheableObjectTypes ) ) {
656 get_nitropack()->setDisabledReason( "page type not allowed (home)" );
657 return false;
658 }
659 } else {
660 if ( is_tax() || is_category() || is_tag() ) {
661 $np_queriedObj = get_queried_object();
662 if ( ! empty( $np_queriedObj ) && ! in_array( $np_queriedObj->taxonomy, $cacheableObjectTypes ) ) {
663 get_nitropack()->setDisabledReason( "page type not allowed ({$np_queriedObj->taxonomy})" );
664 return false;
665 }
666 } else {
667 if ( nitropack_is_archive() ) {
668 if ( ! in_array( 'archive', $cacheableObjectTypes ) ) {
669 get_nitropack()->setDisabledReason( "page type not allowed (archive)" );
670 return false;
671 }
672 } else {
673 $postType = get_post_type();
674 if ( ! empty( $postType ) && ! in_array( $postType, $cacheableObjectTypes ) ) {
675 get_nitropack()->setDisabledReason( "page type not allowed ($postType)" );
676 return false;
677 }
678 }
679 }
680 }
681 }
682
683 $ignoredGETParams = nitropack_get_ignored_get_params();
684 foreach ( $ignoredGETParams as $ignoredGETParam ) {
685 if ( ! empty( $_GET[ $ignoredGETParam ] ) ) {
686 get_nitropack()->setDisabledReason( "ignored url parameter detected ($ignoredGETParam)" );
687 return false;
688 }
689 }
690 //add test mode as disabled reason but not when the testnitro parameter is set
691 if ( empty( $_GET['testnitro'] ) && TestMode::getInstance()->is_test_mode_enabled() ) {
692 get_nitropack()->setDisabledReason( "Test Mode" );
693 return false;
694 }
695
696 if ( null !== $nitro = get_nitropack_sdk() ) {
697 return ( $nitro->isAllowedUrl( $nitro->getUrl() ) || get_nitropack()->setDisabledReason( "url not allowed" ) ) &&
698 ( $nitro->isAllowedRequest( true ) || get_nitropack()->setDisabledReason( "request type not allowed" ) );
699 }
700
701 get_nitropack()->setDisabledReason( "site not connected" );
702 return false;
703 }
704
705 function nitropack_is_ajax() {
706 return ( function_exists( "wp_doing_ajax" ) && wp_doing_ajax() ) ||
707 ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ||
708 ( ! empty( $_SERVER["HTTP_X_REQUESTED_WITH"] ) && $_SERVER["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" ) ||
709 ( ! empty( $_SERVER["REQUEST_URI"] ) && basename( $_SERVER["REQUEST_URI"] ) == "admin-ajax.php" ) ||
710 ! empty( $_GET["wc-ajax"] );
711 }
712
713 /**
714 * Checking if the current request is wp-cli request
715 *
716 * @return bool
717 */
718 function nitropack_is_wp_cli() {
719 return NitroPack\WordPress\NitroPack::isWpCli();
720 }
721
722 function nitropack_is_wp_cron() {
723 return defined( 'DOING_CRON' ) && DOING_CRON;
724 }
725
726 function nitropack_is_rest() {
727 // Source: https://wordpress.stackexchange.com/a/317041
728 $prefix = rest_get_url_prefix();
729 if (
730 defined( 'REST_REQUEST' ) && REST_REQUEST // (#1)
731 || isset( $_GET['rest_route'] ) // (#2)
732 && strpos( trim( $_GET['rest_route'], '\\/' ), $prefix, 0 ) === 0
733 )
734 return true;
735 // (#3)
736 global $wp_rewrite;
737 if ( $wp_rewrite === null )
738 $wp_rewrite = new WP_Rewrite();
739
740 // (#4)
741 $rest_url = wp_parse_url( trailingslashit( rest_url() ) );
742 $current_url = wp_parse_url( add_query_arg( array() ) );
743 return strpos( $current_url['path'], $rest_url['path'], 0 ) === 0;
744 }
745
746 function nitropack_is_post() {
747 return ( ! empty( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] === 'POST' ) || ( empty( $_SERVER['REQUEST_METHOD'] ) && ! empty( $_POST ) );
748 }
749
750 function nitropack_is_xmlrpc() {
751 return defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST;
752 }
753
754 function nitropack_is_robots() {
755 return is_robots() || ( ! empty( $_SERVER["REQUEST_URI"] ) && basename( parse_url( $_SERVER["REQUEST_URI"], PHP_URL_PATH ) ) === "robots.txt" );
756 }
757
758 // IMPORTANT: This function should only be trusted if NitroPack is connected. Otherwise we may not have information about the admin URL in the config file and it may return an incorrect result
759 function nitropack_is_admin() {
760 if ( ( nitropack_is_ajax() || nitropack_is_rest() ) && ! empty( $_SERVER["HTTP_REFERER"] ) ) {
761 $adminUrl = NULL;
762 $siteConfig = nitropack_get_site_config();
763 if ( $siteConfig && ! empty( $siteConfig["admin_url"] ) ) {
764 $adminUrl = $siteConfig["admin_url"];
765 } else if ( function_exists( "admin_url" ) ) {
766 $adminUrl = admin_url();
767 } else {
768 return is_admin();
769 }
770
771 return strpos( $_SERVER["HTTP_REFERER"], $adminUrl ) === 0;
772 } else {
773 return is_admin();
774 }
775 }
776
777 function nitropack_is_warmup_request() {
778 return ! empty( $_SERVER["HTTP_X_NITRO_WARMUP"] );
779 }
780
781 function nitropack_is_lighthouse_request() {
782 return ! empty( $_SERVER["HTTP_USER_AGENT"] ) && stripos( $_SERVER["HTTP_USER_AGENT"], "lighthouse" ) !== false;
783 }
784
785 function nitropack_is_gtmetrix_request() {
786 return ! empty( $_SERVER["HTTP_USER_AGENT"] ) && stripos( $_SERVER["HTTP_USER_AGENT"], "gtmetrix" ) !== false;
787 }
788
789 function nitropack_is_pingdom_request() {
790 return ! empty( $_SERVER["HTTP_USER_AGENT"] ) && stripos( $_SERVER["HTTP_USER_AGENT"], "pingdom" ) !== false;
791 }
792
793 function nitropack_is_optimizer_request() {
794 return isset( $_SERVER["HTTP_X_NITROPACK_REQUEST"] );
795 }
796
797 function nitropack_init() {
798 global $np_queriedObj;
799 nitropack_header( 'X-Nitro-Cache: MISS' );
800 $GLOBALS["NitroPack.tags"] = array();
801
802 if ( is_valid_nitropack_webhook() ) {
803 nitropack_handle_webhook();
804 } else {
805 if ( is_valid_nitropack_beacon() ) {
806 nitropack_handle_beacon();
807 } else {
808 /* The following if statement should stay as it is written.
809 * is_archive() can return true if visiting a tax, category or tag page, so is_acrchive must be checked last
810 */
811 if ( is_tax() || is_category() || is_tag() ) {
812 $np_queriedObj = get_queried_object();
813 get_nitropack()->setPageType( $np_queriedObj->taxonomy );
814 } else {
815 $layout = nitropack_get_layout();
816 get_nitropack()->setPageType( $layout );
817 }
818
819 add_action( 'wp_footer', 'nitropack_print_element_override', 9999999 );
820 if ( ! isset( $_GET["wpf_action"] ) && nitropack_passes_cookie_requirements() && nitropack_passes_page_requirements() ) {
821 add_action( 'wp_footer', 'nitropack_print_beacon_script' );
822 add_action( 'get_footer', 'nitropack_print_beacon_script' );
823
824 if ( nitropack_is_optimizer_request() ) { // Only care about tags for requests coming from our service. There is no need to do an API request when handling a standard client request.
825 if ( defined( 'FUSION_BUILDER_VERSION' ) ) {
826 add_filter( 'do_shortcode_tag', 'nitropack_handle_fusion_builder_conatainer_expiration', 10, 3 );
827 add_action( 'wp_footer', 'nitropack_set_custom_expiration' );
828 } else {
829 nitropack_set_custom_expiration();
830 }
831
832 $GLOBALS["NitroPack.tags"][ "pageType:" . get_nitropack()->getPageType()] = 1;
833
834 /* The following if statement should stay as it is written.
835 * is_archive() can return true if visiting a tax, category or tag page, so is_acrchive must be checked last
836 */
837 if ( is_tax() || is_category() || is_tag() ) {
838 $np_queriedObj = get_queried_object();
839 $GLOBALS["NitroPack.tags"][ "tax:" . $np_queriedObj->term_taxonomy_id ] = 1;
840 } else {
841 if ( is_single() || is_page() || is_attachment() ) {
842 $singlePost = get_post();
843 if ( $singlePost ) {
844 $GLOBALS["NitroPack.tags"][ "single:" . $singlePost->ID ] = 1;
845 }
846 }
847 }
848
849 // Uncomment the code below in case object cache interferes with correct URL taggig
850 // The code below will attempt to temporarily disable using the object cache only for the requests coming from NitroPack
851 //wp_using_ext_object_cache(false);
852 //add_action("pre_get_posts", function($query) {
853 // $query->query_vars["cache_results"] = false;
854 //});
855 //
856 //add_filter("all", function() {
857 // $args = func_get_args();
858 // if (count($args) > 1) {
859 // list($filterName, $value) = func_get_args();
860 // if (preg_match("/^transient_(.*)/", $filterName, $matches) && $value) {
861 // return false;
862 // }
863 // }
864 //}, 10, 2);
865
866 add_filter( 'post_link', 'nitropack_post_link_listener', 10, 3 );
867 add_action( 'the_post', 'nitropack_handle_the_post' );
868 add_action( 'wp_footer', 'nitropack_log_tags' );
869 }
870 } else {
871 nitropack_header( "X-Nitro-Disabled: 1" );
872 if ( ( null !== $nitro = get_nitropack_sdk() ) && ! $nitro->isAllowedBrowser() ) { // This clears any proxy cache when a proxy cached non-optimized request due to unsupported browser
873 add_action( 'wp_footer', 'nitropack_print_beacon_script' );
874 add_action( 'get_footer', 'nitropack_print_beacon_script' );
875 }
876 }
877
878 if ( ! nitropack_is_optimizer_request() ) {
879 add_action( 'wp_head', 'nitropack_print_generic_nitro_script' );
880 }
881 }
882 }
883 }
884
885 function nitropack_handle_fusion_builder_conatainer_expiration( $output, $tag, $attr ) {
886 global $np_customExpirationTimes;
887 if ( $tag == "fusion_builder_container" ) {
888 if ( ! empty( $attr["publish_date"] ) && ! empty( $attr["status"] ) && in_array( $attr["status"], array( "published_until", "publish_after" ) ) ) {
889 $timezone = get_option( 'timezone_string' );
890 $offset = get_option( 'gmt_offset' );
891 $dt = new DateTime( $attr["publish_date"] );
892 if ( $timezone ) {
893 $timeZone = new DateTimeZone( $timezone );
894 $timeZoneOffset = $timeZone->getOffset( $dt );
895 } else if ( $offset ) {
896 $timeZoneOffset = (int) $offset * 3600;
897 }
898 $time = $dt->getTimestamp() - $timeZoneOffset;
899 if ( $time > time() ) { // We only need to look at future dates
900 $np_customExpirationTimes[] = $time;
901 }
902 }
903 }
904 return $output;
905 }
906 function nitropack_set_custom_expiration() {
907
908 //check which CPTs are marked for optimization
909 $CPTOptimization = NitroPack\WordPress\Settings\CPTOptimization::getInstance();
910 $get_optimized_CPTs = $CPTOptimization->nitropack_get_optimized_CPTs();
911 if ( empty( $get_optimized_CPTs ) )
912 return;
913
914 global $np_customExpirationTimes, $wpdb;
915
916 $placeholders = implode( ',', array_fill( 0, count( $get_optimized_CPTs ), '%s' ) );
917 $currentDate = date( "Y-m-d H:i:s" );
918
919 //For better security, we use prepared statements
920 $unmodifiedPosts_query = $wpdb->prepare(
921 "SELECT ID, post_date
922 FROM {$wpdb->prefix}posts
923 WHERE {$wpdb->prefix}posts.post_date > %s
924 AND {$wpdb->prefix}posts.post_type IN ($placeholders)
925 AND ({$wpdb->prefix}posts.post_status = 'future')
926 ORDER BY {$wpdb->prefix}posts.post_date ASC
927 LIMIT 0, 1",
928 array_merge( [ $currentDate ], $get_optimized_CPTs )
929 );
930 $unmodifiedPosts = $wpdb->get_results( $unmodifiedPosts_query );
931
932 if ( ! empty( $unmodifiedPosts ) && strtotime( $unmodifiedPosts[0]->post_date ) > time() ) {
933 $scheduled_post = get_post( $unmodifiedPosts[0]->ID );
934
935 // We will check relatedness only if a proper option is set in wp-config.php
936 $check_relatedness = defined( "NITROPACK_SCHEDULED_POST_EXPIRATION_CHECK_RELATEDNESS" ) && NITROPACK_SCHEDULED_POST_EXPIRATION_CHECK_RELATEDNESS;
937
938 // We'll add the expiration time only if the current page is related to the scheduled post or if we don't need to check relatedness
939 if ( ! $check_relatedness || nitropack_is_page_related_to_scheduled_post( $scheduled_post ) ) {
940 $np_customExpirationTimes[] = strtotime( $unmodifiedPosts[0]->post_date );
941 }
942 }
943
944 if ( ! empty( $np_customExpirationTimes ) ) {
945 sort( $np_customExpirationTimes, SORT_NUMERIC );
946 nitropack_header( "X-Nitro-Expires: " . $np_customExpirationTimes[0] );
947 }
948 }
949
950 // Determine if the current page is related to the scheduled post
951 // This is a best-effort approach and may not cover all cases
952 function nitropack_is_page_related_to_scheduled_post( $scheduled_post ) {
953 $current_layout = nitropack_get_layout();
954 $postType = $scheduled_post->post_type;
955 $CPTOptimization = NitroPack\WordPress\Settings\CPTOptimization::getInstance();
956 $cacheableObjectTypes = $CPTOptimization->nitropack_get_cacheable_object_types();
957
958 // Only proceed if post type is cacheable
959 if ( ! in_array( $postType, $cacheableObjectTypes ) ) {
960 return false;
961 }
962
963 // Check if current home page would be invalidated
964 if ( $current_layout === 'home' ) {
965 return true;
966 }
967
968 // Check if current blog index page would be invalidated
969 if ( $postType === 'post' && $current_layout === 'blogindex' ) {
970 return true;
971 }
972
973 if ( is_post_type_archive( $postType ) ) {
974 return true;
975 }
976
977 // Check if current single post/page would be invalidated
978 if ( is_singular( $postType ) ) {
979 return true;
980 }
981
982 // Default to false for other page types
983 return false;
984 }
985
986 function nitropack_print_beacon_script() {
987 if ( defined( "NITROPACK_BEACON_PRINTED" ) || ! nitropack_passes_page_requirements() )
988 return;
989 define( "NITROPACK_BEACON_PRINTED", true );
990 echo apply_filters( "nitro_script_output", nitropack_get_beacon_script() );
991 }
992
993 function nitropack_get_beacon_script() {
994 $siteConfig = nitropack_get_site_config();
995 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) ) {
996 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
997 $url = $nitro->getUrl();
998 $cookiesJson = json_encode( $nitro->supportedCookiesFilter( NitroPack\SDK\NitroPack::getCookies() ) );
999 $layout = nitropack_get_layout();
1000
1001 if ( function_exists( "hash_hmac" ) && function_exists( "hash_equals" ) ) {
1002 $hash = hash_hmac( "sha512", $url . $cookiesJson . $layout, $siteConfig["siteSecret"] );
1003 } else {
1004 $hash = "";
1005 }
1006 $url = base64_encode( $url ); // We want only ASCII
1007 $cookiesb64 = base64_encode( $cookiesJson );
1008 $proxyPurgeOnly = ! $nitro->isAllowedBrowser();
1009
1010 return "
1011 <script nitro-exclude>
1012 if (!window.NITROPACK_STATE || window.NITROPACK_STATE != 'FRESH') {
1013 var proxyPurgeOnly = " . ( $proxyPurgeOnly ? 1 : 0 ) . ";
1014 if (typeof navigator.sendBeacon !== 'undefined') {
1015 var nitroData = new FormData(); nitroData.append('nitroBeaconUrl', '$url'); nitroData.append('nitroBeaconCookies', '$cookiesb64'); nitroData.append('nitroBeaconHash', '$hash'); nitroData.append('proxyPurgeOnly', '$proxyPurgeOnly'); nitroData.append('layout', '$layout'); navigator.sendBeacon(location.href, nitroData);
1016 } else {
1017 var xhr = new XMLHttpRequest(); xhr.open('POST', location.href, true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('nitroBeaconUrl={$url}&nitroBeaconCookies={$cookiesb64}&nitroBeaconHash={$hash}&proxyPurgeOnly={$proxyPurgeOnly}&layout={$layout}');
1018 }
1019 }
1020 </script>";
1021 }
1022 }
1023 }
1024
1025 function nitropack_print_cookie_handler_script() {
1026
1027 if ( defined( "NITROPACK_COOKIE_HANDLER_PRINTED" ) )
1028 return;
1029 define( "NITROPACK_COOKIE_HANDLER_PRINTED", true );
1030
1031 echo apply_filters( "nitro_script_output", nitropack_get_cookie_handler_script() );
1032 }
1033
1034 function nitropack_get_cookie_handler_script() {
1035 return "
1036 <script nitro-exclude>
1037 document.cookie = 'nitroCachedPage=' + (!window.NITROPACK_STATE ? '0' : '1') + '; path=/; SameSite=Lax';
1038 </script>";
1039 }
1040
1041 function nitropack_print_generic_nitro_script() {
1042 if ( defined( "NITROPACK_GENERIC_NITRO_SCRIPT_PRINTED" ) )
1043 return;
1044 define( "NITROPACK_GENERIC_NITRO_SCRIPT_PRINTED", true );
1045 echo apply_filters( "nitro_script_output", nitropack_get_telemetry_meta() );
1046 echo apply_filters( "nitro_script_output", nitropack_get_generic_nitro_script() );
1047 }
1048
1049 function nitropack_get_generic_nitro_script() {
1050 $siteConfig = nitropack_get_site_config();
1051 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) ) {
1052 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
1053 $config = $nitro->getConfig();
1054 if ( ! empty( $config->GenericNitroScript->Script ) ) {
1055 return "<script id='nitro-generic' nitro-exclude>" . $config->GenericNitroScript->Script . "</script>";
1056 }
1057 }
1058 }
1059
1060 return "";
1061 }
1062
1063 function nitropack_get_telemetry_meta() {
1064 $disabledReason = get_nitropack()->getDisabledReason();
1065 $missReason = $disabledReason !== NULL ? $disabledReason : "cache not found";
1066 $pageType = get_nitropack()->getPageType();
1067 $isEligibleForOptimization = nitropack_passes_page_requirements();
1068 $metaObj = "window.NPTelemetryMetadata={";
1069
1070 if ( $missReason ) {
1071 $metaObj .= "missReason: (!window.NITROPACK_STATE ? '$missReason' : 'hit'),";
1072 }
1073
1074 if ( $pageType ) {
1075 $metaObj .= "pageType: '$pageType',";
1076 }
1077
1078 $metaObj .= "isEligibleForOptimization: " . ( $isEligibleForOptimization ? "true" : "false" ) . ",";
1079
1080 $metaObj .= "}";
1081
1082 return "<script id='nitro-telemetry-meta' nitro-exclude>$metaObj</script>";
1083 }
1084
1085 function nitropack_print_element_override() {
1086 if ( defined( "NITROPACK_ELEMENT_OVERRIDE_PRINTED" ) )
1087 return;
1088 define( "NITROPACK_ELEMENT_OVERRIDE_PRINTED", true );
1089 echo apply_filters( "nitro_script_output", nitropack_get_element_override_script() );
1090 }
1091
1092 function nitropack_get_element_override_script() {
1093 $nitro = get_nitropack_sdk();
1094 return $nitro !== NULL ? $nitro->getStatefulCacheHandlerScript() : "";
1095 }
1096
1097 function nitropack_validate_site_id( $siteId ) {
1098 return preg_match( "/^([a-zA-Z]{32})$/", trim( $siteId ) );
1099 }
1100
1101 function nitropack_validate_site_secret( $siteSecret ) {
1102 return preg_match( "/^([a-zA-Z0-9]{64})$/", trim( $siteSecret ) );
1103 }
1104
1105 function nitropack_validate_webhook_token( $token ) {
1106 return preg_match( "/^([abcdef0-9]{32})$/", strtolower( $token ) );
1107 }
1108
1109 function nitropack_validate_wc_currency( $cookieValue ) {
1110 return preg_match( "/^([a-z]{3})$/", strtolower( $cookieValue ) );
1111 }
1112
1113 function nitropack_validate_wc_currency_language( $cookieValue ) {
1114 return preg_match( "/^([a-z_\\-]{2,})$/", strtolower( $cookieValue ) );
1115 }
1116
1117 function nitropack_is_advanced_cache_allowed() {
1118 return ! in_array( nitropack_detect_hosting(), array(
1119 "pressable"
1120 ) );
1121 }
1122
1123 function nitropack_get_hosting_notice_file() {
1124 return nitropack_trailingslashit( NITROPACK_DATA_DIR ) . "hosting_notice";
1125 }
1126
1127 function nitropack_dismiss_hosting_notice() {
1128 nitropack_verify_ajax_nonce( $_REQUEST );
1129 $hostingNoticeFile = nitropack_get_hosting_notice_file();
1130 if ( WP_DEBUG ) {
1131 touch( $hostingNoticeFile );
1132 } else {
1133 @touch( $hostingNoticeFile );
1134 }
1135 }
1136
1137 function nitropack_is_config_up_to_date() {
1138 $siteConfig = nitropack_get_site_config();
1139 return ! empty( $siteConfig ) && ! empty( $siteConfig["pluginVersion"] ) && $siteConfig["pluginVersion"] == NITROPACK_VERSION;
1140 }
1141
1142 function nitropack_filter_non_original_cookies( &$cookies ) {
1143 global $np_originalRequestCookies;
1144 $ogNames = is_array( $np_originalRequestCookies ) ? array_keys( $np_originalRequestCookies ) : array();
1145 foreach ( $cookies as $name => $val ) {
1146 if ( ! in_array( $name, $ogNames ) ) {
1147 unset( $cookies[ $name ] );
1148 }
1149 }
1150 }
1151
1152 function get_nitropack_sdk( $siteId = null, $siteSecret = null, $urlOverride = NULL, $forwardExceptions = false ) {
1153 return get_nitropack()->getSdk( $siteId, $siteSecret, $urlOverride, $forwardExceptions );
1154 }
1155
1156 function get_nitropack_integration_url( $integration, $nitro = null ) {
1157 if ( $nitro || ( null !== $nitro = get_nitropack_sdk() ) ) {
1158 return $nitro->integrationUrl( $integration );
1159 }
1160
1161 return "#";
1162 }
1163
1164 function nitropack_get_layout() {
1165 $layout = "default";
1166
1167 if ( nitropack_is_home() ) {
1168 $layout = "home";
1169 } else if ( nitropack_is_blogindex() ) {
1170 $layout = "blogindex";
1171 } else if ( is_page() ) {
1172 $layout = "page";
1173 } else if ( is_attachment() ) {
1174 $layout = "attachment";
1175 } else if ( is_author() ) {
1176 $layout = "author";
1177 } else if ( is_search() ) {
1178 $layout = "search";
1179 } else if ( is_tag() ) {
1180 $layout = "tag";
1181 } else if ( is_tax() ) {
1182 $layout = "taxonomy";
1183 } else if ( is_category() ) {
1184 $layout = "category";
1185 } else if ( nitropack_is_archive() ) {
1186 $layout = "archive";
1187 } else if ( is_feed() ) {
1188 $layout = "feed";
1189 } else if ( is_page() ) {
1190 $layout = "page";
1191 } else if ( is_single() ) {
1192 $layout = get_post_type();
1193 }
1194
1195 return $layout;
1196 }
1197
1198 function nitropack_sdk_invalidate( $url = NULL, $tag = NULL, $reason = NULL ) {
1199
1200 $status = false;
1201
1202 if ( null !== $nitro = get_nitropack_sdk() ) {
1203 try {
1204 $siteConfig = nitropack_get_site_config();
1205 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1206
1207 if ( $tag ) {
1208 if ( is_array( $tag ) ) {
1209 $tag = array_map( 'nitropack_filter_tag', $tag );
1210 } else {
1211 $tag = nitropack_filter_tag( $tag );
1212 }
1213 }
1214
1215 $nitro->invalidateCache( $url, $tag, $reason );
1216
1217 try {
1218
1219 if ( defined( 'NITROPACK_DEBUG_MODE' ) ) {
1220 do_action( 'nitropack_debug_invalidate', $url, $tag, $reason );
1221 }
1222
1223 do_action( 'nitropack_integration_purge_url', $homeUrl );
1224
1225 if ( $tag ) {
1226 do_action( 'nitropack_integration_purge_all' );
1227 } else if ( $url ) {
1228 do_action( 'nitropack_integration_purge_url', $url );
1229 } else {
1230 do_action( 'nitropack_integration_purge_all' );
1231 }
1232 } catch (\Exception $e) {
1233 // Exception while signaling 3rd party integration addons to purge their cache
1234 }
1235 } catch (\Exception $e) {
1236 $status = false;
1237 }
1238
1239 $status = true;
1240 }
1241
1242 return $status;
1243 }
1244
1245 /* Start Heartbeat Related Functions */
1246 function nitropack_is_heartbeat_needed() {
1247 return ! nitropack_is_optimizer_request() &&
1248 ! nitropack_is_amp_page() &&
1249 ! nitropack_is_heartbeat_running() &&
1250 ( ! nitropack_is_heartbeat_completed() || time() - nitropack_last_heartbeat() > NITROPACK_HEARTBEAT_INTERVAL );
1251 }
1252
1253 function nitropack_print_heartbeat_script() {
1254 if ( nitropack_is_heartbeat_needed() ) {
1255 if ( defined( "NITROPACK_HEARTBEAT_PRINTED" ) )
1256 return;
1257 define( "NITROPACK_HEARTBEAT_PRINTED", true );
1258 echo apply_filters( "nitro_script_output", nitropack_get_heartbeat_script() );
1259 }
1260 }
1261
1262 function nitropack_get_heartbeat_script() {
1263 $siteConfig = nitropack_get_site_config();
1264 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) ) {
1265 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
1266 if ( is_admin() ) {
1267 $credentials = "same-origin";
1268 } else {
1269 $credentials = "omit";
1270 }
1271
1272 return "
1273 <script nitro-exclude>
1274 var heartbeatData = new FormData(); heartbeatData.append('nitroHeartbeat', '1');
1275 fetch(location.href, {method: 'POST', body: heartbeatData, credentials: '$credentials'});
1276 </script>";
1277 }
1278 }
1279 }
1280
1281 function is_valid_nitropack_heartbeat() {
1282 return ! empty( $_POST['nitroHeartbeat'] );
1283 }
1284
1285 function nitropack_get_heartbeat_file() {
1286 if ( null !== $nitro = get_nitropack_sdk() ) {
1287 return nitropack_trailingslashit( $nitro->getCacheDir() ) . "heartbeat";
1288 } else {
1289 return nitropack_trailingslashit( NITROPACK_DATA_DIR ) . "heartbeat";
1290 }
1291 }
1292
1293 function nitropack_last_heartbeat() {
1294 if ( null !== $nitro = get_nitropack_sdk() ) {
1295 try {
1296 return \NitroPack\SDK\Filesystem::fileMTime( nitropack_get_heartbeat_file() );
1297 } catch (\Exception $e) {
1298 return 0;
1299 }
1300 }
1301 }
1302
1303 function nitropack_is_heartbeat_running() {
1304 if ( null !== $nitro = get_nitropack_sdk() ) {
1305 try {
1306 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents( nitropack_get_heartbeat_file() );
1307 if ( $heartbeatContent == "1" ) {
1308 return time() - nitropack_last_heartbeat() < NITROPACK_HEARTBEAT_INTERVAL;
1309 }
1310 } catch (\Exception $e) {
1311 return false;
1312 }
1313 }
1314 }
1315
1316 function nitropack_is_heartbeat_completed() {
1317 if ( null !== $nitro = get_nitropack_sdk() ) {
1318 try {
1319 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents( nitropack_get_heartbeat_file() );
1320 return $heartbeatContent == "0"; // 0 - Job Done, 1 - Job Running, 2 - Job Needs Repeat
1321 } catch (\Exception $e) {
1322 return true;
1323 }
1324 }
1325 }
1326
1327 function nitropack_handle_heartbeat() {
1328 // TODO: Lock the file before checking this
1329 if ( nitropack_is_heartbeat_running() )
1330 return;
1331
1332 session_write_close();
1333 if ( null !== $nitro = get_nitropack_sdk() ) {
1334 try {
1335 $success = true;
1336 \NitroPack\SDK\Filesystem::filePutContents( nitropack_get_heartbeat_file(), 1 );
1337 if ( nitropack_healthcheck() ) {
1338 $success &= nitropack_flush_backlog();
1339 }
1340 $success &= nitropack_cache_cleanup();
1341
1342 if ( $success ) {
1343 \NitroPack\SDK\Filesystem::filePutContents( nitropack_get_heartbeat_file(), 0 );
1344 } else {
1345 \NitroPack\SDK\Filesystem::filePutContents( nitropack_get_heartbeat_file(), 2 );
1346 }
1347 } catch (\Exception $e) {
1348 return false;
1349 }
1350 }
1351 exit;
1352 }
1353
1354 function nitropack_healthcheck() {
1355 if ( null !== $nitro = get_nitropack_sdk() ) {
1356 return $nitro->getHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY || $nitro->checkHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY;
1357 }
1358 return true;
1359 }
1360
1361 function nitropack_flush_backlog() {
1362 if ( null !== $nitro = get_nitropack_sdk() ) {
1363 try {
1364 if ( $nitro->backlog->exists() ) {
1365 return $nitro->backlog->replay( 30 );
1366 }
1367 } catch (\NitroPack\SDK\BacklogReplayTimeoutException $e) {
1368 $nitro->backlog->delete();
1369 return nitropack_sdk_purge( NULL, NULL, "Full purge after backlog timeout" );
1370 } catch (\Exception $e) {
1371 return false;
1372 }
1373 }
1374 return true;
1375 }
1376
1377 function nitropack_cache_cleanup() {
1378 if ( null !== $nitro = get_nitropack_sdk() ) {
1379 $cacheDirParent = dirname( $nitro->getCacheDir() );
1380 $entries = scandir( $cacheDirParent );
1381 foreach ( $entries as $entry ) {
1382 if ( strpos( $entry, ".stale." ) !== false ) {
1383 $cacheDir = nitropack_trailingslashit( $cacheDirParent ) . $entry;
1384 try {
1385 \NitroPack\SDK\Filesystem::deleteDir( $cacheDir );
1386 } catch (\Exception $e) {
1387 // TODO: Log this
1388 return false;
1389 }
1390 }
1391 }
1392 }
1393 return true;
1394 }
1395 /* End Heartbeat Related Functions */
1396
1397 function nitropack_sdk_purge( $url = NULL, $tag = NULL, $reason = NULL, $type = \NitroPack\SDK\PurgeType::COMPLETE ) {
1398
1399 $status = false;
1400
1401 if ( null !== $nitro = get_nitropack_sdk() ) {
1402 try {
1403 $siteConfig = nitropack_get_site_config();
1404 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1405
1406 if ( $tag ) {
1407 if ( is_array( $tag ) ) {
1408 $tag = array_map( 'nitropack_filter_tag', $tag );
1409 } else {
1410 $tag = nitropack_filter_tag( $tag );
1411 }
1412 }
1413
1414 if ( ! $url && ! $tag ) {
1415 $nitro->purgeLocalCache( true );
1416 }
1417
1418 $nitro->purgeCache( $url, $tag, $type, $reason );
1419
1420 if ( defined( 'NITROPACK_DEBUG_MODE' ) ) {
1421 do_action( 'nitropack_debug_purge', $url, $tag, $reason );
1422 }
1423
1424 try {
1425 do_action( 'nitropack_integration_purge_url', $homeUrl );
1426
1427 if ( $tag ) {
1428 do_action( 'nitropack_integration_purge_all' );
1429 } else if ( $url ) {
1430 do_action( 'nitropack_integration_purge_url', $url );
1431 } else {
1432 do_action( 'nitropack_integration_purge_all' );
1433 }
1434 } catch (\Exception $e) {
1435 // Exception while signaling 3rd party integration addons to purge their cache
1436 }
1437 } catch (\Exception $e) {
1438 $status = false;
1439 }
1440
1441 $status = true;
1442 }
1443
1444 return $status;
1445 }
1446
1447 /**
1448 * @param string|null $url
1449 * @return bool
1450 */
1451 function nitropack_sdk_purge_local( $url = NULL ) {
1452 if ( null === $nitro = get_nitropack_sdk() ) {
1453 return false;
1454 }
1455
1456 try {
1457 if ( $url ) {
1458 $nitro->purgeLocalUrlCache( $url );
1459 do_action( 'nitropack_integration_purge_url', $url );
1460 return true;
1461 }
1462
1463 $nitro->purgeLocalCache( true );
1464
1465 try {
1466 do_action( 'nitropack_integration_purge_all' );
1467 } catch (\Exception $e) {
1468 // Exception while signaling our 3rd party integration addons to purge their cache
1469 }
1470
1471 return true;
1472 } catch (\Exception $e) {
1473 return false;
1474 }
1475 }
1476
1477 /**
1478 * @param string|null $url
1479 * @return bool
1480 */
1481 function nitropack_sdk_invalidate_local( $url = NULL ) {
1482 if ( null === $nitro = get_nitropack_sdk() ) {
1483 return false;
1484 }
1485
1486 try {
1487 if ( $url ) {
1488 $nitro->invalidateLocalUrlCache( $url );
1489 do_action( 'nitropack_integration_purge_url', $url );
1490 return true;
1491 }
1492
1493 $nitro->invalidateLocalCache( true );
1494
1495 try {
1496 do_action( 'nitropack_integration_purge_all' );
1497 } catch (\Exception $e) {
1498 // Exception while signaling our 3rd party integration addons to purge their cache
1499 }
1500
1501 return true;
1502 } catch (\Exception $e) {
1503 return false;
1504 }
1505 }
1506
1507 function nitropack_sdk_delete_backlog() {
1508 if ( null !== $nitro = get_nitropack_sdk() ) {
1509 try {
1510 if ( $nitro->backlog->exists() ) {
1511 $nitro->backlog->delete();
1512 }
1513 } catch (\Exception $e) {
1514 return false;
1515 }
1516
1517 return true;
1518 }
1519
1520 return false;
1521 }
1522
1523 function nitropack_purge( $url = NULL, $tag = NULL, $reason = NULL ) {
1524 if ( $tag != "pageType:home" ) {
1525 $siteConfig = nitropack_get_site_config();
1526 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1527 nitropack_log_invalidate( $homeUrl, "pageType:home", $reason );
1528 }
1529
1530 if ( $tag != "pageType:archive" ) {
1531 nitropack_log_invalidate( NULL, "pageType:archive", $reason );
1532 }
1533
1534 nitropack_log_purge( $url, $tag, $reason );
1535 }
1536
1537 function nitropack_log_purge( $url = NULL, $tag = NULL, $reason = NULL ) {
1538 global $np_loggedPurges;
1539 if ( $tag && is_array( $tag ) ) {
1540 foreach ( $tag as $tagSingle ) {
1541 nitropack_log_purge( $url, $tagSingle, $reason );
1542 }
1543 return;
1544 }
1545
1546 $keyBase = "";
1547 if ( $url ) {
1548 $keyBase .= $url;
1549 }
1550
1551 if ( $tag ) {
1552 $tag = nitropack_filter_tag( $tag );
1553 $keyBase .= $tag;
1554 }
1555
1556 $purgeRequestKey = md5( $keyBase );
1557 if ( is_array( $np_loggedPurges ) && array_key_exists( $purgeRequestKey, $np_loggedPurges ) ) {
1558 $np_loggedPurges[ $purgeRequestKey ]["reason"] = $reason;
1559 $np_loggedPurges[ $purgeRequestKey ]["priority"]++;
1560 } else {
1561 $np_loggedPurges[ $purgeRequestKey ] = array(
1562 "url" => $url,
1563 "tag" => $tag,
1564 "reason" => $reason,
1565 "priority" => 1
1566 );
1567 }
1568 }
1569
1570 function nitropack_invalidate( $url = NULL, $tag = NULL, $reason = NULL ) {
1571 if ( $tag != "pageType:home" ) {
1572 $siteConfig = nitropack_get_site_config();
1573 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1574 nitropack_log_invalidate( $homeUrl, "pageType:home", $reason );
1575 }
1576
1577 if ( $tag != "pageType:archive" ) {
1578 nitropack_log_invalidate( NULL, "pageType:archive", $reason );
1579 }
1580
1581 nitropack_log_invalidate( $url, $tag, $reason );
1582 }
1583
1584 function nitropack_log_invalidate( $url = NULL, $tag = NULL, $reason = NULL ) {
1585 global $np_loggedInvalidations;
1586 if ( $tag && is_array( $tag ) ) {
1587 foreach ( $tag as $tagSingle ) {
1588 nitropack_log_invalidate( $url, $tagSingle, $reason );
1589 }
1590 return;
1591 }
1592
1593 $keyBase = "";
1594 if ( $url ) {
1595 $keyBase .= $url;
1596 }
1597
1598 if ( $tag ) {
1599 $tag = nitropack_filter_tag( $tag );
1600 $keyBase .= $tag;
1601 }
1602
1603 $invalidateRequestKey = md5( $keyBase );
1604 if ( is_array( $np_loggedInvalidations ) && array_key_exists( $invalidateRequestKey, $np_loggedInvalidations ) ) {
1605 $np_loggedInvalidations[ $invalidateRequestKey ]["reason"] = $reason;
1606 $np_loggedInvalidations[ $invalidateRequestKey ]["priority"]++;
1607 } else {
1608 $np_loggedInvalidations[ $invalidateRequestKey ] = array(
1609 "url" => $url,
1610 "tag" => $tag,
1611 "reason" => $reason,
1612 "priority" => 1
1613 );
1614 }
1615 }
1616
1617 function nitropack_queue_sort( $a, $b ) {
1618 if ( $a["priority"] == $b["priority"] ) {
1619 return 0;
1620 }
1621 return ( $a["priority"] < $b["priority"] ) ? -1 : 1;
1622 }
1623
1624 function nitropack_execute_purges() {
1625 global $np_loggedPurges;
1626
1627 if ( ! empty( $np_loggedPurges ) ) {
1628 uasort( $np_loggedPurges, "nitropack_queue_sort" );
1629 foreach ( $np_loggedPurges as $requestKey => $data ) {
1630 nitropack_sdk_purge( $data["url"], $data["tag"], $data["reason"] );
1631 }
1632 }
1633 }
1634
1635 function nitropack_execute_invalidations() {
1636 global $np_loggedInvalidations;
1637
1638 if ( ! empty( $np_loggedInvalidations ) ) {
1639 uasort( $np_loggedInvalidations, "nitropack_queue_sort" );
1640 foreach ( $np_loggedInvalidations as $requestKey => $data ) {
1641 nitropack_sdk_invalidate( $data["url"], $data["tag"], $data["reason"] );
1642 }
1643 }
1644 }
1645
1646 function nitropack_execute_warmups() {
1647 if ( ! empty( $_GET["action"] ) && ( $_GET["action"] === "edit" ) && ! empty( $_GET["meta-box-loader"] ) ) {
1648 return;
1649 }
1650
1651 try {
1652 if ( ! empty( \NitroPack\WordPress\NitroPack::$np_loggedWarmups ) && ( null !== $nitro = get_nitropack_sdk() ) ) {
1653 $warmupStats = $nitro->getApi()->getWarmupStats();
1654 if ( ! empty( $warmupStats["status"] ) ) {
1655 foreach ( array_unique( \NitroPack\WordPress\NitroPack::$np_loggedWarmups ) as $url ) {
1656 $nitro->getApi()->runWarmup( $url );
1657 }
1658 }
1659 }
1660 } catch (\Exception $e) {
1661 }
1662 }
1663
1664 function nitropack_fetch_config() {
1665 if ( null !== $nitro = get_nitropack_sdk() ) {
1666 try {
1667 $nitro->fetchConfig();
1668 } catch (\Exception $e) {
1669 }
1670 }
1671 }
1672
1673 function nitropack_theme_handler( $event = NULL ) {
1674 if ( ! get_option( "nitropack-autoCachePurge", 1 ) )
1675 return;
1676
1677 $msg = $event ? $event : 'Theme switched';
1678
1679 try {
1680 nitropack_sdk_purge( NULL, NULL, $msg ); // purge entire cache
1681 } catch (\Exception $e) {
1682 }
1683 }
1684
1685 function nitropack_json_and_exit( $array ) {
1686 if ( nitropack_is_wp_cli() ) {
1687 $type = NULL;
1688 if ( array_key_exists( "status", $array ) ) {
1689 $type = $array["status"];
1690 } else if ( array_key_exists( "type", $array ) ) {
1691 $type = $array["type"];
1692 }
1693
1694 if ( $type && array_key_exists( "message", $array ) ) {
1695 if ( $type == "success" ) {
1696 WP_CLI::success( $array["message"] );
1697 } else {
1698 WP_CLI::error( $array["message"] );
1699 }
1700 }
1701 } else {
1702 echo json_encode( $array );
1703 }
1704 exit;
1705 }
1706 function nitropack_admin_toast_msgs( $type ) {
1707 if ( $type === 'success' ) {
1708 $msg = esc_html__( 'Settings updated.', 'nitropack' );
1709 } else {
1710 $msg = esc_html__( 'Something went wrong.', 'nitropack' );
1711 }
1712 return $msg;
1713 }
1714 /* General verification for AJAX requests
1715 * @params array $request_data The request data
1716 * @params array|null $allowed_roles The allowed user roles
1717 */
1718 function nitropack_verify_ajax_nonce( $request_data, $allowed_roles = null ) {
1719 // If not an ajax request
1720 if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
1721 return;
1722 }
1723
1724 // Check if WordPress functions are available
1725 if ( ! function_exists( 'wp_verify_nonce' ) || ! function_exists( 'wp_die' ) || ! function_exists( 'current_user_can' ) ) {
1726 return;
1727 }
1728
1729 // If nonce fails verification
1730 if ( empty( $request_data['nonce'] ) || ! wp_verify_nonce( $request_data['nonce'], NITROPACK_NONCE ) ) {
1731 wp_die( 'Unauthorized request' );
1732 }
1733
1734 // Check user permissions
1735 if ( $allowed_roles ) {
1736 $has_permission = false;
1737 foreach ( $allowed_roles as $role ) {
1738 if ( current_user_can( $role ) ) {
1739 $has_permission = true;
1740 break;
1741 }
1742 }
1743 if ( ! $has_permission ) {
1744 wp_die( 'Unauthorized request' );
1745 }
1746 } else {
1747 //fallback to admin rights
1748 if ( ! current_user_can( 'manage_options' ) ) {
1749 wp_die( 'Unauthorized request' );
1750 }
1751 }
1752 }
1753 function nitropack_has_post_important_change( $post ) {
1754 $prevPost = nitropack_get_post_pre_update( $post );
1755 return $prevPost && ( $prevPost->post_title != $post->post_title || $prevPost->post_name != $post->post_name || $prevPost->post_excerpt != $post->post_excerpt );
1756 }
1757
1758
1759 function nitropack_clean_post_cache( $post, $taxonomies = NULL, $hasImportantChangeInPost = NULL, $reason = NULL, $usePurge = false ) {
1760 try {
1761 $postID = $post->ID;
1762 $postType = isset( $post->post_type ) ? $post->post_type : "post";
1763 $nicePostTypeLabel = nitropack_get_nice_post_type_label( $postType );
1764 $reason = $reason ? $reason : sprintf( "Updated %s '%s'", $nicePostTypeLabel, $post->post_title );
1765 $CPTOptimization = NitroPack\WordPress\Settings\CPTOptimization::getInstance();
1766 $cacheableObjectTypes = $CPTOptimization->nitropack_get_cacheable_object_types();
1767
1768 if ( in_array( $postType, $cacheableObjectTypes ) ) {
1769 if ( $usePurge ) {
1770 // We only purge the single pages because they have to immediately stop serving cache
1771 // These pages no longer exists and if their URL is requested we must not server cache
1772 nitropack_purge( NULL, "single:$postID", $reason );
1773 } else {
1774 nitropack_invalidate( NULL, "single:$postID", $reason );
1775 }
1776
1777 nitropack_invalidate( NULL, "post:$postID", $reason );
1778
1779 if ( $hasImportantChangeInPost === NULL ) {
1780 $hasImportantChangeInPost = nitropack_has_post_important_change( $post );
1781 }
1782 if ( $taxonomies === NULL ) {
1783 if ( $hasImportantChangeInPost ) { // This change should be reflected in all taxonomy pages
1784 $taxonomies = array( 'related' => nitropack_get_taxonomies( $post ) );
1785 } else { // No important change, so only update taxonomy pages which have been added or removed from the post
1786 $taxonomies = nitropack_get_taxonomies_for_update( $post );
1787 }
1788 }
1789 if ( $taxonomies ) {
1790 if ( ! empty( $taxonomies['added'] ) ) { // taxonomies that the post was just added to, must purge all pages for these taxonomies
1791 foreach ( $taxonomies['added'] as $term_taxonomy_id ) {
1792 nitropack_invalidate( NULL, "tax:$term_taxonomy_id", $reason );
1793 }
1794 }
1795 if ( ! empty( $taxonomies['deleted'] ) ) { // taxonomy pages that the post was just removed from (also accounts for paginations via the taxpost: tag instead of only tax:)
1796 foreach ( $taxonomies['deleted'] as $term_taxonomy_id ) {
1797 nitropack_invalidate( NULL, "taxpost:$term_taxonomy_id:$postID", $reason );
1798 }
1799 }
1800 if ( ! empty( $taxonomies['related'] ) ) { // taxonomy pages that the post is linked to (also accounts for paginations via the taxpost: tag instead of only tax:)
1801 foreach ( $taxonomies['related'] as $term_taxonomy_id ) {
1802 nitropack_invalidate( NULL, "taxpost:$term_taxonomy_id:$postID", $reason );
1803 }
1804 }
1805 }
1806 } else {
1807 if ( $post->public ) {
1808 nitropack_invalidate( NULL, "post:$postID", $reason );
1809 }
1810
1811 $posts = get_post_ancestors( $postID );
1812 foreach ( $posts as $parentID ) {
1813 $parent = get_post( $parentID );
1814 nitropack_clean_post_cache( $parent, false, false, $reason );
1815 }
1816 }
1817 } catch (\Exception $e) {
1818 }
1819 }
1820
1821 function nitropack_get_nice_post_type_label( $postType ) {
1822 $postTypes = get_post_types( array(
1823 "name" => $postType
1824 ), "objects" );
1825
1826 return ! empty( $postTypes[ $postType ] ) && ! empty( $postTypes[ $postType ]->labels ) ? $postTypes[ $postType ]->labels->singular_name : $postType;
1827 }
1828
1829 function nitropack_handle_comment_transition( $new, $old, $comment ) {
1830 if ( ! get_option( "nitropack-autoCachePurge", 1 ) )
1831 return;
1832
1833 try {
1834 $postID = $comment->comment_post_ID;
1835 $post = get_post( $postID );
1836 $postType = isset( $post->post_type ) ? $post->post_type : "post";
1837 $CPTOptimization = NitroPack\WordPress\Settings\CPTOptimization::getInstance();
1838 $cacheableObjectTypes = $CPTOptimization->nitropack_get_cacheable_object_types();
1839
1840 if ( in_array( $postType, $cacheableObjectTypes ) ) {
1841 nitropack_invalidate( NULL, "single:" . $postID, sprintf( "Invalidation of '%s' due to changing related comment status", $post->post_title ) );
1842 }
1843 } catch (\Exception $e) {
1844 // TODO: Log the error
1845 }
1846 }
1847
1848 function nitropack_handle_comment_post( $commentID, $isApproved ) {
1849 if ( ! get_option( "nitropack-autoCachePurge", 1 ) || $isApproved !== 1 )
1850 return;
1851
1852 try {
1853 $comment = get_comment( $commentID );
1854 $postID = $comment->comment_post_ID;
1855 $post = get_post( $postID );
1856 nitropack_invalidate( NULL, "single:" . $postID, sprintf( "Invalidation of '%s' due to posting a new approved comment", $post->post_title ) );
1857 } catch (\Exception $e) {
1858 // TODO: Log the error
1859 }
1860 }
1861
1862 function nitropack_detect_changes_and_clean_post_cache( $post ) {
1863 if ( ! get_option( "nitropack-autoCachePurge", 1 ) ) {
1864 return;
1865 }
1866
1867 $post_before = nitropack_get_post_pre_update( $post );
1868 $ignoredComparisonKeys = array( 'post_modified', 'post_modified_gmt' );
1869 $canCleanPostCache = false;
1870 $postStatesEqual = nitropack_compare_posts( (array) $post_before, (array) $post, $ignoredComparisonKeys );
1871
1872 if ( $postStatesEqual ) {
1873 $taxCurrent = nitropack_get_taxonomies( $post );
1874 $taxPreUpdate = nitropack_get_taxonomies_pre_update( $post );
1875 $taxAreEqual = nitropack_compare_posts( $taxCurrent, $taxPreUpdate );
1876 if ( $taxAreEqual ) {
1877 $metaCurrent = get_post_meta( $post->ID );
1878 $metaPreUpdate = nitropack_get_meta_pre_update( $post );
1879 $metaIsEqual = nitropack_compare_posts( $metaCurrent, $metaPreUpdate );
1880 if ( ! $metaIsEqual ) {
1881 $canCleanPostCache = true;
1882 }
1883 } else {
1884 $canCleanPostCache = true;
1885 }
1886 } else {
1887 $canCleanPostCache = true;
1888 }
1889
1890 if ( $canCleanPostCache ) {
1891 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post );
1892 nitropack_clean_post_cache( $post );
1893 define( 'NITROPACK_PURGE_CACHE', true );
1894 }
1895 }
1896
1897
1898 function nitropack_handle_post_transition( $new, $old, $post ) {
1899 if ( wp_is_post_revision( $post ) )
1900 return;
1901 if ( ! empty( $post->ID ) && in_array( $post->ID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs ) )
1902 return;
1903 if ( ! get_option( "nitropack-autoCachePurge", 1 ) )
1904 return;
1905
1906 try {
1907 if ( $new === "auto-draft" || ( $new === "draft" && $old === "auto-draft" ) || ( $new === "draft" && $old != "publish" ) || $new === "inherit" ) { // Creating a new post or draft, don't do anything for now.
1908 return;
1909 }
1910
1911 $ignoredPostTypes = array(
1912 "revision",
1913 "scheduled-action",
1914 "flamingo_contact",
1915 "carts"/*WooCommerce Cart Reports*/
1916 );
1917
1918 $nicePostTypes = array(
1919 "post" => "Post",
1920 "page" => "Page",
1921 "tribe_events" => "Calendar Event",
1922 );
1923 $postType = isset( $post->post_type ) ? $post->post_type : "post";
1924 $nicePostTypeLabel = nitropack_get_nice_post_type_label( $postType );
1925
1926 if ( in_array( $postType, $ignoredPostTypes ) )
1927 return;
1928
1929 switch ( $postType ) {
1930 case "nav_menu_item":
1931 nitropack_invalidate( NULL, NULL, sprintf( "Invalidation of all pages due to modifying menu entries" ) );
1932 break;
1933 case "customize_changeset":
1934 nitropack_invalidate( NULL, NULL, sprintf( "Invalidation of all pages due to applying appearance customization" ) );
1935 break;
1936 case "custom_css":
1937 nitropack_invalidate( NULL, NULL, sprintf( "Invalidation of all pages due to modifying custom CSS" ) );
1938 break;
1939 default:
1940 if ( $new == "future" ) {
1941 nitropack_clean_post_cache( $post, array( 'added' => nitropack_get_taxonomies( $post ) ), true, sprintf( "Invalidate related pages due to scheduling %s '%s'", $nicePostTypeLabel, $post->post_title ) );
1942 } else if ( $new === 'publish' && $old === 'trash' ) {
1943 nitropack_clean_post_cache( $post, array( 'added' => nitropack_get_taxonomies( $post ) ), true, sprintf( "Invalidate related pages due to restoring %s '%s'", $nicePostTypeLabel, $post->post_title ) );
1944 } else if ( $new == "publish" && $old != "publish" ) {
1945 /* Handle first publish */
1946 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post->ID );
1947 if ( ! defined( 'NITROPACK_PURGE_CACHE' ) ) {
1948 nitropack_clean_post_cache( $post, array( 'added' => nitropack_get_taxonomies( $post ) ), true, sprintf( "Invalidate related pages due to publishing %s '%s'", $nicePostTypeLabel, $post->post_title ), true );
1949 }
1950 if ( $post->post_type === 'post' ) {
1951 nitropack_invalidate( NULL, "pageType:blogindex", 'Invalidation of blog page due to changing related post status' );
1952 }
1953 } else if ( $new == "trash" && $old == "publish" ) {
1954 nitropack_clean_post_cache( $post, array( 'deleted' => nitropack_get_taxonomies( $post ) ), true, sprintf( "Invalidate related pages due to deleting %s '%s'", $nicePostTypeLabel, $post->post_title ), true );
1955 } else if ( $new == "private" && $old == "publish" ) {
1956 nitropack_clean_post_cache( $post, array( 'deleted' => nitropack_get_taxonomies( $post ) ), true, sprintf( "Invalidate related pages due to making %s '%s' private", $nicePostTypeLabel, $post->post_title ), true );
1957 } else if ( $new == "draft" && $old == "publish" ) {
1958 nitropack_clean_post_cache( $post, array( 'deleted' => nitropack_get_taxonomies( $post ) ), true, sprintf( "Invalidate related pages due to making %s '%s' a draft", $nicePostTypeLabel, $post->post_title ), true );
1959 } else if ( $new != "trash" ) {
1960 if ( ! defined( 'NITROPACK_PURGE_CACHE' ) ) {
1961 nitropack_detect_changes_and_clean_post_cache( $post );
1962 }
1963 if ( $new == 'publish' ) {
1964 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post->ID );
1965 }
1966 }
1967 break;
1968 }
1969 } catch (\Exception $e) {
1970 // TODO: Log the error
1971 }
1972 }
1973
1974 function nitropack_post_link_listener( $permalink, $post, $leavename ) {
1975 if ( is_object( $post ) ) {
1976 nitropack_handle_the_post( $post );
1977 }
1978
1979 return $permalink;
1980 }
1981
1982 function nitropack_handle_the_post( $post ) {
1983 global $np_customExpirationTimes, $np_queriedObj;
1984 if ( defined( 'POSTEXPIRATOR_VERSION' ) ) {
1985 $postExpiryDate = get_post_meta( $post->ID, "_expiration-date", true );
1986 if ( ! empty( $postExpiryDate ) && $postExpiryDate > time() ) { // We only need to look at future dates
1987 $np_customExpirationTimes[] = $postExpiryDate;
1988 }
1989 }
1990
1991 if ( function_exists( "sort_portfolio" ) ) { // Portfolio Sorting plugin
1992 $portfolioStartDate = get_post_meta( $post->ID, "start_date", true );
1993 $portfolioEndDate = get_post_meta( $post->ID, "end_date", true );
1994 if ( ! empty( $portfolioStartDate ) && strtotime( $portfolioStartDate ) > time() ) { // We only need to look at future dates
1995 $np_customExpirationTimes[] = strtotime( $portfolioStartDate );
1996 } else if ( ! empty( $portfolioEndDate ) && strtotime( $portfolioEndDate ) > time() ) { // We only need to look at future dates
1997 $np_customExpirationTimes[] = strtotime( $portfolioEndDate );
1998 }
1999 }
2000
2001 $GLOBALS["NitroPack.tags"][ "post:" . $post->ID ] = 1;
2002 $GLOBALS["NitroPack.tags"][ "author:" . $post->post_author ] = 1;
2003 if ( $np_queriedObj ) {
2004 $GLOBALS["NitroPack.tags"][ "taxpost:" . $np_queriedObj->term_taxonomy_id . ":" . $post->ID ] = 1;
2005 }
2006 }
2007
2008 function nitropack_ignore_post_updates( $postID ) {
2009 \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs[] = $postID;
2010 }
2011
2012 function nitropack_get_taxonomies( $post ) {
2013 $term_taxonomy_ids = array();
2014 $taxonomies = get_object_taxonomies( $post->post_type );
2015 foreach ( $taxonomies as $taxonomy ) {
2016 $terms = get_the_terms( $post->ID, $taxonomy );
2017 if ( ! empty( $terms ) ) {
2018 foreach ( $terms as $term ) {
2019 $term_taxonomy_ids[] = $term->term_taxonomy_id;
2020 }
2021 }
2022 }
2023 return $term_taxonomy_ids;
2024 }
2025
2026 function nitropack_get_taxonomies_for_update( $post ) {
2027 $prevTaxonomies = nitropack_get_taxonomies_pre_update( $post );
2028 $newTaxonomies = nitropack_get_taxonomies( $post );
2029 $intersection = array_intersect( $newTaxonomies, $prevTaxonomies );
2030 $prevTaxonomies = array_diff( $prevTaxonomies, $intersection );
2031 $newTaxonomies = array_diff( $newTaxonomies, $intersection );
2032 return array(
2033 "added" => array_diff( $newTaxonomies, $prevTaxonomies ),
2034 "deleted" => array_diff( $prevTaxonomies, $newTaxonomies )
2035 );
2036 }
2037
2038 function nitropack_get_post_pre_update( $post ) {
2039 return ! empty( \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $post->ID ] ) ? \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $post->ID ] : NULL;
2040 }
2041
2042 function nitropack_get_taxonomies_pre_update( $post ) {
2043 return ! empty( \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $post->ID ] ) ? \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $post->ID ] : array();
2044 }
2045
2046 function nitropack_get_meta_pre_update( $post ) {
2047 return ! empty( \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $post->ID ] ) ? \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $post->ID ] : array();
2048 }
2049
2050 function nitropack_log_post_pre_update( $postID ) {
2051 if ( in_array( $postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs ) )
2052 return;
2053
2054
2055 $post = get_post( $postID );
2056 \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $postID ] = $post;
2057 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $postID ] = nitropack_get_taxonomies( $post );
2058 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2059 \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $postID ] = get_post_meta( $postID );
2060 }
2061
2062 function nitropack_log_product_pre_api_update( $product, $request, $creating ) {
2063
2064 if ( ! $creating ) {
2065
2066 $postID = $product->get_id();
2067 if ( in_array( $postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs ) )
2068 return;
2069
2070
2071 $post = get_post( $postID );
2072 \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $postID ] = $post;
2073 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $postID ] = nitropack_get_taxonomies( $post );
2074 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2075 \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $postID ] = get_post_meta( $postID );
2076 }
2077
2078 return $product;
2079 }
2080
2081 function nitropack_compare_posts( array $p1, array $p2, $ignoredKeys = null ) {
2082 $p1keys = array_keys( $p1 );
2083 $p2keys = array_keys( $p2 );
2084 if ( count( $p1keys ) !== count( $p2keys ) ) {
2085 return false;
2086 }
2087 if ( array_diff( $p1keys, $p2keys ) ) {
2088 return false;
2089 }
2090
2091 $isP1assoc = false;
2092 $expectedKey = 0;
2093 foreach ( $p2 as $i => $_ ) {
2094 if ( $i !== $expectedKey ) {
2095 $isP1assoc = true;
2096 }
2097 $expectedKey++;
2098 }
2099
2100 $isP2assoc = false;
2101 $expectedKey = 0;
2102 foreach ( $p2 as $i => $_ ) {
2103 if ( $i !== $expectedKey ) {
2104 $isP2assoc = true;
2105 }
2106 $expectedKey++;
2107 }
2108
2109 if ( $isP1assoc !== $isP2assoc ) {
2110 return false;
2111 }
2112
2113 if ( ! $isP1assoc && ! $isP2assoc ) {
2114 sort( $p1 );
2115 sort( $p2 );
2116 }
2117
2118 foreach ( $p1 as $poKey => $poVal ) {
2119 if ( $ignoredKeys && in_array( $poKey, $ignoredKeys, true ) ) {
2120 continue;
2121 }
2122 $checkpoint01 = is_array( $poVal );
2123 $checkpoint02 = is_array( $p2[ $poKey ] );
2124 if ( $checkpoint01 && $checkpoint02 ) {
2125 if ( ! nitropack_compare_posts( $poVal, $p2[ $poKey ], $ignoredKeys, 'Re:' ) ) { //'Re:' left for debug purpose to destinguish between main and recursive call
2126 return false;
2127 }
2128 } elseif ( ! $checkpoint01 && ! $checkpoint02 ) {
2129 if ( $poVal != $p2[ $poKey ] ) {
2130 return false;
2131 }
2132 } else {
2133 return false;
2134 }
2135 }
2136 return true;
2137 }
2138
2139 function nitropack_filter_tag( $tag ) {
2140 return preg_replace( "/[^a-zA-Z0-9:]/", ":", $tag );
2141 }
2142
2143 function nitropack_log_tags() {
2144 if ( ! empty( $GLOBALS["NitroPack.instance"] ) && ! empty( $GLOBALS["NitroPack.tags"] ) ) {
2145 $nitro = $GLOBALS["NitroPack.instance"];
2146 $layout = nitropack_get_layout();
2147 try {
2148 $config = $nitro->getConfig();
2149 $useHeader = ! empty( $config->TagsViaHeader );
2150
2151 if ( $layout == "home" ) {
2152 if ( $useHeader ) {
2153 nitropack_header( "x-nitro-tags:pageType:home" );
2154 } else {
2155 $nitro->getApi()->tagUrl( $nitro->getUrl(), "pageType:home" );
2156 }
2157 } else if ( $layout == "archive" ) {
2158 if ( $useHeader ) {
2159 nitropack_header( "x-nitro-tags:pageType:archive" );
2160 } else {
2161 $nitro->getApi()->tagUrl( $nitro->getUrl(), "pageType:archive" );
2162 }
2163 } else {
2164 if ( $useHeader && count( $GLOBALS["NitroPack.tags"] ) <= 100 ) {
2165 nitropack_header( "x-nitro-tags:" . implode( "|", array_map( "nitropack_filter_tag", array_keys( $GLOBALS["NitroPack.tags"] ) ) ) );
2166 } else {
2167 $nitro->getApi()->tagUrl( $nitro->getUrl(), array_map( "nitropack_filter_tag", array_keys( $GLOBALS["NitroPack.tags"] ) ) );
2168 }
2169 }
2170 } catch (\Exception $e) {
2171 }
2172 }
2173 }
2174
2175 function nitropack_extend_nonce_life( $life ) {
2176 if ( nitropack_is_rest() && isset( $_COOKIE["nitroCachedPage"] ) && $_COOKIE["nitroCachedPage"] == "0" ) {
2177 return $life;
2178 }
2179
2180 // Nonce life should be extended only:
2181 // - if NitroPack is connected for this site
2182 // - if the current value is shorter than the life time of a cache file
2183 // - if no user is logged in
2184 // - for cacheable requests
2185 //
2186 // Reasons why we might need to extend the nonce life time even for requests that are not cacheable:
2187 // - a request may be cachable at first, but become uncachable during changes at runtime or user actions on the page (example: log in via AJAX on a category page. Once logged in the page will not redirect, but if there is an infinite scroll it will stop working if we stop extending the nonce life time)
2188 // - a request may seem cachable at first, but be determined uncachable during runtime (example: visit to a URL of a page whose post type does not match the enabled cacheable post types, or a cart, checkout page, etc.)
2189
2190 if ( ( null !== $nitro = get_nitropack_sdk() ) ) {
2191 $siteConfig = nitropack_get_site_config();
2192 if ( $siteConfig && ! empty( $siteConfig["isDlmActive"] ) && ! empty( $siteConfig["dlm_downloading_url"] ) && ! empty( $siteConfig["dlm_download_endpoint"] ) ) {
2193 $currentUrl = $nitro->getUrl();
2194 if ( strpos( $currentUrl, $siteConfig["dlm_downloading_url"] ) !== false || strpos( $currentUrl, $siteConfig["dlm_download_endpoint"] ) !== false ) {
2195 // Do not modify the nonce times on pages of Download Monitor
2196 return $life;
2197 }
2198 }
2199 $cacheExpiration = $nitro->getConfig()->PageCache->ExpireTime;
2200 return $cacheExpiration > $life ? $cacheExpiration : $life; // Extend the life of cacheable nonces up to the cache expiration time if needed
2201 }
2202 return $life;
2203 }
2204
2205 function nitropack_reconfigure_webhooks() {
2206 nitropack_verify_ajax_nonce( $_REQUEST );
2207 $siteConfig = nitropack_get_site_config();
2208
2209 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) ) {
2210 $siteId = $siteConfig["siteId"];
2211 if ( null !== $nitro = get_nitropack_sdk() ) {
2212 $token = nitropack_generate_webhook_token( $siteId );
2213 try {
2214 nitropack_setup_webhooks( $nitro, $token );
2215 update_option( "nitropack-webhookToken", $token );
2216 nitropack_json_and_exit( array( "status" => "success", 'message' => __( 'Connection reconfigured successfully', 'nitropack' ) ) );
2217 } catch (\NitroPack\SDK\WebhookException $e) {
2218 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Webhook Error: ' . $e );
2219 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Webhook Error: ', 'nitropack' ) . $e->getTraceAsString() ) );
2220 }
2221 } else {
2222 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Unable to get SDK instance' );
2223 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Unable to get SDK instance', 'nitropack' ) ) );
2224 }
2225 } else {
2226 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Incomplete site config. Please reinstall the plugin' );
2227 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Incomplete site config. Please reinstall the plugin!', 'nitropack' ) ) );
2228 }
2229 }
2230
2231 function nitropack_generate_webhook_token( $siteId ) {
2232 if ( defined( "NITROPACK_WEBHOOK_TOKEN" ) && ! empty( NITROPACK_WEBHOOK_TOKEN ) ) {
2233 return NITROPACK_WEBHOOK_TOKEN;
2234 }
2235 return md5( __FILE__ . ":" . $siteId );
2236 }
2237
2238 function nitropack_check_func_availability( $func_name ) {
2239 if ( function_exists( 'ini_get' ) ) {
2240 $existsResult = stripos( ini_get( 'disable_functions' ), $func_name ) === false;
2241 } else {
2242 $existsResult = function_exists( $func_name );
2243 }
2244 return $existsResult;
2245 }
2246
2247 function nitropack_prevent_connecting( $nitroSDK ) {
2248 $remoteUrl = $nitroSDK->getApi()->getWebhook( "config" );
2249 if ( empty( $remoteUrl ) ) {
2250 return false;
2251 }
2252 $siteConfig = nitropack_get_site_config();
2253 $localUrl = new \NitroPack\Url\Url( $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url() );
2254 $localHome = strtolower( $localUrl->getHost() . $localUrl->getPath() );
2255 $storedUrl = new \NitroPack\Url\Url( $remoteUrl );
2256 $remoteHome = strtolower( $storedUrl->getHost() . $storedUrl->getPath() );
2257 if ( $localHome === $remoteHome ) {
2258 return false;
2259 }
2260 return array( 'local' => $localHome, 'remote' => $remoteHome );
2261 }
2262
2263 function nitropack_reset_webhooks( $nitroSDK ) {
2264 $nitroSDK->getApi()->unsetWebhook( "config" );
2265 $nitroSDK->getApi()->unsetWebhook( "cache_clear" );
2266 $nitroSDK->getApi()->unsetWebhook( "cache_ready" );
2267 }
2268
2269 function nitropack_setup_webhooks( $nitro, $token = NULL ) {
2270 if ( ! $nitro || ! $token ) {
2271 throw new \NitroPack\SDK\WebhookException( 'Webhook token cannot be empty.' );
2272 }
2273
2274 $homeUrl = strtolower( get_home_url() );
2275 $configUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=config&token=$token" );
2276 $cacheClearUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=cache_clear&token=$token" );
2277 $cacheReadyUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=cache_ready&token=$token" );
2278
2279 $nitro->getApi()->setWebhook( "config", $configUrl );
2280 $nitro->getApi()->setWebhook( "cache_clear", $cacheClearUrl );
2281 $nitro->getApi()->setWebhook( "cache_ready", $cacheReadyUrl );
2282 }
2283
2284 function nitropack_is_cart_cache_active() {
2285 $nitro = get_nitropack()->getSdk();
2286 if ( $nitro ) {
2287 $config = $nitro->getConfig();
2288 if ( ! empty( $config->StatefulCache->Status ) && ! empty( $config->StatefulCache->CartCache ) ) {
2289 return nitropack_is_cart_cache_available();
2290 }
2291 }
2292 return false;
2293 }
2294
2295 function nitropack_is_cart_cache_available() {
2296 $nitro = get_nitropack()->getSdk();
2297 if ( $nitro ) {
2298 $config = $nitro->getConfig();
2299 if ( ! empty( $config->StatefulCache->isCartCacheAvailable ) ) {
2300 return true;
2301 }
2302 }
2303 return false;
2304 }
2305
2306 function nitropack_handle_compression_toggle( $old_value, $new_value ) {
2307 nitropack_update_blog_compression( $new_value == 1 );
2308 }
2309
2310 function nitropack_update_blog_compression( $enableCompression = false ) {
2311 if ( get_nitropack()->isConnected() ) {
2312 $siteConfig = nitropack_get_site_config();
2313 $siteId = $siteConfig["siteId"];
2314 $siteSecret = $siteConfig["siteSecret"];
2315 $blogId = get_current_blog_id();
2316 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'update_blog_compression' );
2317 get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId, $enableCompression );
2318 }
2319 }
2320
2321 function nitropack_get_site_config() {
2322 return get_nitropack()->getSiteConfig();
2323 }
2324
2325 function nitropack_get_current_site_id() {
2326
2327 $site_config = nitropack_get_site_config();
2328
2329 if ( $site_config && isset( $site_config['siteId'] ) ) {
2330 return $site_config['siteId'];
2331 }
2332 }
2333
2334 function get_nitropack() {
2335 return \NitroPack\WordPress\NitroPack::getInstance();
2336 }
2337
2338 function nitropack_event( $event, $nitro = null, $additional_meta_data = null ) {
2339 global $wp_version;
2340
2341 try {
2342 $eventUrl = get_nitropack_integration_url( "extensionEvent", $nitro );
2343 $domain = ! empty( $_SERVER["HTTP_HOST"] ) ? $_SERVER["HTTP_HOST"] : "Unknown";
2344
2345
2346 if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
2347 $platform = 'WooCommerce';
2348 } else {
2349 $platform = 'WordPress';
2350 }
2351
2352 $query_data = array(
2353 'event' => $event,
2354 'platform' => $platform,
2355 'platform_version' => $wp_version,
2356 'nitropack_extension_version' => NITROPACK_VERSION,
2357 'additional_meta_data' => $additional_meta_data ? json_encode( $additional_meta_data ) : "{}",
2358 'domain' => $domain
2359 );
2360
2361 $client = new NitroPack\HttpClient\HttpClient( $eventUrl . '&' . http_build_query( $query_data ) );
2362 $client->doNotDownload = true;
2363 $client->fetch();
2364 } catch (\Exception $e) {
2365 }
2366 }
2367
2368 function nitropack_get_wpconfig_path() {
2369 $configFilePath = nitropack_trailingslashit( ABSPATH ) . "wp-config.php";
2370 if ( ! file_exists( $configFilePath ) ) {
2371 $configFilePath = nitropack_trailingslashit( dirname( ABSPATH ) ) . "wp-config.php";
2372 $settingsFilePath = nitropack_trailingslashit( dirname( ABSPATH ) ) . "wp-settings.php"; // We need to check for this file to avoid confusion if the current installation is a nested directory of another WP installation. Refer to wp-load.php for more information.
2373 if ( ! file_exists( $configFilePath ) || file_exists( $settingsFilePath ) ) {
2374 return false;
2375 }
2376 }
2377
2378
2379 if ( ! is_writable( $configFilePath ) ) {
2380 return false;
2381 }
2382
2383 return $configFilePath;
2384 }
2385
2386 function nitropack_get_htaccess_path() {
2387 $configFilePath = nitropack_trailingslashit( ABSPATH ) . ".htaccess";
2388 if ( ! file_exists( $configFilePath ) ) {
2389 return false;
2390 }
2391
2392
2393 if ( ! is_writable( $configFilePath ) ) {
2394 return false;
2395 }
2396
2397 return $configFilePath;
2398 }
2399
2400 function nitropack_detect_hosting() {
2401 if ( \NitroPack\Integration\Hosting\Flywheel::detect() ) {
2402 return "flywheel";
2403 } else if ( \NitroPack\Integration\Hosting\Cloudways::detect() ) {
2404 return "cloudways";
2405 } else if ( \NitroPack\Integration\Hosting\WPEngine::detect() ) {
2406 return "wpengine";
2407 } else if ( \NitroPack\Integration\Hosting\SiteGround::detect() ) {
2408 return "siteground";
2409 } else if ( \NitroPack\Integration\Hosting\GoDaddyWPaaS::detect() ) {
2410 return "godaddy_wpaas";
2411 } else if ( \NitroPack\Integration\Hosting\GridPane::detect() ) {
2412 return "gridpane";
2413 } else if ( \NitroPack\Integration\Hosting\Kinsta::detect() ) {
2414 return "kinsta";
2415 } else if ( \NitroPack\Integration\Hosting\Closte::detect() ) {
2416 return "closte";
2417 } else if ( \NitroPack\Integration\Hosting\Pagely::detect() ) {
2418 return "pagely";
2419 } else if ( \NitroPack\Integration\Hosting\WPX::detect() ) {
2420 return "wpx";
2421 } else if ( \NitroPack\Integration\Hosting\Vimexx::detect() ) {
2422 return "vimexx";
2423 } else if ( \NitroPack\Integration\Hosting\Pressable::detect() ) {
2424 return "pressable";
2425 } else if ( \NitroPack\Integration\Hosting\RocketNet::detect() ) {
2426 return "rocketnet";
2427 } else if ( \NitroPack\Integration\Hosting\Savvii::detect() ) {
2428 return "savvii";
2429 } else if ( \NitroPack\Integration\Hosting\DreamHost::detect() ) {
2430 return "dreamhost";
2431 } else if ( \NitroPack\Integration\Hosting\Raidboxes::detect() ) {
2432 return "raidboxes";
2433 } else {
2434 return "unknown";
2435 }
2436 }
2437
2438 function nitropack_removeCacheBustParam( $content ) {
2439 $content = preg_replace( "/(\?|%26|&#0?38;|&#x0?26;|&(amp;)?)ignorenitro(%3D|=)[a-fA-F0-9]{32}(?!%26|&#0?38;|&#x0?26;|&(amp;)?)\/?/mu", "", $content );
2440 return preg_replace( "/(\?|%26|&#0?38;|&#x0?26;|&(amp;)?)ignorenitro(%3D|=)[a-fA-F0-9]{32}(%26|&#0?38;|&#x0?26;|&(amp;)?)/mu", "$1", $content );
2441 }
2442
2443 function nitropack_handle_request( $servedFrom = "unknown" ) {
2444
2445 global $np_integrationSetupEvent;
2446
2447 if ( isset( $_GET["ignorenitro"] ) ) {
2448 unset( $_GET["ignorenitro"] );
2449 }
2450
2451 if ( defined( "NITROPACK_STRIP_IGNORENITRO" ) && NITROPACK_STRIP_IGNORENITRO && $_SERVER['REQUEST_URI'] != '' ) {
2452 $_SERVER['REQUEST_URI'] = nitropack_removeCacheBustParam( $_SERVER['REQUEST_URI'] );
2453 }
2454
2455 nitropack_header( 'Cache-Control: no-cache' );
2456 do_action( "nitropack_early_cache_headers" ); // Overrides the Cache-Control header on supported platforms
2457 $isManageWpRequest = ! empty( $_GET["mwprid"] );
2458 $isWpCli = nitropack_is_wp_cli();
2459
2460 if ( file_exists( NITROPACK_CONFIG_FILE ) && ! empty( $_SERVER["HTTP_HOST"] ) && ! empty( $_SERVER["REQUEST_URI"] ) && ! $isManageWpRequest && ! $isWpCli ) {
2461 try {
2462 $siteConfig = nitropack_get_site_config();
2463 if ( $siteConfig && null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
2464 if ( is_valid_nitropack_webhook() ) {
2465 nitropack_handle_webhook();
2466 } else if ( is_valid_nitropack_beacon() ) {
2467 nitropack_handle_beacon();
2468 } else if ( is_valid_nitropack_heartbeat() ) {
2469 nitropack_handle_heartbeat();
2470 } else {
2471 $GLOBALS["NitroPack.instance"] = $nitro;
2472
2473 if ( nitropack_passes_cookie_requirements() || ( nitropack_is_ajax() && ! empty( $_COOKIE["nitroCachedPage"] ) ) ) {
2474 // Check whether the current URL is cacheable
2475 // If this is an AJAX request, check whether the referer is cachable - this is needed for cases when NitroPack's "Enabled URLs" option is being used to whitelist certain URLs.
2476 // If we are not checking the referer, the AJAX requests on these pages can fail.
2477 $urlToCheck = nitropack_is_ajax() && ! empty( $_SERVER["HTTP_REFERER"] ) ? $_SERVER["HTTP_REFERER"] : $nitro->getUrl();
2478 if ( $nitro->isAllowedUrl( $urlToCheck ) ) {
2479 add_filter( 'nonce_life', 'nitropack_extend_nonce_life' );
2480 }
2481 }
2482
2483 if ( nitropack_passes_cookie_requirements() && apply_filters( "nitropack_can_serve_cache", true ) ) {
2484 if ( $nitro->isCacheAllowed() ) {
2485 if ( ! nitropack_is_ajax() ) {
2486 do_action( "nitropack_cacheable_cache_headers" );
2487 }
2488
2489 // Handle corner cases where the URL contains multiple slashes
2490 if ( ! empty( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '//' ) !== false ) {
2491 $redirect_url = preg_replace( '#(?<!:)/{2,}#', '/', $nitro->getUrl() );
2492 header( 'HTTP/1.1 301 Moved Permanently' );
2493 header( 'Location: ' . $redirect_url );
2494 exit;
2495 }
2496
2497 if ( ! empty( $siteConfig["compression"] ) ) {
2498 $nitro->enableCompression();
2499 }
2500
2501 if ( $nitro->hasLocalCache() ) {
2502 // TODO: Make this work so we can provide the reverse proxies with this information $remainingTtl = $nitr->pageCache->getRemainingTtl();
2503 do_action( "nitropack_cachehit_cache_headers" ); // TODO: Pass the remaining TTL here
2504 $cacheControlOverride = defined( "NITROPACK_CACHE_CONTROL_OVERRIDE" ) ? NITROPACK_CACHE_CONTROL_OVERRIDE : NULL;
2505 if ( $cacheControlOverride ) {
2506 nitropack_header( 'Cache-Control: ' . $cacheControlOverride );
2507 }
2508
2509 nitropack_header( 'X-Nitro-Cache: HIT' );
2510 nitropack_header( 'X-Nitro-Cache-From: ' . $servedFrom );
2511 $cjHandler = new \NitroPack\SDK\Utils\CjHandler( $nitro );
2512 $cjHandler->handleQueryParams();
2513 $nitro->pageCache->readfile();
2514 exit;
2515 } else {
2516 // We need the following if..else block to handle bot requests which will not be firing our beacon
2517 if ( nitropack_is_warmup_request() ) {
2518 if ( ! empty( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ) ) {
2519 add_action( "init", function () use ($nitro) {
2520 $nitro->hasRemoteCache( "default" ); // Only ping the API letting our service know that this page must be cached.
2521 exit;
2522 }, 9999 );
2523 return; // We need to wait for a language plugin (if present) to redirect
2524 } else {
2525 $nitro->hasRemoteCache( "default" ); // Only ping the API letting our service know that this page must be cached.
2526 exit; // No need to continue handling this request. The response is not important.
2527 }
2528 } else if ( nitropack_is_lighthouse_request() || nitropack_is_gtmetrix_request() || nitropack_is_pingdom_request() ) {
2529 $nitro->hasRemoteCache( "default" ); // Ping the API letting our service know that this page must be cached.
2530 }
2531
2532 $nitro->pageCache->useInvalidated( true );
2533 if ( $nitro->hasLocalCache() ) {
2534 nitropack_header( 'X-Nitro-Cache: STALE' );
2535 nitropack_header( 'X-Nitro-Cache-From: ' . $servedFrom );
2536 $cjHandler = new \NitroPack\SDK\Utils\CjHandler( $nitro );
2537 $cjHandler->handleQueryParams();
2538 $nitro->pageCache->readfile();
2539 exit;
2540 } else {
2541 $nitro->pageCache->useInvalidated( false );
2542 }
2543 }
2544 }
2545 }
2546 }
2547 }
2548 } catch (\Exception $e) {
2549 // Do nothing, cache serving will be handled by nitropack_init
2550 }
2551 }
2552 }
2553
2554 function nitropack_is_dropin_cache_allowed() {
2555 $siteConfig = nitropack_get_site_config();
2556 return $siteConfig && empty( $siteConfig["isEzoicActive"] );
2557 }
2558
2559 function nitropack_cookiepath() {
2560 $siteConfig = nitropack_get_site_config();
2561 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
2562 $url = new \NitroPack\Url\Url( $homeUrl );
2563 return $url ? $url->getPath() : "/";
2564 }
2565
2566 function nitropack_cookie_path_ajax() {
2567 nitropack_verify_ajax_nonce( $_REQUEST );
2568 nitropack_json_and_exit( array(
2569 'cookie_path' => nitropack_cookiepath()
2570 ) );
2571 }
2572 add_action( 'wp_ajax_nitropack_cookie_path_ajax', 'nitropack_cookie_path_ajax' );
2573
2574 function nitropack_setcookie( $name, $value, $expires = NULL, $options = [] ) {
2575 if ( headers_sent() )
2576 return;
2577 $cookie_options = '';
2578 $cookie_path = nitropack_cookiepath();
2579
2580 if ( $expires && is_numeric( $expires ) ) {
2581 $options["Expires"] = date( "D, d M Y H:i:s", (int) $expires ) . ' GMT';
2582 }
2583
2584 if ( empty( $options["SameSite"] ) ) {
2585 $options["SameSite"] = "Lax";
2586 }
2587
2588 foreach ( $options as $optName => $optValue ) {
2589 $cookie_options .= "$optName=$optValue; ";
2590 }
2591 nitropack_header( "set-cookie: $name=$value; Path=$cookie_path; " . $cookie_options, false );
2592 }
2593
2594 function nitropack_header( $header, $replace = true, $response_code = 0 ) {
2595 if ( ! nitropack_is_wp_cron() && ! nitropack_is_wp_cli() ) {
2596 header( $header, $replace, $response_code );
2597 }
2598 }
2599
2600 function nitropack_upgrade_handler( $entity ) {
2601 $np = 'nitropack/main.php';
2602 $trigger = $entity;
2603 if ( $entity instanceof Plugin_Upgrader ) {
2604 $trigger = $entity->plugin_info();
2605 if ( ! is_plugin_active( $trigger ) ) {
2606 return;
2607 }
2608 }
2609
2610 if ( $entity instanceof Theme_Upgrader ) {
2611 if ( $entity->theme_info()->Name === wp_get_theme()->Name ) {
2612 nitropack_theme_handler( 'Theme updated' );
2613 }
2614 return;
2615 }
2616
2617 if ( $trigger !== $np ) {
2618 $cookie_expires = date( "D, d M Y H:i:s", time() + 600 ) . ' GMT';
2619 nitropack_setcookie( 'nitropack_apwarning', "1", time() + 600 );
2620 }
2621 }
2622 /**
2623 * Caches some options in the config so that we can access them before get_option() is defined
2624 * which is in advanced_cache.php, functions.php and Integrations
2625 */
2626 function nitropack_updated_option( $option, $oldValue, $value ) {
2627 $neededOptions = \NitroPack\WordPress\NitroPack::$optionsToCache;
2628 if ( ! in_array( $option, $neededOptions ) )
2629 return;
2630
2631 $np = get_nitropack();
2632 $siteConfig = $np->Config->get();
2633
2634 if ( function_exists( 'get_home_url' ) ) {
2635 $configKey = \NitroPack\WordPress\NitroPack::getConfigKey();
2636 $siteConfig[ $configKey ]['options_cache'][ $option ] = $value;
2637 $np->Config->set( $siteConfig );
2638 }
2639 }
2640
2641 function nitropack_is_late_integration_init_required() {
2642 return \NitroPack\Integration\Plugin\NginxHelper::isActive() || \NitroPack\Integration\Plugin\Cloudflare::isApoActive();
2643 }
2644
2645 function nitropack_get_notice_id( $message ) {
2646 return md5( $message );
2647 }
2648
2649 function nitropack_active_sitemap_plugins() {
2650 return
2651 NitroPack\Integration\Plugin\YoastSEO::isActive() ||
2652 NitroPack\Integration\Plugin\JetPackNP::isActive() ||
2653 NitroPack\Integration\Plugin\SquirrlySEO::isActive() ||
2654 NitroPack\Integration\Plugin\RankMathNP::isActive();
2655 }
2656
2657 function nitropack_get_site_maps() {
2658 $sitemapUrls['YoastSEO'] = NitroPack\Integration\Plugin\YoastSEO::getSitemapURL();
2659 $sitemapUrls['JetPack'] = NitroPack\Integration\Plugin\JetPackNP::getSitemapURL();
2660 $sitemapUrls['SquirrlySEO'] = NitroPack\Integration\Plugin\SquirrlySEO::getSitemapURL();
2661 $sitemapUrls['RankMath'] = NitroPack\Integration\Plugin\RankMathNP::getSitemapURL();
2662
2663 return $sitemapUrls;
2664 }
2665
2666 function get_default_sitemap() {
2667
2668 $defaultSiteMap = NitroPack\Integration\Plugin\WPCacheHelper::getSitemapURL();
2669 if ( $defaultSiteMap ) {
2670 set_sitemap_indication_msg( 'WordPress', $defaultSiteMap );
2671 return $defaultSiteMap;
2672 }
2673
2674 return false;
2675 }
2676
2677 function evaluate_warmup_sitemap( $sitemapUrls ) {
2678
2679 $sitemapProviders = array(
2680 'YoastSEO' => 'Yoast!',
2681 'SquirrlySEO' => 'Squirrly SEO',
2682 'RankMath' => 'Rank Math',
2683 'JetPack' => 'Jetpack',
2684 );
2685
2686 foreach ( $sitemapProviders as $provider => $name ) {
2687 if ( isset( $sitemapUrls[ $provider ] ) && $sitemapUrls[ $provider ] ) {
2688 set_sitemap_indication_msg( $name, $sitemapUrls[ $provider ] );
2689 return $sitemapUrls[ $provider ];
2690 }
2691 }
2692
2693 return get_default_sitemap();
2694 }
2695
2696 function set_sitemap_indication_msg( $pluginName, $sitemapURL ) {
2697 $sitemapURI = explode( "/", parse_url( $sitemapURL, PHP_URL_PATH ) );
2698 $msg = $sitemapURI[1] . ' used by ' . $pluginName;
2699 update_option( 'nitropack-warmup-sitemap', $msg );
2700 }
2701
2702 function get_date_midpoint( $endDate ) {
2703 return ( time() + strtotime( $endDate ) ) / 2;
2704 }
2705
2706
2707 function initVariationCookies( $customVariationCookies ) {
2708 $api = get_nitropack_sdk()->getApi();
2709 try {
2710 $variationCookies = $api->getVariationCookies();
2711 foreach ( $variationCookies as $cookie ) {
2712 $index = array_search( $cookie["name"], $customVariationCookies );
2713 if ( $index !== false ) {
2714 array_splice( $customVariationCookies, $index, 1 );
2715 }
2716 }
2717
2718 foreach ( $customVariationCookies as $cookieName ) {
2719 $api->setVariationCookie( $cookieName );
2720 }
2721 } catch (\Exception $e) {
2722 // what to do here? possible reason for exception is the API not responding
2723 return false;
2724 }
2725 }
2726
2727 function removeVariationCookies( $cookiesToRemove ) {
2728 $api = get_nitropack_sdk()->getApi();
2729 try {
2730 $variationCookies = $api->getVariationCookies();
2731 foreach ( $variationCookies as $cookie ) {
2732 if ( in_array( $cookie["name"], $cookiesToRemove ) ) {
2733 $api->unsetVariationCookie( $cookie["name"] );
2734 }
2735 }
2736 } catch (\Exception $e) {
2737 // what to do here? possible reason for exception is the API not responding
2738 return false;
2739 }
2740 }
2741
2742 function getNewCookie( $name ) {
2743 $cookies = getNewCookies();
2744 return ! empty( $cookies[ $name ] ) ? $cookies[ $name ] : null;
2745 }
2746
2747 /**
2748 * Returns an array of newly set cookies (not in $_COOKIE), that will be sent along with the headers of the current response.
2749 */
2750 function getNewCookies() {
2751 $cookies = [];
2752 $headers = headers_list();
2753 foreach ( $headers as $header ) {
2754 if ( strpos( $header, 'Set-Cookie: ' ) === 0 ) {
2755 $value = str_replace( '&', urlencode( '&' ), substr( $header, 12 ) );
2756 parse_str( current( explode( ';', $value ) ), $pair );
2757 $cookies = array_merge_recursive( $cookies, $pair );
2758 }
2759 }
2760
2761 return array_filter( array_map( function ( $val ) {
2762 if ( is_array( $val ) ) {
2763 $lastEl = end( $val );
2764 if ( is_array( $lastEl ) ) {
2765 return NULL;
2766 }
2767 return $lastEl;
2768 }
2769
2770 return $val;
2771 }, $cookies ) );
2772 }
2773
2774 //to be removed when the mu-file is removed
2775 function nitropack_verify_connect(string $siteId, string $siteSecret) {
2776 $nitropack_connect = new \NitroPack\WordPress\Connect();
2777 $nitropack_connect->nitropack_verify_connect($siteId, $siteSecret);
2778 }
2779 // Init integration action handlers
2780 $modHandler = NitroPack\ModuleHandler::getInstance();
2781 $modHandler->init();
2782