PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.18.6
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.18.6
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
classes 7 months ago languages 7 months ago nitropack-sdk 7 months ago view 7 months ago advanced-cache.php 1 year ago batcache-compat.php 1 year ago constants.php 7 months ago diagnostics.php 11 months ago functions.php 7 months ago helpers.php 1 year ago main.php 7 months ago readme.txt 7 months ago uninstall.php 7 months ago
functions.php
4122 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
82 nitropack_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 // Make sure it's the correct user
118 if ( intval( get_option( 'nitropack-activation-redirect', false ) ) === wp_get_current_user()->ID ) {
119 delete_option( 'nitropack-activation-redirect' );
120 wp_safe_redirect( admin_url( 'admin.php?page=nitropack' ) );
121 exit;
122 }
123 }
124 add_action( 'admin_init', 'nitropack_activation_redirect' );
125
126 function nitropack_deactivate() {
127 nitropack_set_htaccess_rules( false );
128 nitropack_set_wp_cache_const( false );
129 nitropack_uninstall_advanced_cache();
130
131 try {
132 do_action( 'nitropack_integration_purge_all' );
133 } catch (\Exception $e) {
134 // Exception while signaling our 3rd party integration addons to purge their cache
135 }
136
137 if ( get_nitropack()->isConnected() ) {
138 nitropack_event( "disable_extension" );
139 }
140
141 if ( function_exists( "opcache_reset" ) ) {
142 opcache_reset();
143 }
144 // Unscheduling events from the cron.
145 \NitroPack\WordPress\Cron::unschedule_events();
146 }
147
148 function nitropack_install_advanced_cache() {
149 $conflictingPlugins = \NitroPack\WordPress\ConflictingPlugins::getInstance();
150 $nitropack_is_conflicting_plugin_active = $conflictingPlugins->nitropack_is_conflicting_plugin_active();
151 if ( $nitropack_is_conflicting_plugin_active )
152 return false;
153 if ( ! nitropack_is_advanced_cache_allowed() )
154 return false;
155
156 $templatePath = nitropack_trailingslashit( __DIR__ ) . "advanced-cache.php";
157 if ( file_exists( $templatePath ) ) {
158 $contents = file_get_contents( $templatePath );
159 $contents = str_replace( "/*NITROPACK_FUNCTIONS_FILE*/", __FILE__, $contents );
160 $contents = str_replace( "/*NITROPACK_ABSPATH*/", ABSPATH, $contents );
161 $contents = str_replace( "/*LOGIN_COOKIES*/", defined( "LOGGED_IN_COOKIE" ) ? LOGGED_IN_COOKIE : "", $contents );
162 $contents = str_replace( "/*NP_VERSION*/", NITROPACK_VERSION, $contents );
163
164 $advancedCacheFile = nitropack_trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php';
165 if ( WP_DEBUG ) {
166 return file_put_contents( $advancedCacheFile, $contents );
167 } else {
168 return @file_put_contents( $advancedCacheFile, $contents );
169 }
170 }
171 }
172
173 function nitropack_uninstall_advanced_cache() {
174 $advancedCacheFile = nitropack_trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php';
175 if ( file_exists( $advancedCacheFile ) ) {
176 if ( WP_DEBUG ) {
177 return file_put_contents( $advancedCacheFile, "" );
178 } else {
179 return @file_put_contents( $advancedCacheFile, "" );
180 }
181 }
182 }
183
184 function nitropack_set_wp_cache_const( $status ) {
185 if ( \NitroPack\Integration\Hosting\Flywheel::detect() ) { // Flywheel: This is configured throught the FW control panel
186 return true;
187 }
188
189 if ( \NitroPack\Integration\Hosting\Pressable::detect() ) { // Pressable: We need to deal with Batcache here
190 return nitropack_set_batcache_compat( $status );
191 }
192
193 $configFilePath = nitropack_get_wpconfig_path();
194 if ( ! $configFilePath )
195 return false;
196
197 $newVal = sprintf( "define( 'WP_CACHE', %s /* Modified by NitroPack */ );\n", ( $status ? "true" : "false" ) );
198 $replacementVal = sprintf( " %s /* Modified by NitroPack */ ", ( $status ? "true" : "false" ) );
199 $lines = file( $configFilePath );
200
201 if ( empty( $lines ) )
202 return false;
203
204 $wpCacheFound = false;
205 $phpOpeningTagLine = false;
206
207 foreach ( $lines as $lineIndex => &$line ) {
208 if ( strpos( $line, "<?php" ) !== false && strpos( $line, "?>" ) === false ) {
209 $phpOpeningTagLine = $lineIndex;
210 }
211
212 if ( ! $wpCacheFound && preg_match( "/define\s*\(\s*['\"](.*?)['\"].?,(.*?)\)/", $line, $matches ) ) {
213 if ( $matches[1] == "WP_CACHE" ) {
214 $line = str_replace( $matches[2], $replacementVal, $line );
215 $wpCacheFound = true;
216 }
217 }
218
219 if ( $phpOpeningTagLine !== false && $wpCacheFound !== false )
220 break;
221 }
222
223 if ( ! $wpCacheFound ) {
224 if ( ! $status )
225 return true; // No need to modify the file at all
226
227 if ( $phpOpeningTagLine !== false ) {
228 array_splice( $lines, $phpOpeningTagLine + 1, 0, [ $newVal ] );
229 } else {
230 array_unshift( $lines, "<?php " . trim( $newVal ) . " ?>\n" );
231 }
232 }
233
234 return WP_DEBUG ? file_put_contents( $configFilePath, implode( "", $lines ) ) : @file_put_contents( $configFilePath, implode( "", $lines ) );
235 }
236
237 function nitropack_set_htaccess_rules( $status ) {
238 if ( ! apply_filters( 'nitropack_should_modify_htaccess', false ) )
239 return true;
240
241 $htaccessFilePath = nitropack_get_htaccess_path();
242 if ( ! $htaccessFilePath )
243 return false;
244
245 $htaccessBackupFilePath = $htaccessFilePath . ".nitrobackup";
246 $backupExists = WP_DEBUG ? file_exists( $htaccessBackupFilePath ) : @file_exists( $htaccessBackupFilePath );
247 if ( ! $backupExists ) {
248 $isBackupSuccess = WP_DEBUG ? copy( $htaccessFilePath, $htaccessBackupFilePath ) : @copy( $htaccessFilePath, $htaccessBackupFilePath );
249 if ( ! $isBackupSuccess )
250 return false;
251 }
252
253 $lines = file( $htaccessFilePath );
254 $linesBackup = $lines;
255
256 if ( empty( $lines ) )
257 return false; // We might want to remove this check
258
259 // Remove the old LiteSpeed rules. We need to do this because LiteSpeed's rules are not compatible with NitroPack's rules.
260 if ( $status ) {
261
262 $nitroLsOpenLine = false;
263 $nitroLsCloseLine = false;
264
265 foreach ( $lines as $lineIndex => &$line ) {
266 if ( trim( $line ) == "# BEGIN LSCACHE" ) {
267 $nitroLsOpenLine = $lineIndex;
268 }
269
270 if ( trim( $line ) == "# END LSCACHE" ) {
271 $nitroLsCloseLine = $lineIndex;
272 }
273 }
274
275 if ( $nitroLsOpenLine !== false && $nitroLsCloseLine !== false && $nitroLsCloseLine > $nitroLsOpenLine ) {
276
277 array_splice( $lines, $nitroLsOpenLine, $nitroLsCloseLine - $nitroLsOpenLine + 1 );
278 }
279 }
280
281 $nitroOpenLine = false;
282 $nitroCloseLine = false;
283
284 foreach ( $lines as $lineIndex => &$line ) {
285 if ( trim( $line ) == "# BEGIN NITROPACK" ) {
286 $nitroOpenLine = $lineIndex;
287 }
288
289 if ( trim( $line ) == "# END NITROPACK" ) {
290 $nitroCloseLine = $lineIndex;
291 }
292 }
293
294 $nitroLines = [];
295
296 if ( // We either didn't find the NitroPack markers or we found both in the correct order
297 ( $nitroOpenLine === false && $nitroCloseLine === false ) ||
298 ( $nitroOpenLine !== false && $nitroCloseLine !== false && $nitroCloseLine > $nitroOpenLine )
299 ) {
300 $nitroLines[] = "# BEGIN NITROPACK";
301 if ( $status ) {
302 $rules = apply_filters( "nitropack_htaccess_rules", [] );
303
304 if ( is_string( $rules ) ) {
305 $rules = explode( "\n", $rules );
306 }
307
308 if ( is_array( $rules ) ) {
309 $nitroLines = array_merge( $nitroLines, $rules );
310 }
311 }
312 $nitroLines[] = "# END NITROPACK";
313 $nitroLines = array_map( function ( $line ) {
314 return trim( $line ) . "\n";
315 }, $nitroLines );
316
317 // Begin .htaccess modification
318 $offset = $nitroOpenLine !== false ? $nitroOpenLine : 0;
319 $length = $nitroOpenLine !== false ? $nitroCloseLine - $nitroOpenLine + 1 : 0;
320 array_splice( $lines, $offset, $length, $nitroLines );
321 $writeResult = WP_DEBUG ? file_put_contents( $htaccessFilePath, implode( "", $lines ) ) : @file_put_contents( $htaccessFilePath, implode( "", $lines ) );
322 if ( $writeResult ) {
323 $homeUrl = NULL;
324 $siteConfig = get_nitropack()->getSiteConfig();
325
326 if ( $siteConfig && ! empty( $siteConfig["home_url"] ) ) {
327 $homeUrl = $siteConfig["home_url"];
328 } else if ( function_exists( get_home_url() ) ) {
329 $homeUrl = get_home_url();
330 }
331
332 if ( $homeUrl ) {
333 $homeUrl .= ( strpos( $homeUrl, "?" ) === false ? "?" : "&" ) . "nitroHealthcheck=1";
334 try {
335 $client = new \NitroPack\HttpClient\HttpClient( $homeUrl );
336 $client->timeout = 5;
337 $client->setHeader( "Accept", "text/html" );
338 $client->fetch();
339 if ( $client->getStatusCode() != 200 ) {
340 // Restore the initial version of the file
341 WP_DEBUG ? file_put_contents( $htaccessFilePath, implode( "", $linesBackup ) ) : @file_put_contents( $htaccessFilePath, implode( "", $linesBackup ) );
342 return false;
343 }
344 } catch (\Exception $e) {
345 return false;
346 // Unfortunately we can't be certain whether an issue appeared due to the .htaccess mods
347 // There are no known cases of this happening, so it's fairly safe to assume that all is fine
348 // There are server setups which do not allow loopback requests, which is the more likely reason to end up here
349 // However we can't be certain which one it is, so we are taking the safer approach
350 }
351 } else {
352 return false;
353 }
354 }
355 return $writeResult;
356 }
357
358 return true;
359 }
360
361 function nitropack_set_batcache_compat( $status ) {
362 $currentCompatStatus = defined( "NITROPACK_BATCACHE_COMPAT" ) && NITROPACK_BATCACHE_COMPAT;
363 if ( $currentCompatStatus === $status )
364 return true;
365
366 $configFilePath = nitropack_get_wpconfig_path();
367 if ( ! $configFilePath )
368 return false;
369
370 $batCacheFilePath = NITROPACK_PLUGIN_DIR . "batcache-compat.php";
371 $compatInclude = sprintf( "if (file_exists(\"%s\")) { require_once \"%s\"; } // NitroPack compatibility with Batcache\n", $batCacheFilePath, $batCacheFilePath );
372 $lines = file( $configFilePath );
373
374 if ( empty( $lines ) )
375 return false;
376
377 foreach ( $lines as $lineIndex => &$line ) {
378 if ( preg_match( "/nitropack.*?batcache/i", $line ) ) {
379 $line = "//REMOVE AT FILTER";
380 }
381 }
382
383 $newLines = array_filter( $lines, function ( $line ) {
384 return $line != "//REMOVE AT FILTER";
385 } );
386
387 if ( $status ) {
388 $phpOpeningTagLine = false;
389
390 unset( $line );
391 foreach ( $newLines as $lineIndex => $line ) {
392 if ( strpos( $line, "<?php" ) !== false && strpos( $line, "?>" ) === false ) {
393 $phpOpeningTagLine = $lineIndex;
394 break;
395 }
396 }
397
398 if ( $phpOpeningTagLine !== false ) {
399 array_splice( $newLines, $phpOpeningTagLine + 1, 0, [ $compatInclude ] );
400 } else {
401 array_unshift( $newLines, "<?php " . trim( $compatInclude ) . " ?>\n" );
402 }
403 }
404
405 return WP_DEBUG ? file_put_contents( $configFilePath, implode( "", $newLines ) ) : @file_put_contents( $configFilePath, implode( "", $newLines ) );
406 }
407
408 function is_valid_nitropack_webhook() {
409 return ! empty( $_GET["nitroWebhook"] ) && ! empty( $_GET["token"] ) && nitropack_validate_webhook_token( $_GET["token"] );
410 }
411
412 function is_valid_nitropack_beacon() {
413 if ( ! isset( $_POST["nitroBeaconUrl"] ) || ! isset( $_POST["nitroBeaconHash"] ) )
414 return false;
415
416 $siteConfig = nitropack_get_site_config();
417 if ( ! $siteConfig || empty( $siteConfig["siteSecret"] ) )
418 return false;
419
420
421 if ( function_exists( "hash_hmac" ) && function_exists( "hash_equals" ) ) {
422 $url = base64_decode( $_POST["nitroBeaconUrl"] );
423 $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 :(
424 $layout = ! empty( $_POST["layout"] ) ? $_POST["layout"] : "";
425 $localHash = hash_hmac( "sha512", $url . $cookiesJson . $layout, $siteConfig["siteSecret"] );
426 return hash_equals( $_POST["nitroBeaconHash"], $localHash );
427 } else {
428 return ! empty( $_POST["nitroBeaconUrl"] );
429 }
430 }
431
432 function nitropack_handle_beacon() {
433 global $np_originalRequestCookies;
434 if ( ! defined( "NITROPACK_BEACON_HANDLED" ) ) {
435 define( "NITROPACK_BEACON_HANDLED", 1 );
436 } else {
437 return;
438 }
439
440 $siteConfig = nitropack_get_site_config();
441 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) && ! empty( $_POST["nitroBeaconUrl"] ) ) {
442 $url = base64_decode( $_POST["nitroBeaconUrl"] );
443
444 if ( ! empty( $_POST["nitroBeaconCookies"] ) ) {
445 $np_originalRequestCookies = json_decode( base64_decode( $_POST["nitroBeaconCookies"] ), true );
446 }
447
448 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Beacon request received for URL: ' . $url );
449
450 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"], $url ) ) {
451 try {
452
453 $hasLocalCache = $nitro->hasLocalCache( false );
454 $needsHeartbeat = nitropack_is_heartbeat_needed();
455 $proxyPurgeOnly = ! empty( $_POST["proxyPurgeOnly"] );
456 $layout = ! empty( $_POST["layout"] ) ? $_POST["layout"] : "default";
457 $output = "";
458
459 if ( ! $proxyPurgeOnly ) {
460 if ( ! $hasLocalCache ) {
461 nitropack_header( "X-Nitro-Beacon: FORWARD" );
462 try {
463 $hasCache = $nitro->hasRemoteCache( $layout, false ); // Download the new cache file
464 $hasLocalCache = $hasCache;
465 $output = sprintf( "Cache %s", $hasCache ? "fetched" : "requested" );
466 } catch (\Exception $e) {
467 // not a critical error, do nothing
468 }
469 } else {
470 nitropack_header( "X-Nitro-Beacon: SKIP" );
471 $output = sprintf( "Cache exists already" );
472 }
473 }
474
475 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
476 nitropack_header( "X-Nitro-Proxy-Purge: true" );
477 $nitro->purgeProxyCache( $url );
478 do_action( 'nitropack_integration_purge_url', $url );
479 }
480
481 \NitroPack\ModuleHandler::onShutdown( function () use ($output) {
482 echo $output;
483 } );
484 } catch (Exception $e) {
485 // not a critical error, do nothing
486 }
487 }
488 }
489 \NitroPack\ModuleHandler::onCriticalInit( function () {
490 exit;
491 } );
492 }
493
494 /**
495 * Handle NitroPack webhooks
496 *
497 * @return void
498 */
499 /**
500 * Handles the NitroPack webhook request
501 *
502 * @return void
503 */
504 function nitropack_handle_webhook() {
505 if ( defined( 'NITROPACK_DEBUG_MODE' ) ) {
506 do_action( 'nitropack_debug_webhook', $_REQUEST );
507 }
508 if ( ! defined( "NITROPACK_WEBHOOK_HANDLED" ) ) {
509 define( "NITROPACK_WEBHOOK_HANDLED", 1 );
510 } else {
511 return;
512 }
513
514 $siteConfig = nitropack_get_site_config();
515 if ( $siteConfig && $siteConfig["webhookToken"] == $_GET["token"] ) {
516 switch ( $_GET["nitroWebhook"] ) {
517 case "config":
518 nitropack_fetch_config();
519 get_nitropack()->resetSdkInstances(); // This is needed in order to obtain a new SDK instance with the fresh config
520 nitropack_set_htaccess_rules( true );
521 if ( null !== $nitro = get_nitropack_sdk() ) {
522 $nitro->purgeProxyCache();
523 }
524 do_action( 'nitropack_integration_purge_all' );
525 break;
526 case "cache_ready":
527 if ( isset( $_POST['url'] ) ) {
528 $urls = array( $_POST['url'] );
529 } elseif ( isset( $_POST['urls'] ) ) {
530 $urls = $_POST['urls'];
531 } else {
532 $urls = array();
533 }
534 if ( ! empty( $urls ) ) {
535 $readyUrls = [];
536 foreach ( $urls as $url ) {
537 $readyUrl = nitropack_sanitize_url_input( $url );
538 if ( $readyUrl ) {
539 $readyUrls[] = $readyUrl;
540 }
541 }
542
543 if ( $readyUrls && null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"], $readyUrls[0] ) ) {
544 $hasCache = $nitro->hasRemoteCacheMulti( $readyUrls, "default", false ); // Download the new cache file
545 foreach ( $readyUrls as $readyUrl ) {
546 $nitro->purgeProxyCache( $readyUrl );
547 do_action( 'nitropack_integration_purge_url', $readyUrl );
548 }
549 }
550 }
551 break;
552 case "cache_clear":
553 if ( isset( $_POST['url'] ) ) {
554 $urls = array( $_POST['url'] );
555 } elseif ( isset( $_POST['urls'] ) ) {
556 $urls = $_POST['urls'];
557 }
558
559 $proxyPurgeOnly = ! empty( $_POST["proxyPurgeOnly"] );
560 $doAction = ! empty( $_POST['useInvalidate'] )
561 ? static function ( $url = null ) {
562 nitropack_sdk_invalidate_local( $url );
563 }
564 : static function ( $url = null ) {
565 nitropack_sdk_purge_local( $url );
566 };
567
568 if ( ! empty( $_POST["url"] ) ) {
569 $urls = is_array( $_POST["url"] ) ? $_POST["url"] : array( $_POST["url"] );
570 foreach ( $urls as $url ) {
571 $sanitizedUrl = nitropack_sanitize_url_input( $url );
572 if ( $proxyPurgeOnly ) {
573 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
574 $nitro->purgeProxyCache( $sanitizedUrl );
575 }
576 do_action( 'nitropack_integration_purge_url', $sanitizedUrl );
577 } else {
578 $doAction( $sanitizedUrl );
579 }
580 }
581 } else {
582 if ( $proxyPurgeOnly ) {
583 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
584 $nitro->purgeProxyCache();
585 }
586 do_action( 'nitropack_integration_purge_all' );
587 } else {
588 $doAction();
589 nitropack_sdk_delete_backlog();
590 }
591 }
592 break;
593 }
594 }
595 \NitroPack\ModuleHandler::onCriticalInit( function () {
596 nitropack_json_and_exit( array(
597 "type" => "success",
598 ) );
599 } );
600 }
601
602 function nitropack_sanitize_url_input( $url ) {
603 $result = NULL;
604 if ( ! function_exists( "esc_url" ) ) {
605 $sanitizedUrl = filter_var( $url, FILTER_SANITIZE_URL );
606 if ( $sanitizedUrl !== false && filter_var( $sanitizedUrl, FILTER_VALIDATE_URL ) !== false ) {
607 $result = $sanitizedUrl;
608 }
609 } else if ( $validatedUrl = esc_url( $url, array( "http", "https" ), "notdisplay" ) ) {
610 $result = $validatedUrl;
611 }
612
613 return $result;
614 }
615
616 function nitropack_is_amp_page() {
617 return ( function_exists( 'amp_is_request' ) && amp_is_request() && ! get_nitropack()->setDisabledReason( "amp page" ) ) ||
618 ( function_exists( 'ampforwp_is_amp_endpoint' ) && ampforwp_is_amp_endpoint() && ! get_nitropack()->setDisabledReason( "amp page" ) );
619 }
620
621 function nitropack_passes_page_requirements( $detectIfNoCachedResult = true ) {
622 static $cachedResult = NULL;
623 $reduceCheckoutChecks = defined( "NITROPACK_REDUCE_CHECKOUT_CHECKS" ) && NITROPACK_REDUCE_CHECKOUT_CHECKS;
624 $reduceCartChecks = defined( "NITROPACK_REDUCE_CART_CHECKS" ) && NITROPACK_REDUCE_CART_CHECKS;
625
626 if ( $cachedResult === NULL && $detectIfNoCachedResult ) {
627
628 $cachedResult = ! (
629 ( is_404() && ! get_nitropack()->setDisabledReason( "404" ) ) ||
630 ( is_preview() && ! get_nitropack()->setDisabledReason( "preview page" ) ) ||
631 ( is_feed() && ! get_nitropack()->setDisabledReason( "feed" ) ) ||
632 ( is_comment_feed() && ! get_nitropack()->setDisabledReason( "comment feed" ) ) ||
633 ( is_trackback() && ! get_nitropack()->setDisabledReason( "trackback" ) ) ||
634 ( nitropack_is_logged_in() && ! get_nitropack()->setDisabledReason( "logged in" ) ) ||
635 ( is_search() && ! get_nitropack()->setDisabledReason( "search" ) ) ||
636 ( nitropack_is_ajax() && ! get_nitropack()->setDisabledReason( "ajax" ) ) ||
637 ( nitropack_is_post() && ! get_nitropack()->setDisabledReason( "post request" ) ) ||
638 ( nitropack_is_xmlrpc() && ! get_nitropack()->setDisabledReason( "xmlrpc" ) ) ||
639 ( nitropack_is_robots() && ! get_nitropack()->setDisabledReason( "robots" ) ) ||
640 nitropack_is_amp_page() ||
641 ! nitropack_is_allowed_request() ||
642 ( nitropack_is_wp_cron() && ! get_nitropack()->setDisabledReason( "doing cron" ) ) || // CRON request
643 ( nitropack_is_wp_cli() ) || // CLI request
644 ( defined( 'WC_PLUGIN_FILE' ) && ( is_page( 'cart' ) || ( ! $reduceCartChecks && is_cart() ) ) && ! get_nitropack()->setDisabledReason( "cart page" ) ) || // WooCommerce
645 ( defined( 'WC_PLUGIN_FILE' ) && ( is_page( 'checkout' ) || ( ! $reduceCheckoutChecks && is_checkout() ) ) && ! get_nitropack()->setDisabledReason( "checkout page" ) ) || // WooCommerce
646 ( defined( 'WC_PLUGIN_FILE' ) && is_account_page() && ! get_nitropack()->setDisabledReason( "account page" ) ) // WooCommerce
647 );
648 }
649
650 return $cachedResult;
651 }
652
653 function nitropack_is_home() {
654 if ( 'posts' == get_option( 'show_on_front' ) ) {
655 return is_front_page() || is_home();
656 } else {
657 return is_front_page();
658 }
659 }
660
661 function nitropack_is_blogindex() {
662 return is_home();
663 }
664
665 function nitropack_is_archive() {
666 return apply_filters( "nitropack_is_archive_page", is_author() || is_archive() );
667 }
668
669 function nitropack_is_allowed_request() {
670 global $np_queriedObj;
671 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
672 if ( is_array( $cacheableObjectTypes ) ) {
673 if ( nitropack_is_home() ) {
674 if ( ! in_array( 'home', $cacheableObjectTypes ) ) {
675 get_nitropack()->setDisabledReason( "page type not allowed (home)" );
676 return false;
677 }
678 } else {
679 if ( is_tax() || is_category() || is_tag() ) {
680 $np_queriedObj = get_queried_object();
681 if ( ! empty( $np_queriedObj ) && ! in_array( $np_queriedObj->taxonomy, $cacheableObjectTypes ) ) {
682 get_nitropack()->setDisabledReason( "page type not allowed ({$np_queriedObj->taxonomy})" );
683 return false;
684 }
685 } else {
686 if ( nitropack_is_archive() ) {
687 if ( ! in_array( 'archive', $cacheableObjectTypes ) ) {
688 get_nitropack()->setDisabledReason( "page type not allowed (archive)" );
689 return false;
690 }
691 } else {
692 $postType = get_post_type();
693 if ( ! empty( $postType ) && ! in_array( $postType, $cacheableObjectTypes ) ) {
694 get_nitropack()->setDisabledReason( "page type not allowed ($postType)" );
695 return false;
696 }
697 }
698 }
699 }
700 }
701
702 //add test mode as disabled reason but not when the testnitro parameter is set
703 if ( empty( $_GET['testnitro'] ) && TestMode::getInstance()->is_test_mode_enabled() ) {
704 get_nitropack()->setDisabledReason( "Test Mode" );
705 return false;
706 }
707
708 if ( null !== $nitro = get_nitropack_sdk() ) {
709 return ( $nitro->isAllowedUrl( $nitro->getUrl() ) || get_nitropack()->setDisabledReason( "url not allowed" ) ) &&
710 ( $nitro->isAllowedRequest( true ) || get_nitropack()->setDisabledReason( "request type not allowed" ) );
711 }
712
713 get_nitropack()->setDisabledReason( "site not connected" );
714 return false;
715 }
716
717 function nitropack_is_ajax() {
718 return ( function_exists( "wp_doing_ajax" ) && wp_doing_ajax() ) ||
719 ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ||
720 ( ! empty( $_SERVER["HTTP_X_REQUESTED_WITH"] ) && $_SERVER["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" ) ||
721 ( ! empty( $_SERVER["REQUEST_URI"] ) && basename( $_SERVER["REQUEST_URI"] ) == "admin-ajax.php" ) ||
722 ! empty( $_GET["wc-ajax"] );
723 }
724
725 /**
726 * Checking if the current request is wp-cli request
727 *
728 * @return bool
729 */
730 function nitropack_is_wp_cli() {
731 return NitroPack\WordPress\NitroPack::isWpCli();
732 }
733
734 function nitropack_is_wp_cron() {
735 return defined( 'DOING_CRON' ) && DOING_CRON;
736 }
737
738 function nitropack_is_rest() {
739 // Source: https://wordpress.stackexchange.com/a/317041
740 $prefix = rest_get_url_prefix();
741 if (
742 defined( 'REST_REQUEST' ) && REST_REQUEST // (#1)
743 || isset( $_GET['rest_route'] ) // (#2)
744 && strpos( trim( $_GET['rest_route'], '\\/' ), $prefix, 0 ) === 0
745 )
746 return true;
747 // (#3)
748 global $wp_rewrite;
749 if ( $wp_rewrite === null )
750 $wp_rewrite = new WP_Rewrite();
751
752 // (#4)
753 $rest_url = wp_parse_url( trailingslashit( rest_url() ) );
754 $current_url = wp_parse_url( add_query_arg( array() ) );
755 return strpos( $current_url['path'], $rest_url['path'], 0 ) === 0;
756 }
757
758 function nitropack_is_post() {
759 return ( ! empty( $_SERVER['REQUEST_METHOD'] ) && $_SERVER['REQUEST_METHOD'] === 'POST' ) || ( empty( $_SERVER['REQUEST_METHOD'] ) && ! empty( $_POST ) );
760 }
761
762 function nitropack_is_xmlrpc() {
763 return defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST;
764 }
765
766 function nitropack_is_robots() {
767 return is_robots() || ( ! empty( $_SERVER["REQUEST_URI"] ) && basename( parse_url( $_SERVER["REQUEST_URI"], PHP_URL_PATH ) ) === "robots.txt" );
768 }
769
770 // 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
771 function nitropack_is_admin() {
772 if ( ( nitropack_is_ajax() || nitropack_is_rest() ) && ! empty( $_SERVER["HTTP_REFERER"] ) ) {
773 $adminUrl = NULL;
774 $siteConfig = nitropack_get_site_config();
775 if ( $siteConfig && ! empty( $siteConfig["admin_url"] ) ) {
776 $adminUrl = $siteConfig["admin_url"];
777 } else if ( function_exists( "admin_url" ) ) {
778 $adminUrl = admin_url();
779 } else {
780 return is_admin();
781 }
782
783 return strpos( $_SERVER["HTTP_REFERER"], $adminUrl ) === 0;
784 } else {
785 return is_admin();
786 }
787 }
788
789 function nitropack_is_warmup_request() {
790 return ! empty( $_SERVER["HTTP_X_NITRO_WARMUP"] );
791 }
792
793 function nitropack_is_lighthouse_request() {
794 return ! empty( $_SERVER["HTTP_USER_AGENT"] ) && stripos( $_SERVER["HTTP_USER_AGENT"], "lighthouse" ) !== false;
795 }
796
797 function nitropack_is_gtmetrix_request() {
798 return ! empty( $_SERVER["HTTP_USER_AGENT"] ) && stripos( $_SERVER["HTTP_USER_AGENT"], "gtmetrix" ) !== false;
799 }
800
801 function nitropack_is_pingdom_request() {
802 return ! empty( $_SERVER["HTTP_USER_AGENT"] ) && stripos( $_SERVER["HTTP_USER_AGENT"], "pingdom" ) !== false;
803 }
804
805 function nitropack_is_optimizer_request() {
806 return isset( $_SERVER["HTTP_X_NITROPACK_REQUEST"] );
807 }
808
809 function nitropack_init() {
810 global $np_queriedObj;
811 nitropack_header( 'X-Nitro-Cache: MISS' );
812 $GLOBALS["NitroPack.tags"] = array();
813
814 if ( is_valid_nitropack_webhook() ) {
815 nitropack_handle_webhook();
816 } else {
817 if ( is_valid_nitropack_beacon() ) {
818 nitropack_handle_beacon();
819 } else {
820 /* The following if statement should stay as it is written.
821 * is_archive() can return true if visiting a tax, category or tag page, so is_acrchive must be checked last
822 */
823 if ( is_tax() || is_category() || is_tag() ) {
824 $np_queriedObj = get_queried_object();
825 get_nitropack()->setPageType( $np_queriedObj->taxonomy );
826 } else {
827 $layout = nitropack_get_layout();
828 get_nitropack()->setPageType( $layout );
829 }
830
831 add_action( 'wp_footer', 'nitropack_print_element_override', 9999999 );
832 if ( ! isset( $_GET["wpf_action"] ) && nitropack_passes_cookie_requirements() && nitropack_passes_page_requirements() ) {
833 add_action( 'wp_footer', 'nitropack_print_beacon_script' );
834 add_action( 'get_footer', 'nitropack_print_beacon_script' );
835
836 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.
837 if ( defined( 'FUSION_BUILDER_VERSION' ) ) {
838 add_filter( 'do_shortcode_tag', 'nitropack_handle_fusion_builder_conatainer_expiration', 10, 3 );
839 add_action( 'wp_footer', 'nitropack_set_custom_expiration' );
840 } else {
841 nitropack_set_custom_expiration();
842 }
843
844 $GLOBALS["NitroPack.tags"][ "pageType:" . get_nitropack()->getPageType()] = 1;
845
846 /* The following if statement should stay as it is written.
847 * is_archive() can return true if visiting a tax, category or tag page, so is_acrchive must be checked last
848 */
849 if ( is_tax() || is_category() || is_tag() ) {
850 $np_queriedObj = get_queried_object();
851 $GLOBALS["NitroPack.tags"][ "tax:" . $np_queriedObj->term_taxonomy_id ] = 1;
852 } else {
853 if ( is_single() || is_page() || is_attachment() ) {
854 $singlePost = get_post();
855 if ( $singlePost ) {
856 $GLOBALS["NitroPack.tags"][ "single:" . $singlePost->ID ] = 1;
857 }
858 }
859 }
860
861 // Uncomment the code below in case object cache interferes with correct URL taggig
862 // The code below will attempt to temporarily disable using the object cache only for the requests coming from NitroPack
863 //wp_using_ext_object_cache(false);
864 //add_action("pre_get_posts", function($query) {
865 // $query->query_vars["cache_results"] = false;
866 //});
867 //
868 //add_filter("all", function() {
869 // $args = func_get_args();
870 // if (count($args) > 1) {
871 // list($filterName, $value) = func_get_args();
872 // if (preg_match("/^transient_(.*)/", $filterName, $matches) && $value) {
873 // return false;
874 // }
875 // }
876 //}, 10, 2);
877
878 add_filter( 'post_link', 'nitropack_post_link_listener', 10, 3 );
879 add_action( 'the_post', 'nitropack_handle_the_post' );
880 add_action( 'wp_footer', 'nitropack_log_tags' );
881 }
882 } else {
883 nitropack_header( "X-Nitro-Disabled: 1" );
884 if ( ( null !== $nitro = get_nitropack_sdk() ) && ! $nitro->isAllowedBrowser() ) { // This clears any proxy cache when a proxy cached non-optimized request due to unsupported browser
885 add_action( 'wp_footer', 'nitropack_print_beacon_script' );
886 add_action( 'get_footer', 'nitropack_print_beacon_script' );
887 }
888 }
889
890 if ( ! nitropack_is_optimizer_request() ) {
891 add_action( 'wp_head', 'nitropack_print_generic_nitro_script' );
892 }
893 }
894 }
895 }
896
897 function nitropack_handle_fusion_builder_conatainer_expiration( $output, $tag, $attr ) {
898 global $np_customExpirationTimes;
899 if ( $tag == "fusion_builder_container" ) {
900 if ( ! empty( $attr["publish_date"] ) && ! empty( $attr["status"] ) && in_array( $attr["status"], array( "published_until", "publish_after" ) ) ) {
901 $timezone = get_option( 'timezone_string' );
902 $offset = get_option( 'gmt_offset' );
903 $dt = new DateTime( $attr["publish_date"] );
904 if ( $timezone ) {
905 $timeZone = new DateTimeZone( $timezone );
906 $timeZoneOffset = $timeZone->getOffset( $dt );
907 } else if ( $offset ) {
908 $timeZoneOffset = (int) $offset * 3600;
909 }
910 $time = $dt->getTimestamp() - $timeZoneOffset;
911 if ( $time > time() ) { // We only need to look at future dates
912 $np_customExpirationTimes[] = $time;
913 }
914 }
915 }
916 return $output;
917 }
918 function nitropack_set_custom_expiration() {
919
920 //check which CPTs are marked for optimization
921 $get_optimized_CPTs = nitropack_get_optimized_CPTs();
922 if ( empty( $get_optimized_CPTs ) )
923 return;
924
925 global $np_customExpirationTimes, $wpdb;
926
927 $placeholders = implode( ',', array_fill( 0, count( $get_optimized_CPTs ), '%s' ) );
928 $currentDate = date( "Y-m-d H:i:s" );
929
930 //For better security, we use prepared statements
931 $unmodifiedPosts_query = $wpdb->prepare(
932 "SELECT ID, post_date
933 FROM {$wpdb->prefix}posts
934 WHERE {$wpdb->prefix}posts.post_date > %s
935 AND {$wpdb->prefix}posts.post_type IN ($placeholders)
936 AND ({$wpdb->prefix}posts.post_status = 'future')
937 ORDER BY {$wpdb->prefix}posts.post_date ASC
938 LIMIT 0, 1",
939 array_merge( [ $currentDate ], $get_optimized_CPTs )
940 );
941 $unmodifiedPosts = $wpdb->get_results( $unmodifiedPosts_query );
942
943 if ( ! empty( $unmodifiedPosts ) && strtotime( $unmodifiedPosts[0]->post_date ) > time() ) {
944 $scheduled_post = get_post( $unmodifiedPosts[0]->ID );
945
946 // We will check relatedness only if a proper option is set in wp-config.php
947 $check_relatedness = defined( "NITROPACK_SCHEDULED_POST_EXPIRATION_CHECK_RELATEDNESS" ) && NITROPACK_SCHEDULED_POST_EXPIRATION_CHECK_RELATEDNESS;
948
949 // 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
950 if ( ! $check_relatedness || nitropack_is_page_related_to_scheduled_post( $scheduled_post ) ) {
951 $np_customExpirationTimes[] = strtotime( $unmodifiedPosts[0]->post_date );
952 }
953 }
954
955 if ( ! empty( $np_customExpirationTimes ) ) {
956 sort( $np_customExpirationTimes, SORT_NUMERIC );
957 nitropack_header( "X-Nitro-Expires: " . $np_customExpirationTimes[0] );
958 }
959 }
960
961 // Determine if the current page is related to the scheduled post
962 // This is a best-effort approach and may not cover all cases
963 function nitropack_is_page_related_to_scheduled_post( $scheduled_post ) {
964 $current_layout = nitropack_get_layout();
965 $postType = $scheduled_post->post_type;
966 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
967
968 // Only proceed if post type is cacheable
969 if ( ! in_array( $postType, $cacheableObjectTypes ) ) {
970 return false;
971 }
972
973 // Check if current home page would be invalidated
974 if ( $current_layout === 'home' ) {
975 return true;
976 }
977
978 // Check if current blog index page would be invalidated
979 if ( $postType === 'post' && $current_layout === 'blogindex' ) {
980 return true;
981 }
982
983 if ( is_post_type_archive($postType) ) {
984 return true;
985 }
986
987 // Check if current single post/page would be invalidated
988 if (is_singular($postType)) {
989 return true;
990 }
991
992 // Default to false for other page types
993 return false;
994 }
995
996 function nitropack_print_beacon_script() {
997 if ( defined( "NITROPACK_BEACON_PRINTED" ) || ! nitropack_passes_page_requirements() )
998 return;
999 define( "NITROPACK_BEACON_PRINTED", true );
1000 echo apply_filters( "nitro_script_output", nitropack_get_beacon_script() );
1001 }
1002
1003 function nitropack_get_beacon_script() {
1004 $siteConfig = nitropack_get_site_config();
1005 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) ) {
1006 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
1007 $url = $nitro->getUrl();
1008 $cookiesJson = json_encode( $nitro->supportedCookiesFilter( NitroPack\SDK\NitroPack::getCookies() ) );
1009 $layout = nitropack_get_layout();
1010
1011 if ( function_exists( "hash_hmac" ) && function_exists( "hash_equals" ) ) {
1012 $hash = hash_hmac( "sha512", $url . $cookiesJson . $layout, $siteConfig["siteSecret"] );
1013 } else {
1014 $hash = "";
1015 }
1016 $url = base64_encode( $url ); // We want only ASCII
1017 $cookiesb64 = base64_encode( $cookiesJson );
1018 $proxyPurgeOnly = ! $nitro->isAllowedBrowser();
1019
1020 return "
1021 <script nitro-exclude>
1022 if (!window.NITROPACK_STATE || window.NITROPACK_STATE != 'FRESH') {
1023 var proxyPurgeOnly = " . ( $proxyPurgeOnly ? 1 : 0 ) . ";
1024 if (typeof navigator.sendBeacon !== 'undefined') {
1025 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);
1026 } else {
1027 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}');
1028 }
1029 }
1030 </script>";
1031 }
1032 }
1033 }
1034
1035 function nitropack_print_cookie_handler_script() {
1036
1037 if ( defined( "NITROPACK_COOKIE_HANDLER_PRINTED" ) )
1038 return;
1039 define( "NITROPACK_COOKIE_HANDLER_PRINTED", true );
1040
1041 echo apply_filters( "nitro_script_output", nitropack_get_cookie_handler_script() );
1042 }
1043
1044 function nitropack_get_cookie_handler_script() {
1045 return "
1046 <script nitro-exclude>
1047 document.cookie = 'nitroCachedPage=' + (!window.NITROPACK_STATE ? '0' : '1') + '; path=/; SameSite=Lax';
1048 </script>";
1049 }
1050
1051 function nitropack_print_generic_nitro_script() {
1052 if ( defined( "NITROPACK_GENERIC_NITRO_SCRIPT_PRINTED" ) )
1053 return;
1054 define( "NITROPACK_GENERIC_NITRO_SCRIPT_PRINTED", true );
1055 echo apply_filters( "nitro_script_output", nitropack_get_telemetry_meta() );
1056 echo apply_filters( "nitro_script_output", nitropack_get_generic_nitro_script() );
1057 }
1058
1059 function nitropack_get_generic_nitro_script() {
1060 $siteConfig = nitropack_get_site_config();
1061 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) ) {
1062 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
1063 $config = $nitro->getConfig();
1064 if ( ! empty( $config->GenericNitroScript->Script ) ) {
1065 return "<script id='nitro-generic' nitro-exclude>" . $config->GenericNitroScript->Script . "</script>";
1066 }
1067 }
1068 }
1069
1070 return "";
1071 }
1072
1073 function nitropack_get_telemetry_meta() {
1074 $disabledReason = get_nitropack()->getDisabledReason();
1075 $missReason = $disabledReason !== NULL ? $disabledReason : "cache not found";
1076 $pageType = get_nitropack()->getPageType();
1077 $isEligibleForOptimization = nitropack_passes_page_requirements();
1078 $metaObj = "window.NPTelemetryMetadata={";
1079
1080 if ( $missReason ) {
1081 $metaObj .= "missReason: (!window.NITROPACK_STATE ? '$missReason' : 'hit'),";
1082 }
1083
1084 if ( $pageType ) {
1085 $metaObj .= "pageType: '$pageType',";
1086 }
1087
1088 $metaObj .= "isEligibleForOptimization: " . ( $isEligibleForOptimization ? "true" : "false" ) . ",";
1089
1090 $metaObj .= "}";
1091
1092 return "<script id='nitro-telemetry-meta' nitro-exclude>$metaObj</script>";
1093 }
1094
1095 function nitropack_print_element_override() {
1096 if ( defined( "NITROPACK_ELEMENT_OVERRIDE_PRINTED" ) )
1097 return;
1098 define( "NITROPACK_ELEMENT_OVERRIDE_PRINTED", true );
1099 echo apply_filters( "nitro_script_output", nitropack_get_element_override_script() );
1100 }
1101
1102 function nitropack_get_element_override_script() {
1103 $nitro = get_nitropack_sdk();
1104 return $nitro !== NULL ? $nitro->getStatefulCacheHandlerScript() : "";
1105 }
1106
1107 function nitropack_has_advanced_cache() {
1108 return defined( 'NITROPACK_ADVANCED_CACHE' );
1109 }
1110
1111 function nitropack_validate_site_id( $siteId ) {
1112 return preg_match( "/^([a-zA-Z]{32})$/", trim( $siteId ) );
1113 }
1114
1115 function nitropack_validate_site_secret( $siteSecret ) {
1116 return preg_match( "/^([a-zA-Z0-9]{64})$/", trim( $siteSecret ) );
1117 }
1118
1119 function nitropack_validate_webhook_token( $token ) {
1120 return preg_match( "/^([abcdef0-9]{32})$/", strtolower( $token ) );
1121 }
1122
1123 function nitropack_validate_wc_currency( $cookieValue ) {
1124 return preg_match( "/^([a-z]{3})$/", strtolower( $cookieValue ) );
1125 }
1126
1127 function nitropack_validate_wc_currency_language( $cookieValue ) {
1128 return preg_match( "/^([a-z_\\-]{2,})$/", strtolower( $cookieValue ) );
1129 }
1130
1131 function nitropack_get_default_cacheable_object_types() {
1132 $result = array( "home", "archive" );
1133 $postTypes = get_post_types( array( 'public' => true ), 'names' );
1134 $result = array_merge( $result, $postTypes );
1135 foreach ( $postTypes as $postType ) {
1136 $result = array_merge( $result, get_taxonomies( array( 'object_type' => array( $postType ), 'public' => true ), 'names' ) );
1137 }
1138 return $result;
1139 }
1140
1141 function nitropack_get_object_types() {
1142 $objectTypes = get_post_types( array( 'public' => true ), 'objects' );
1143 $taxonomies = get_taxonomies( array( 'public' => true ), 'objects' );
1144
1145 foreach ( $objectTypes as &$objectType ) {
1146 $objectType->taxonomies = [];
1147 foreach ( $taxonomies as $tax ) {
1148 if ( in_array( $objectType->name, $tax->object_type ) ) {
1149 $objectType->taxonomies[] = $tax;
1150 }
1151 }
1152 }
1153
1154 return $objectTypes;
1155 }
1156
1157 /**
1158 * Retrievs all CPTs eligable for optimization and checking if they are optimized
1159 */
1160 function nitropack_get_CPTs_with_optimization_status() {
1161
1162 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
1163 $objectTypes = nitropack_get_object_types();
1164
1165 $result = [
1166 "home" => [
1167 'name' => 'Home',
1168 'isOptimized' => in_array( 'home', $cacheableObjectTypes ) ? 1 : 0,
1169 ],
1170 "archive" => [
1171 'name' => 'Archive',
1172 'isOptimized' => in_array( 'archive', $cacheableObjectTypes ) ? 1 : 0,
1173 ]
1174 ];
1175
1176 // Determine new object types by comparing current with stored
1177 foreach ( $objectTypes as $slug => $objectType ) {
1178 $isOptimized = in_array( $objectType->name, $cacheableObjectTypes );
1179 $taxonomies = [];
1180
1181 if ( ! empty( $objectType->taxonomies ) ) {
1182 foreach ( $objectType->taxonomies as $tax ) {
1183 $taxName = $tax->name;
1184 $taxonomies[ $taxName ] = [
1185 'isOptimized' => in_array( $taxName, $cacheableObjectTypes ) ? 1 : 0,
1186 'name' => $tax->labels->name
1187 ];
1188 }
1189 }
1190
1191 $result[ $slug ] = [
1192 'isOptimized' => $isOptimized ? 1 : 0,
1193 'name' => $objectType->labels->name,
1194 'taxonomies' => $taxonomies
1195 ];
1196 }
1197
1198 return $result;
1199 }
1200 /**
1201 * Filters the CPTs which are not optimized.
1202 * Show it only once.
1203 */
1204 function nitropack_filter_non_optimized() {
1205 $filteredArr = [];
1206 $objectTypes = nitropack_get_CPTs_with_optimization_status();
1207 foreach ( $objectTypes as $slug => $objectType ) {
1208 $includeObjectType = ! $objectType['isOptimized'];
1209 $filteredTaxonomies = [];
1210 if ( isset( $objectType['taxonomies'] ) ) {
1211 foreach ( $objectType['taxonomies'] as $taxSlug => $taxonomy ) {
1212 if ( ! $taxonomy['isOptimized'] ) {
1213 $filteredTaxonomies[ $taxSlug ] = $taxonomy;
1214 $includeObjectType = true; // Include CPT if it has any non-optimized taxonomy
1215 }
1216 }
1217 }
1218 if ( $includeObjectType ) {
1219 $filteredArr[ $slug ] = [
1220 'isOptimized' => $objectType['isOptimized'],
1221 'name' => $objectType['name'],
1222 'taxonomies' => $filteredTaxonomies
1223 ];
1224 }
1225 }
1226 return $filteredArr;
1227 }
1228 /**
1229 * Retrieve the list of optimized Custom Post Types (CPTs).
1230 *
1231 * This function fetches the CPTs with their optimization status and returns an array of CPT keys
1232 * that are marked as optimized. It excludes 'home' and 'archive' as they are not valid CPTs.
1233 *
1234 * @return array An array of optimized CPT keys.
1235 */
1236 function nitropack_get_optimized_CPTs() {
1237 $get_CPTs_with_optimization_status = nitropack_get_CPTs_with_optimization_status();
1238
1239 $optimizedKeys = [];
1240
1241 foreach ( $get_CPTs_with_optimization_status as $key => $value ) {
1242
1243 if ( $key === 'home' || $key === 'archive' )
1244 continue; //not valid CPTs
1245
1246 if ( isset( $value['isOptimized'] ) && $value['isOptimized'] === 1 ) {
1247 $optimizedKeys[] = $key;
1248 }
1249 }
1250
1251 return $optimizedKeys;
1252 }
1253
1254 function nitropack_autooptimize_new_post_types_and_taxonomies() {
1255 //start optimizing after the notice is shown
1256 $notices = get_option( 'nitropack-dismissed-notices', [] );
1257 if ( ! $notices || ! in_array( 'OptimizeCPT', $notices ) )
1258 return;
1259 //check if the non-optimized CPTs are stored, if not store them
1260 $nonCacheableObjectTypes = get_option( 'nitropack-nonCacheableObjectTypes' );
1261 if ( ! $nonCacheableObjectTypes ) {
1262 $notOptimizedCPTs = nitropack_filter_non_optimized();
1263 $nonCacheableObjectTypes = [];
1264 foreach ( $notOptimizedCPTs as $slug => $objectType ) {
1265 if ( ! $objectType['isOptimized'] ) {
1266 $nonCacheableObjectTypes[] = $slug;
1267 }
1268 foreach ( $objectType['taxonomies'] as $taxSlug => $taxonomy ) {
1269 if ( ! $taxonomy['isOptimized'] ) {
1270 $nonCacheableObjectTypes[] = $taxSlug;
1271 }
1272 }
1273 }
1274 update_option( 'nitropack-nonCacheableObjectTypes', $nonCacheableObjectTypes );
1275 }
1276
1277 $postTypes = get_post_types( array( 'public' => true ), 'objects' );
1278 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
1279 foreach ( $postTypes as $slug => $postType ) {
1280 if ( $postType->public ) {
1281 // Check and add post type to cacheable object types
1282 if ( ! in_array( $slug, $nonCacheableObjectTypes ) && ! in_array( $slug, $cacheableObjectTypes ) ) {
1283 $cacheableObjectTypes[] = $slug;
1284 }
1285
1286 // Fetch and add connected taxonomies
1287 $taxonomies = get_object_taxonomies( $slug, 'names' );
1288 foreach ( $taxonomies as $taxonomy ) {
1289 if ( ! in_array( $taxonomy, $nonCacheableObjectTypes ) && ! in_array( $taxonomy, $cacheableObjectTypes ) ) {
1290 $cacheableObjectTypes[] = $taxonomy;
1291 }
1292 }
1293 }
1294 }
1295
1296 update_option( 'nitropack-cacheableObjectTypes', $cacheableObjectTypes );
1297 }
1298
1299
1300
1301
1302 function nitropack_get_cacheable_object_types() {
1303 return apply_filters( "nitropack_cacheable_post_types", get_option( "nitropack-cacheableObjectTypes", nitropack_get_default_cacheable_object_types() ) );
1304 }
1305
1306 /** Step 3. */
1307 function nitropack_options() {
1308 if ( ! current_user_can( 'manage_options' ) ) {
1309 wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
1310 }
1311
1312 wp_enqueue_script( 'jquery-form' );
1313
1314 // Manually add home and archive page object
1315 $homeCustomObject = new stdClass();
1316 $homeCustomObject->name = 'home';
1317 $homeCustomObject->label = 'Home';
1318 $homeCustomObject->taxonomies = array();
1319
1320 $archiveCustomObject = new stdClass();
1321 $archiveCustomObject->name = 'archive';
1322 $archiveCustomObject->label = 'Archive';
1323 $archiveCustomObject->taxonomies = array();
1324 $objectTypes = array_merge( array( 'home' => $homeCustomObject, 'archive' => $archiveCustomObject ), nitropack_get_object_types() );
1325 $enableCompression = get_option( 'nitropack-enableCompression' );
1326 $canEditorClearCache = get_option( 'nitropack-canEditorClearCache' );
1327 $autoCachePurge = get_option( 'nitropack-autoCachePurge', 1 );
1328 $bbCacheSyncPurge = get_option( 'nitropack-bbCacheSyncPurge', 0 );
1329 $legacyPurge = get_option( 'nitropack-legacyPurge', 0 );
1330 $checkedCompression = get_option( 'nitropack-checkedCompression' );
1331 $stockReduceStatus = get_option( 'nitropack-stockReduceStatus' );
1332 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
1333
1334 if ( get_nitropack()->isConnected() ) {
1335 $planDetailsUrl = get_nitropack_integration_url( "plan_details_json" );
1336 $optimizationDetailsUrl = get_nitropack_integration_url( "optimization_details_json" );
1337 $quickSetupUrl = get_nitropack_integration_url( "quicksetup_json" );
1338 $quickSetupSaveUrl = get_nitropack_integration_url( "quicksetup" );
1339 $helpLabels = [ 'wordpress_plugin_help' ];
1340
1341 if ( get_nitropack()->getDistribution() == "oneclick" ) {
1342 $helpLabels = [ 'wordpress_plugin_help_oneclick' ];
1343 $oneClickVendorWidget = apply_filters( "nitropack_oneclick_vendor_widget", "" );
1344 include plugin_dir_path( __FILE__ ) . nitropack_trailingslashit( 'view' ) . 'oneclick.php';
1345 } else {
1346 include plugin_dir_path( __FILE__ ) . nitropack_trailingslashit( 'view' ) . 'admin.php';
1347 }
1348
1349 } else {
1350 if ( get_nitropack()->getDistribution() == "oneclick" ) {
1351 $oneClickConnectUrl = apply_filters( "nitropack_oneclick_connect_url", "" );
1352 include plugin_dir_path( __FILE__ ) . nitropack_trailingslashit( 'view' ) . 'connect-oneclick.php';
1353 } else {
1354 include plugin_dir_path( __FILE__ ) . nitropack_trailingslashit( 'view' ) . 'connect.php';
1355 }
1356 }
1357 }
1358 function load_nitropack_scripts_styles( $page ) {
1359 //global WP
1360 wp_enqueue_style( 'nitropack-notifications', plugin_dir_url( __FILE__ ) . 'view/stylesheet/nitro-notifications.min.css', array(), NITROPACK_VERSION );
1361 wp_enqueue_script( 'nitropack_notices_js', plugin_dir_url( __FILE__ ) . 'view/javascript/np_notices.js', array(), NITROPACK_VERSION, true );
1362 wp_localize_script( 'nitropack_notices_js', 'nitropack_notices_vars', array(
1363 'nonce' => wp_create_nonce( NITROPACK_NONCE ),
1364 ) );
1365 //plugin only
1366 if ( $page === 'toplevel_page_nitropack' ) {
1367 //css
1368 wp_enqueue_style( 'nitropack', plugin_dir_url( __FILE__ ) . 'view/stylesheet/style.min.css', array(), NITROPACK_VERSION );
1369 wp_enqueue_style( 'nitropack-connect', plugin_dir_url( __FILE__ ) . 'view/stylesheet/connect.min.css', array(), NITROPACK_VERSION );
1370 //json animations
1371 wp_enqueue_script( 'lottie', 'https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js', array(), null, false );
1372 //js
1373 wp_enqueue_script( 'nitropack_flowbite_js', plugin_dir_url( __FILE__ ) . 'view/javascript/flowbite.min.js', array(), NITROPACK_VERSION, true );
1374 wp_enqueue_script( 'nitropack_ui', plugin_dir_url( __FILE__ ) . 'view/javascript/nitropackUI.js', array(), NITROPACK_VERSION, true );
1375
1376 if ( get_nitropack()->isConnected() ) {
1377 $passed_onboarding = get_option( 'nitropack-onboardingPassed' );
1378 if ( ! $passed_onboarding ) {
1379 wp_enqueue_script( 'nitropack_preview_site', plugin_dir_url( __FILE__ ) . 'view/javascript/preview_site.js', array('nitropack_flowbite_js'), NITROPACK_VERSION, true );
1380 wp_localize_script(
1381 'nitropack_preview_site',
1382 'np_onboarding',
1383 array(
1384 'nitro_plugin_url' => plugin_dir_url( __FILE__ ),
1385 'select_mode' => esc_html__( 'Select Mode', 'nitropack' ),
1386 'active_mode' => esc_html__( 'Active Mode', 'nitropack' ),
1387 'switching_mode' => esc_html__( 'Switching Optimization Mode.', 'nitropack' ),
1388 'est_cachewarmup_msg' => esc_html__( 'Estimating optimizations usage', 'nitropack' ),
1389 )
1390 );
1391 }
1392 wp_enqueue_script( 'nitropack_settings', plugin_dir_url( __FILE__ ) . 'view/javascript/np_settings.js', array(), NITROPACK_VERSION, true );
1393 wp_localize_script(
1394 'nitropack_settings',
1395 'np_settings',
1396 array(
1397 'nitroNonce' => wp_create_nonce( NITROPACK_NONCE ),
1398 'nitro_plugin_url' => plugin_dir_url( __FILE__ ),
1399 'error_msg' => esc_html__( 'Something went wrong.', 'nitropack' ),
1400 'success_msg' => esc_html__( 'Settings updated.', 'nitropack' ),
1401 'est_cachewarmup_msg' => esc_html__( 'Estimating optimizations usage', 'nitropack' ),
1402 'quickSetupSaveUrl' => get_nitropack_integration_url( "quicksetup" ),
1403 )
1404 );
1405 //select2
1406 wp_register_script( 'np-select2', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js', array( 'jquery' ), NITROPACK_VERSION, true );
1407 wp_enqueue_script( 'np-select2' );
1408 }
1409 }
1410 }
1411 add_action( 'admin_enqueue_scripts', 'load_nitropack_scripts_styles' );
1412
1413
1414 function nitropack_is_advanced_cache_allowed() {
1415 return ! in_array( nitropack_detect_hosting(), array(
1416 "pressable"
1417 ) );
1418 }
1419
1420
1421 function nitropack_get_hosting_notice_file() {
1422 return nitropack_trailingslashit( NITROPACK_DATA_DIR ) . "hosting_notice";
1423 }
1424
1425
1426
1427 function nitropack_dismiss_hosting_notice() {
1428 nitropack_verify_ajax_nonce( $_REQUEST );
1429 $hostingNoticeFile = nitropack_get_hosting_notice_file();
1430 if ( WP_DEBUG ) {
1431 touch( $hostingNoticeFile );
1432 } else {
1433 @touch( $hostingNoticeFile );
1434 }
1435 }
1436
1437
1438
1439
1440 function nitropack_is_config_up_to_date() {
1441 $siteConfig = nitropack_get_site_config();
1442 return ! empty( $siteConfig ) && ! empty( $siteConfig["pluginVersion"] ) && $siteConfig["pluginVersion"] == NITROPACK_VERSION;
1443 }
1444
1445 function nitropack_filter_non_original_cookies( &$cookies ) {
1446 global $np_originalRequestCookies;
1447 $ogNames = is_array( $np_originalRequestCookies ) ? array_keys( $np_originalRequestCookies ) : array();
1448 foreach ( $cookies as $name => $val ) {
1449 if ( ! in_array( $name, $ogNames ) ) {
1450 unset( $cookies[ $name ] );
1451 }
1452 }
1453 }
1454
1455 function nitropack_add_meta_box() {
1456 $editor = get_option( "nitropack-canEditorClearCache" );
1457 $allowed_capabilities = current_user_can( 'manage_options' ) || current_user_can( 'nitropack_meta_box' ) || ( $editor && current_user_can( 'editor' ) );
1458 if ( $allowed_capabilities ) {
1459 foreach ( nitropack_get_cacheable_object_types() as $objectType ) {
1460 add_meta_box( 'nitropack_manage_cache_box', 'NitroPack', 'nitropack_print_meta_box', $objectType, 'side' );
1461 }
1462 }
1463 }
1464
1465
1466 // This is only used for post types that can have "single" pages
1467 function nitropack_print_meta_box( $post ) {
1468 wp_enqueue_script( 'nitropack_metabox_js', plugin_dir_url( __FILE__ ) . 'view/javascript/metabox.js?np_v=' . NITROPACK_VERSION, true );
1469 wp_localize_script( 'nitropack_metabox_js', 'metaboxdata', array( 'nitroNonce' => wp_create_nonce( NITROPACK_NONCE ), 'nitro_plugin_url' => plugin_dir_url( __FILE__ ) ) );
1470
1471 $html = '';
1472 $html .= '<p><a class="button nitropack-invalidate-single" data-post_id="' . $post->ID . '" data-post_url="' . get_permalink( $post ) . '" style="width:100%;text-align:center;padding: 3px 0;">Invalidate cache</a></p>';
1473 $html .= '<p><a class="button nitropack-purge-single" data-post_id="' . $post->ID . '" data-post_url="' . get_permalink( $post ) . '" style="width:100%;text-align:center;padding: 3px 0;">Purge cache</a></p>';
1474 $html .= '<p id="nitropack-status-msg" style="display:none;"></p>';
1475 echo $html;
1476 }
1477
1478 function get_nitropack_sdk( $siteId = null, $siteSecret = null, $urlOverride = NULL, $forwardExceptions = false ) {
1479 return get_nitropack()->getSdk( $siteId, $siteSecret, $urlOverride, $forwardExceptions );
1480 }
1481
1482 function get_nitropack_integration_url( $integration, $nitro = null ) {
1483 if ( $nitro || ( null !== $nitro = get_nitropack_sdk() ) ) {
1484 return $nitro->integrationUrl( $integration );
1485 }
1486
1487 return "#";
1488 }
1489
1490 function register_nitropack_settings() {
1491 register_setting( NITROPACK_OPTION_GROUP, 'nitropack-enableCompression', array( 'default' => -1 ) );
1492 }
1493
1494 function nitropack_get_layout() {
1495 $layout = "default";
1496
1497 if ( nitropack_is_home() ) {
1498 $layout = "home";
1499 } else if ( nitropack_is_blogindex() ) {
1500 $layout = "blogindex";
1501 } else if ( is_page() ) {
1502 $layout = "page";
1503 } else if ( is_attachment() ) {
1504 $layout = "attachment";
1505 } else if ( is_author() ) {
1506 $layout = "author";
1507 } else if ( is_search() ) {
1508 $layout = "search";
1509 } else if ( is_tag() ) {
1510 $layout = "tag";
1511 } else if ( is_tax() ) {
1512 $layout = "taxonomy";
1513 } else if ( is_category() ) {
1514 $layout = "category";
1515 } else if ( nitropack_is_archive() ) {
1516 $layout = "archive";
1517 } else if ( is_feed() ) {
1518 $layout = "feed";
1519 } else if ( is_page() ) {
1520 $layout = "page";
1521 } else if ( is_single() ) {
1522 $layout = get_post_type();
1523 }
1524
1525 return $layout;
1526 }
1527
1528 function nitropack_sdk_invalidate( $url = NULL, $tag = NULL, $reason = NULL ) {
1529
1530 $status = false;
1531
1532 if ( null !== $nitro = get_nitropack_sdk() ) {
1533 try {
1534 $siteConfig = nitropack_get_site_config();
1535 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1536
1537 if ( $tag ) {
1538 if ( is_array( $tag ) ) {
1539 $tag = array_map( 'nitropack_filter_tag', $tag );
1540 } else {
1541 $tag = nitropack_filter_tag( $tag );
1542 }
1543 }
1544
1545 $nitro->invalidateCache( $url, $tag, $reason );
1546
1547 try {
1548
1549 if ( defined( 'NITROPACK_DEBUG_MODE' ) ) {
1550 do_action( 'nitropack_debug_invalidate', $url, $tag, $reason );
1551 }
1552
1553 do_action( 'nitropack_integration_purge_url', $homeUrl );
1554
1555 if ( $tag ) {
1556 do_action( 'nitropack_integration_purge_all' );
1557 } else if ( $url ) {
1558 do_action( 'nitropack_integration_purge_url', $url );
1559 } else {
1560 do_action( 'nitropack_integration_purge_all' );
1561 }
1562 } catch (\Exception $e) {
1563 // Exception while signaling 3rd party integration addons to purge their cache
1564 }
1565 } catch (\Exception $e) {
1566 $status = false;
1567 }
1568
1569 $status = true;
1570 }
1571
1572 return $status;
1573 }
1574
1575 /* Start Heartbeat Related Functions */
1576 function nitropack_is_heartbeat_needed() {
1577 return ! nitropack_is_optimizer_request() &&
1578 ! nitropack_is_amp_page() &&
1579 ! nitropack_is_heartbeat_running() &&
1580 ( ! nitropack_is_heartbeat_completed() || time() - nitropack_last_heartbeat() > NITROPACK_HEARTBEAT_INTERVAL );
1581 }
1582
1583 function nitropack_print_heartbeat_script() {
1584 if ( nitropack_is_heartbeat_needed() ) {
1585 if ( defined( "NITROPACK_HEARTBEAT_PRINTED" ) )
1586 return;
1587 define( "NITROPACK_HEARTBEAT_PRINTED", true );
1588 echo apply_filters( "nitro_script_output", nitropack_get_heartbeat_script() );
1589 }
1590 }
1591
1592 function nitropack_get_heartbeat_script() {
1593 $siteConfig = nitropack_get_site_config();
1594 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) && ! empty( $siteConfig["siteSecret"] ) ) {
1595 if ( null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
1596 if ( is_admin() ) {
1597 $credentials = "same-origin";
1598 } else {
1599 $credentials = "omit";
1600 }
1601
1602 return "
1603 <script nitro-exclude>
1604 var heartbeatData = new FormData(); heartbeatData.append('nitroHeartbeat', '1');
1605 fetch(location.href, {method: 'POST', body: heartbeatData, credentials: '$credentials'});
1606 </script>";
1607 }
1608 }
1609 }
1610
1611 function is_valid_nitropack_heartbeat() {
1612 return ! empty( $_POST['nitroHeartbeat'] );
1613 }
1614
1615 function nitropack_get_heartbeat_file() {
1616 if ( null !== $nitro = get_nitropack_sdk() ) {
1617 return nitropack_trailingslashit( $nitro->getCacheDir() ) . "heartbeat";
1618 } else {
1619 return nitropack_trailingslashit( NITROPACK_DATA_DIR ) . "heartbeat";
1620 }
1621 }
1622
1623 function nitropack_last_heartbeat() {
1624 if ( null !== $nitro = get_nitropack_sdk() ) {
1625 try {
1626 return \NitroPack\SDK\Filesystem::fileMTime( nitropack_get_heartbeat_file() );
1627 } catch (\Exception $e) {
1628 return 0;
1629 }
1630 }
1631 }
1632
1633 function nitropack_is_heartbeat_running() {
1634 if ( null !== $nitro = get_nitropack_sdk() ) {
1635 try {
1636 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents( nitropack_get_heartbeat_file() );
1637 if ( $heartbeatContent == "1" ) {
1638 return time() - nitropack_last_heartbeat() < NITROPACK_HEARTBEAT_INTERVAL;
1639 }
1640 } catch (\Exception $e) {
1641 return false;
1642 }
1643 }
1644 }
1645
1646 function nitropack_is_heartbeat_completed() {
1647 if ( null !== $nitro = get_nitropack_sdk() ) {
1648 try {
1649 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents( nitropack_get_heartbeat_file() );
1650 return $heartbeatContent == "0"; // 0 - Job Done, 1 - Job Running, 2 - Job Needs Repeat
1651 } catch (\Exception $e) {
1652 return true;
1653 }
1654 }
1655 }
1656
1657 function nitropack_handle_heartbeat() {
1658 // TODO: Lock the file before checking this
1659 if ( nitropack_is_heartbeat_running() )
1660 return;
1661
1662 session_write_close();
1663 if ( null !== $nitro = get_nitropack_sdk() ) {
1664 try {
1665 $success = true;
1666 \NitroPack\SDK\Filesystem::filePutContents( nitropack_get_heartbeat_file(), 1 );
1667 if ( nitropack_healthcheck() ) {
1668 $success &= nitropack_flush_backlog();
1669 }
1670 $success &= nitropack_cache_cleanup();
1671
1672 if ( $success ) {
1673 \NitroPack\SDK\Filesystem::filePutContents( nitropack_get_heartbeat_file(), 0 );
1674 } else {
1675 \NitroPack\SDK\Filesystem::filePutContents( nitropack_get_heartbeat_file(), 2 );
1676 }
1677 } catch (\Exception $e) {
1678 return false;
1679 }
1680 }
1681 exit;
1682 }
1683
1684 function nitropack_healthcheck() {
1685 if ( null !== $nitro = get_nitropack_sdk() ) {
1686 return $nitro->getHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY || $nitro->checkHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY;
1687 }
1688 return true;
1689 }
1690
1691 function nitropack_flush_backlog() {
1692 if ( null !== $nitro = get_nitropack_sdk() ) {
1693 try {
1694 if ( $nitro->backlog->exists() ) {
1695 return $nitro->backlog->replay( 30 );
1696 }
1697 } catch (\NitroPack\SDK\BacklogReplayTimeoutException $e) {
1698 $nitro->backlog->delete();
1699 return nitropack_sdk_purge( NULL, NULL, "Full purge after backlog timeout" );
1700 } catch (\Exception $e) {
1701 return false;
1702 }
1703 }
1704 return true;
1705 }
1706
1707 function nitropack_cache_cleanup() {
1708 if ( null !== $nitro = get_nitropack_sdk() ) {
1709 $cacheDirParent = dirname( $nitro->getCacheDir() );
1710 $entries = scandir( $cacheDirParent );
1711 foreach ( $entries as $entry ) {
1712 if ( strpos( $entry, ".stale." ) !== false ) {
1713 $cacheDir = nitropack_trailingslashit( $cacheDirParent ) . $entry;
1714 try {
1715 \NitroPack\SDK\Filesystem::deleteDir( $cacheDir );
1716 } catch (\Exception $e) {
1717 // TODO: Log this
1718 return false;
1719 }
1720 }
1721 }
1722 }
1723 return true;
1724 }
1725 /* End Heartbeat Related Functions */
1726
1727 function nitropack_sdk_purge( $url = NULL, $tag = NULL, $reason = NULL, $type = \NitroPack\SDK\PurgeType::COMPLETE ) {
1728
1729 $status = false;
1730
1731 if ( null !== $nitro = get_nitropack_sdk() ) {
1732 try {
1733 $siteConfig = nitropack_get_site_config();
1734 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1735
1736 if ( $tag ) {
1737 if ( is_array( $tag ) ) {
1738 $tag = array_map( 'nitropack_filter_tag', $tag );
1739 } else {
1740 $tag = nitropack_filter_tag( $tag );
1741 }
1742 }
1743
1744 if ( ! $url && ! $tag ) {
1745 $nitro->purgeLocalCache( true );
1746 }
1747
1748 $nitro->purgeCache( $url, $tag, $type, $reason );
1749
1750 if ( defined( 'NITROPACK_DEBUG_MODE' ) ) {
1751 do_action( 'nitropack_debug_purge', $url, $tag, $reason );
1752 }
1753
1754 try {
1755 do_action( 'nitropack_integration_purge_url', $homeUrl );
1756
1757 if ( $tag ) {
1758 do_action( 'nitropack_integration_purge_all' );
1759 } else if ( $url ) {
1760 do_action( 'nitropack_integration_purge_url', $url );
1761 } else {
1762 do_action( 'nitropack_integration_purge_all' );
1763 }
1764 } catch (\Exception $e) {
1765 // Exception while signaling 3rd party integration addons to purge their cache
1766 }
1767 } catch (\Exception $e) {
1768 $status = false;
1769 }
1770
1771 $status = true;
1772 }
1773
1774 return $status;
1775 }
1776
1777 /**
1778 * @param string|null $url
1779 * @return bool
1780 */
1781 function nitropack_sdk_purge_local( $url = NULL ) {
1782 if ( null === $nitro = get_nitropack_sdk() ) {
1783 return false;
1784 }
1785
1786 try {
1787 if ( $url ) {
1788 $nitro->purgeLocalUrlCache( $url );
1789 do_action( 'nitropack_integration_purge_url', $url );
1790 return true;
1791 }
1792
1793 $nitro->purgeLocalCache( true );
1794
1795 try {
1796 do_action( 'nitropack_integration_purge_all' );
1797 } catch (\Exception $e) {
1798 // Exception while signaling our 3rd party integration addons to purge their cache
1799 }
1800
1801 return true;
1802 } catch (\Exception $e) {
1803 return false;
1804 }
1805 }
1806
1807 /**
1808 * @param string|null $url
1809 * @return bool
1810 */
1811 function nitropack_sdk_invalidate_local( $url = NULL ) {
1812 if ( null === $nitro = get_nitropack_sdk() ) {
1813 return false;
1814 }
1815
1816 try {
1817 if ( $url ) {
1818 $nitro->invalidateLocalUrlCache( $url );
1819 do_action( 'nitropack_integration_purge_url', $url );
1820 return true;
1821 }
1822
1823 $nitro->invalidateLocalCache( true );
1824
1825 try {
1826 do_action( 'nitropack_integration_purge_all' );
1827 } catch (\Exception $e) {
1828 // Exception while signaling our 3rd party integration addons to purge their cache
1829 }
1830
1831 return true;
1832 } catch (\Exception $e) {
1833 return false;
1834 }
1835 }
1836
1837 function nitropack_sdk_delete_backlog() {
1838 if ( null !== $nitro = get_nitropack_sdk() ) {
1839 try {
1840 if ( $nitro->backlog->exists() ) {
1841 $nitro->backlog->delete();
1842 }
1843 } catch (\Exception $e) {
1844 return false;
1845 }
1846
1847 return true;
1848 }
1849
1850 return false;
1851 }
1852
1853 function nitropack_purge( $url = NULL, $tag = NULL, $reason = NULL ) {
1854 if ( $tag != "pageType:home" ) {
1855 $siteConfig = nitropack_get_site_config();
1856 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1857 nitropack_log_invalidate( $homeUrl, "pageType:home", $reason );
1858 }
1859
1860 if ( $tag != "pageType:archive" ) {
1861 nitropack_log_invalidate( NULL, "pageType:archive", $reason );
1862 }
1863
1864 nitropack_log_purge( $url, $tag, $reason );
1865 }
1866
1867 function nitropack_log_purge( $url = NULL, $tag = NULL, $reason = NULL ) {
1868 global $np_loggedPurges;
1869 if ( $tag && is_array( $tag ) ) {
1870 foreach ( $tag as $tagSingle ) {
1871 nitropack_log_purge( $url, $tagSingle, $reason );
1872 }
1873 return;
1874 }
1875
1876 $keyBase = "";
1877 if ( $url ) {
1878 $keyBase .= $url;
1879 }
1880
1881 if ( $tag ) {
1882 $tag = nitropack_filter_tag( $tag );
1883 $keyBase .= $tag;
1884 }
1885
1886 $purgeRequestKey = md5( $keyBase );
1887 if ( is_array( $np_loggedPurges ) && array_key_exists( $purgeRequestKey, $np_loggedPurges ) ) {
1888 $np_loggedPurges[ $purgeRequestKey ]["reason"] = $reason;
1889 $np_loggedPurges[ $purgeRequestKey ]["priority"]++;
1890 } else {
1891 $np_loggedPurges[ $purgeRequestKey ] = array(
1892 "url" => $url,
1893 "tag" => $tag,
1894 "reason" => $reason,
1895 "priority" => 1
1896 );
1897 }
1898 }
1899
1900 function nitropack_invalidate( $url = NULL, $tag = NULL, $reason = NULL ) {
1901 if ( $tag != "pageType:home" ) {
1902 $siteConfig = nitropack_get_site_config();
1903 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
1904 nitropack_log_invalidate( $homeUrl, "pageType:home", $reason );
1905 }
1906
1907 if ( $tag != "pageType:archive" ) {
1908 nitropack_log_invalidate( NULL, "pageType:archive", $reason );
1909 }
1910
1911 nitropack_log_invalidate( $url, $tag, $reason );
1912 }
1913
1914 function nitropack_log_invalidate( $url = NULL, $tag = NULL, $reason = NULL ) {
1915 global $np_loggedInvalidations;
1916 if ( $tag && is_array( $tag ) ) {
1917 foreach ( $tag as $tagSingle ) {
1918 nitropack_log_invalidate( $url, $tagSingle, $reason );
1919 }
1920 return;
1921 }
1922
1923 $keyBase = "";
1924 if ( $url ) {
1925 $keyBase .= $url;
1926 }
1927
1928 if ( $tag ) {
1929 $tag = nitropack_filter_tag( $tag );
1930 $keyBase .= $tag;
1931 }
1932
1933 $invalidateRequestKey = md5( $keyBase );
1934 if ( is_array( $np_loggedInvalidations ) && array_key_exists( $invalidateRequestKey, $np_loggedInvalidations ) ) {
1935 $np_loggedInvalidations[ $invalidateRequestKey ]["reason"] = $reason;
1936 $np_loggedInvalidations[ $invalidateRequestKey ]["priority"]++;
1937 } else {
1938 $np_loggedInvalidations[ $invalidateRequestKey ] = array(
1939 "url" => $url,
1940 "tag" => $tag,
1941 "reason" => $reason,
1942 "priority" => 1
1943 );
1944 }
1945 }
1946
1947 function nitropack_queue_sort( $a, $b ) {
1948 if ( $a["priority"] == $b["priority"] ) {
1949 return 0;
1950 }
1951 return ( $a["priority"] < $b["priority"] ) ? -1 : 1;
1952 }
1953
1954 function nitropack_execute_purges() {
1955 global $np_loggedPurges;
1956 // if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1957 // return;
1958 // }
1959 if ( ! empty( $np_loggedPurges ) ) {
1960 uasort( $np_loggedPurges, "nitropack_queue_sort" );
1961 foreach ( $np_loggedPurges as $requestKey => $data ) {
1962 nitropack_sdk_purge( $data["url"], $data["tag"], $data["reason"] );
1963 }
1964 }
1965 }
1966
1967 function nitropack_execute_invalidations() {
1968 global $np_loggedInvalidations;
1969 // if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1970 // return;
1971 // }
1972 if ( ! empty( $np_loggedInvalidations ) ) {
1973 uasort( $np_loggedInvalidations, "nitropack_queue_sort" );
1974 foreach ( $np_loggedInvalidations as $requestKey => $data ) {
1975 nitropack_sdk_invalidate( $data["url"], $data["tag"], $data["reason"] );
1976 }
1977 }
1978 }
1979
1980 function nitropack_execute_warmups() {
1981 if ( ! empty( $_GET["action"] ) && ( $_GET["action"] === "edit" ) && ! empty( $_GET["meta-box-loader"] ) ) {
1982 return;
1983 }
1984
1985 try {
1986 if ( ! empty( \NitroPack\WordPress\NitroPack::$np_loggedWarmups ) && ( null !== $nitro = get_nitropack_sdk() ) ) {
1987 $warmupStats = $nitro->getApi()->getWarmupStats();
1988 if ( ! empty( $warmupStats["status"] ) ) {
1989 foreach ( array_unique( \NitroPack\WordPress\NitroPack::$np_loggedWarmups ) as $url ) {
1990 $nitro->getApi()->runWarmup( $url );
1991 }
1992 }
1993 }
1994 } catch (\Exception $e) {
1995 }
1996 }
1997
1998 function nitropack_fetch_config() {
1999 if ( null !== $nitro = get_nitropack_sdk() ) {
2000 try {
2001 $nitro->fetchConfig();
2002 } catch (\Exception $e) {
2003 }
2004 }
2005 }
2006
2007 function nitropack_theme_handler( $event = NULL ) {
2008 if ( ! get_option( "nitropack-autoCachePurge", 1 ) )
2009 return;
2010
2011 $msg = $event ? $event : 'Theme switched';
2012
2013 try {
2014 nitropack_sdk_purge( NULL, NULL, $msg ); // purge entire cache
2015 } catch (\Exception $e) {
2016 }
2017 }
2018
2019 function nitropack_purge_cache() {
2020 nitropack_verify_ajax_nonce( $_REQUEST );
2021 try {
2022 if ( nitropack_sdk_purge( NULL, NULL, 'Light purge of all caches', \NitroPack\SDK\PurgeType::LIGHT_PURGE ) ) {
2023 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Light purge of all caches' );
2024 nitropack_json_and_exit( array(
2025 "type" => "success",
2026 "message" => __( 'Cache has been purged successfully!', 'nitropack' )
2027 ) );
2028 }
2029 } catch (\Exception $e) {
2030 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Light purge of all caches. Error: ' . $e );
2031 }
2032 nitropack_json_and_exit( array(
2033 "type" => "error",
2034 "message" => __( 'Error! There was an error and the cache was not purged!', 'nitropack' )
2035 ) );
2036 }
2037
2038 function nitropack_invalidate_cache() {
2039 nitropack_verify_ajax_nonce( $_REQUEST );
2040 try {
2041 if ( nitropack_sdk_invalidate( NULL, NULL, 'Manual invalidation of all pages' ) ) {
2042 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Manual invalidation of all pages' );
2043 nitropack_json_and_exit( array(
2044 "type" => "success",
2045 "message" => __( 'Cache has been invalidated successfully!', 'nitropack' )
2046
2047 ) );
2048 }
2049 } catch (\Exception $e) {
2050 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Manual invalidation of all pages. Error: ' . $e );
2051 }
2052
2053 nitropack_json_and_exit( array(
2054 "type" => "error",
2055 "message" => __( 'There was an error and the cache was not invalidated!', 'nitropack' )
2056 ) );
2057 }
2058
2059 function nitropack_clear_residual_cache() {
2060 nitropack_verify_ajax_nonce( $_REQUEST );
2061 $gde = ! empty( $_POST["gde"] ) ? $_POST["gde"] : NULL;
2062 if ( $gde && array_key_exists( $gde, NitroPack\Integration\Plugin\RC::$modules ) ) {
2063 $result = call_user_func( array( NitroPack\Integration\Plugin\RC::$modules[ $gde ], "clearCache" ) ); // This needs to be like this because of compatibility with PHP 5.6
2064 if ( ! in_array( false, $result ) ) {
2065 nitropack_json_and_exit( array(
2066 "type" => "success",
2067 "message" => __( 'Success! The residual cache has been cleared successfully!', 'nitropack' )
2068 ) );
2069 }
2070 }
2071 nitropack_json_and_exit( array(
2072 "type" => "error",
2073 "message" => __( 'Error! There was an error clearing the residual cache!', 'nitropack' )
2074 ) );
2075 }
2076
2077 function nitropack_json_and_exit( $array ) {
2078 if ( nitropack_is_wp_cli() ) {
2079 $type = NULL;
2080 if ( array_key_exists( "status", $array ) ) {
2081 $type = $array["status"];
2082 } else if ( array_key_exists( "type", $array ) ) {
2083 $type = $array["type"];
2084 }
2085
2086 if ( $type && array_key_exists( "message", $array ) ) {
2087 if ( $type == "success" ) {
2088 WP_CLI::success( $array["message"] );
2089 } else {
2090 WP_CLI::error( $array["message"] );
2091 }
2092 }
2093 } else {
2094 echo json_encode( $array );
2095 }
2096 exit;
2097 }
2098 function nitropack_admin_toast_msgs( $type ) {
2099 if ( $type === 'success' ) {
2100 $msg = esc_html__( 'Settings updated.', 'nitropack' );
2101 } else {
2102 $msg = esc_html__( 'Something went wrong.', 'nitropack' );
2103 }
2104 return $msg;
2105 }
2106 /* General verification for AJAX requests
2107 * @params array $request_data The request data
2108 * @params array|null $allowed_roles The allowed user roles
2109 */
2110 function nitropack_verify_ajax_nonce( $request_data, $allowed_roles = null ) {
2111 // If not an ajax request
2112 if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
2113 return;
2114 }
2115
2116 // Check if WordPress functions are available
2117 if ( ! function_exists( 'wp_verify_nonce' ) || ! function_exists( 'wp_die' ) || ! function_exists( 'current_user_can' ) ) {
2118 return;
2119 }
2120
2121 // If nonce fails verification
2122 if ( empty( $request_data['nonce'] ) || ! wp_verify_nonce( $request_data['nonce'], NITROPACK_NONCE ) ) {
2123 wp_die( 'Unauthorized request' );
2124 }
2125
2126 // Check user permissions
2127 if ( $allowed_roles ) {
2128 $has_permission = false;
2129 foreach ( $allowed_roles as $role ) {
2130 if ( current_user_can( $role ) ) {
2131 $has_permission = true;
2132 break;
2133 }
2134 }
2135 if ( ! $has_permission ) {
2136 wp_die( 'Unauthorized request' );
2137 }
2138 } else {
2139 //fallback to admin rights
2140 if ( ! current_user_can( 'manage_options' ) ) {
2141 wp_die( 'Unauthorized request' );
2142 }
2143 }
2144 }
2145 function nitropack_has_post_important_change( $post ) {
2146 $prevPost = nitropack_get_post_pre_update( $post );
2147 return $prevPost && ( $prevPost->post_title != $post->post_title || $prevPost->post_name != $post->post_name || $prevPost->post_excerpt != $post->post_excerpt );
2148 }
2149
2150 function nitropack_purge_single_cache() {
2151 $canEditorPurge = get_option( 'nitropack-canEditorClearCache' );
2152 if ( $canEditorPurge ) {
2153 nitropack_verify_ajax_nonce( $_REQUEST, [ 'editor', 'manage_options' ] );
2154 } else {
2155 nitropack_verify_ajax_nonce( $_REQUEST, [ 'manage_options' ] );
2156 }
2157 if ( ! empty( $_POST["postId"] ) && is_numeric( $_POST["postId"] ) ) {
2158 $postId = $_POST["postId"];
2159 $postUrl = ! empty( $_POST["postUrl"] ) ? $_POST["postUrl"] : NULL;
2160 $reason = sprintf( "Manual purge of post %s via the WordPress admin panel", $postId );
2161 $tag = $postId > 0 ? "single:$postId" : NULL;
2162
2163 if ( $postUrl ) {
2164 if ( is_array( $postUrl ) ) {
2165 foreach ( $postUrl as &$url ) {
2166 $url = nitropack_sanitize_url_input( $url );
2167 }
2168 } else {
2169 $postUrl = nitropack_sanitize_url_input( $postUrl );
2170 $reason = "Manual purge of " . $postUrl;
2171 }
2172 }
2173
2174 try {
2175 if ( nitropack_sdk_purge( $postUrl, $tag, $reason ) ) {
2176 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Manual purge of post ' . $postId . ' via WordPress.' );
2177 nitropack_json_and_exit( array(
2178 "type" => "success",
2179 "message" => __( 'Success! Cache has been purged successfully!', 'nitropack' )
2180 ) );
2181 }
2182 } catch (\Exception $e) {
2183 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Manual purge of post ' . $postId . ' via WordPress. Error: ' . $e );
2184 }
2185 }
2186
2187 nitropack_json_and_exit( array(
2188 "type" => "error",
2189 "message" => __( 'Error! There was an error and the cache was not purged!', 'nitropack' )
2190 ) );
2191 }
2192
2193 function nitropack_purge_entire_cache() {
2194 nitropack_verify_ajax_nonce( $_REQUEST );
2195 try {
2196 if ( nitropack_sdk_purge( null, null, 'Manual purge of all pages' ) ) {
2197 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Manual purge of all pages' );
2198 nitropack_json_and_exit( [
2199 "type" => "success",
2200 "message" => __( 'Success! Cache has been purged successfully!', 'nitropack' )
2201 ] );
2202 }
2203 } catch (\Exception $e) {
2204 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Manual purge of all pages. Error: ' . $e );
2205 }
2206
2207 nitropack_json_and_exit( [
2208 "type" => "error",
2209 "message" => __( 'Error! There was an error and the cache was not purged!', 'nitropack' )
2210 ] );
2211 }
2212
2213 function nitropack_invalidate_single_cache() {
2214 $canEditorPurge = get_option( 'nitropack-canEditorClearCache' );
2215 if ( $canEditorPurge ) {
2216 nitropack_verify_ajax_nonce( $_REQUEST, [ 'editor', 'manage_options' ] );
2217 } else {
2218 nitropack_verify_ajax_nonce( $_REQUEST, [ 'manage_options' ] );
2219 }
2220 if ( ! empty( $_POST["postId"] ) && is_numeric( $_POST["postId"] ) ) {
2221 $postId = $_POST["postId"];
2222 $postUrl = ! empty( $_POST["postUrl"] ) ? $_POST["postUrl"] : NULL;
2223 $reason = sprintf( "Manual invalidation of post %s via the WordPress admin panel", $postId );
2224 $tag = $postId > 0 ? "single:$postId" : NULL;
2225
2226 if ( $postUrl ) {
2227 if ( is_array( $postUrl ) ) {
2228 foreach ( $postUrl as &$url ) {
2229 $url = nitropack_sanitize_url_input( $url );
2230 }
2231 } else {
2232 $postUrl = nitropack_sanitize_url_input( $postUrl );
2233 $reason = "Manual invalidation of " . $postUrl;
2234 }
2235 }
2236
2237 try {
2238 if ( nitropack_sdk_invalidate( $postUrl, $tag, $reason ) ) {
2239 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Manual invalidation of post ' . $postId . ' via WordPress.' );
2240 nitropack_json_and_exit( array(
2241 "type" => "success",
2242 "message" => __( 'Success! Cache has been invalidated successfully!', 'nitropack' )
2243 ) );
2244 }
2245 } catch (\Exception $e) {
2246 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Manual invalidation of post ' . $postId . ' via WordPress. Error: ' . $e );
2247 }
2248 }
2249
2250 nitropack_json_and_exit( array(
2251 "type" => "error",
2252 "message" => __( 'Error! There was an error and the cache was not invalidated!', 'nitropack' )
2253 ) );
2254 }
2255
2256 function nitropack_clean_post_cache( $post, $taxonomies = NULL, $hasImportantChangeInPost = NULL, $reason = NULL, $usePurge = false ) {
2257 try {
2258 $postID = $post->ID;
2259 $postType = isset( $post->post_type ) ? $post->post_type : "post";
2260 $nicePostTypeLabel = nitropack_get_nice_post_type_label( $postType );
2261 $reason = $reason ? $reason : sprintf( "Updated %s '%s'", $nicePostTypeLabel, $post->post_title );
2262 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
2263
2264 if ( in_array( $postType, $cacheableObjectTypes ) ) {
2265 if ( $usePurge ) {
2266 // We only purge the single pages because they have to immediately stop serving cache
2267 // These pages no longer exists and if their URL is requested we must not server cache
2268 nitropack_purge( NULL, "single:$postID", $reason );
2269 } else {
2270 nitropack_invalidate( NULL, "single:$postID", $reason );
2271 }
2272
2273 nitropack_invalidate( NULL, "post:$postID", $reason );
2274
2275 if ( $hasImportantChangeInPost === NULL ) {
2276 $hasImportantChangeInPost = nitropack_has_post_important_change( $post );
2277 }
2278 if ( $taxonomies === NULL ) {
2279 if ( $hasImportantChangeInPost ) { // This change should be reflected in all taxonomy pages
2280 $taxonomies = array( 'related' => nitropack_get_taxonomies( $post ) );
2281 } else { // No important change, so only update taxonomy pages which have been added or removed from the post
2282 $taxonomies = nitropack_get_taxonomies_for_update( $post );
2283 }
2284 }
2285 if ( $taxonomies ) {
2286 if ( ! empty( $taxonomies['added'] ) ) { // taxonomies that the post was just added to, must purge all pages for these taxonomies
2287 foreach ( $taxonomies['added'] as $term_taxonomy_id ) {
2288 nitropack_invalidate( NULL, "tax:$term_taxonomy_id", $reason );
2289 }
2290 }
2291 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:)
2292 foreach ( $taxonomies['deleted'] as $term_taxonomy_id ) {
2293 nitropack_invalidate( NULL, "taxpost:$term_taxonomy_id:$postID", $reason );
2294 }
2295 }
2296 if ( ! empty( $taxonomies['related'] ) ) { // taxonomy pages that the post is linked to (also accounts for paginations via the taxpost: tag instead of only tax:)
2297 foreach ( $taxonomies['related'] as $term_taxonomy_id ) {
2298 nitropack_invalidate( NULL, "taxpost:$term_taxonomy_id:$postID", $reason );
2299 }
2300 }
2301 }
2302 } else {
2303 if ( $post->public ) {
2304 nitropack_invalidate( NULL, "post:$postID", $reason );
2305 }
2306
2307 $posts = get_post_ancestors( $postID );
2308 foreach ( $posts as $parentID ) {
2309 $parent = get_post( $parentID );
2310 nitropack_clean_post_cache( $parent, false, false, $reason );
2311 }
2312 }
2313 } catch (\Exception $e) {
2314 }
2315 }
2316
2317 function nitropack_get_nice_post_type_label( $postType ) {
2318 $postTypes = get_post_types( array(
2319 "name" => $postType
2320 ), "objects" );
2321
2322 return ! empty( $postTypes[ $postType ] ) && ! empty( $postTypes[ $postType ]->labels ) ? $postTypes[ $postType ]->labels->singular_name : $postType;
2323 }
2324
2325 function nitropack_handle_comment_transition( $new, $old, $comment ) {
2326 if ( ! get_option( "nitropack-autoCachePurge", 1 ) )
2327 return;
2328
2329 try {
2330 $postID = $comment->comment_post_ID;
2331 $post = get_post( $postID );
2332 $postType = isset( $post->post_type ) ? $post->post_type : "post";
2333 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
2334
2335 if ( in_array( $postType, $cacheableObjectTypes ) ) {
2336 nitropack_invalidate( NULL, "single:" . $postID, sprintf( "Invalidation of '%s' due to changing related comment status", $post->post_title ) );
2337 }
2338 } catch (\Exception $e) {
2339 // TODO: Log the error
2340 }
2341 }
2342
2343 function nitropack_handle_comment_post( $commentID, $isApproved ) {
2344 if ( ! get_option( "nitropack-autoCachePurge", 1 ) || $isApproved !== 1 )
2345 return;
2346
2347 try {
2348 $comment = get_comment( $commentID );
2349 $postID = $comment->comment_post_ID;
2350 $post = get_post( $postID );
2351 nitropack_invalidate( NULL, "single:" . $postID, sprintf( "Invalidation of '%s' due to posting a new approved comment", $post->post_title ) );
2352 } catch (\Exception $e) {
2353 // TODO: Log the error
2354 }
2355 }
2356
2357 function custom_reduce_stock_after_order_placed( $order ) {
2358
2359 if ( (int) get_option( 'nitropack-stockReduceStatus' ) !== 1 )
2360 return;
2361
2362 $items = $order->get_items();
2363
2364 foreach ( $items as $item ) {
2365 $product_id = $item->get_product_id();
2366 $product_url = get_permalink( $product_id );
2367
2368 $stock_quantity = get_post_meta( $product_id, '_stock', true );
2369
2370 if ( $stock_quantity > 0 ) {
2371 nitropack_sdk_invalidate( $product_url, NULL, 'Invalidated to adjust order quantity' );
2372 }
2373 }
2374 }
2375
2376 function nitropack_detect_changes_and_clean_post_cache( $post ) {
2377 if ( ! get_option( "nitropack-autoCachePurge", 1 ) ) {
2378 return;
2379 }
2380
2381 $post_before = nitropack_get_post_pre_update( $post );
2382 $ignoredComparisonKeys = array( 'post_modified', 'post_modified_gmt' );
2383 $canCleanPostCache = false;
2384 $postStatesEqual = nitropack_compare_posts( (array) $post_before, (array) $post, $ignoredComparisonKeys );
2385
2386 if ( $postStatesEqual ) {
2387 $taxCurrent = nitropack_get_taxonomies( $post );
2388 $taxPreUpdate = nitropack_get_taxonomies_pre_update( $post );
2389 $taxAreEqual = nitropack_compare_posts( $taxCurrent, $taxPreUpdate );
2390 if ( $taxAreEqual ) {
2391 $metaCurrent = get_post_meta( $post->ID );
2392 $metaPreUpdate = nitropack_get_meta_pre_update( $post );
2393 $metaIsEqual = nitropack_compare_posts( $metaCurrent, $metaPreUpdate );
2394 if ( ! $metaIsEqual ) {
2395 $canCleanPostCache = true;
2396 }
2397 } else {
2398 $canCleanPostCache = true;
2399 }
2400 } else {
2401 $canCleanPostCache = true;
2402 }
2403
2404 if ( $canCleanPostCache ) {
2405 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post );
2406 nitropack_clean_post_cache( $post );
2407 define( 'NITROPACK_PURGE_CACHE', true );
2408 }
2409 }
2410
2411
2412 function nitropack_handle_post_transition( $new, $old, $post ) {
2413 if ( wp_is_post_revision( $post ) )
2414 return;
2415 if ( ! empty( $post->ID ) && in_array( $post->ID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs ) )
2416 return;
2417 if ( ! get_option( "nitropack-autoCachePurge", 1 ) )
2418 return;
2419
2420 try {
2421 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.
2422 return;
2423 }
2424
2425 $ignoredPostTypes = array(
2426 "revision",
2427 "scheduled-action",
2428 "flamingo_contact",
2429 "carts"/*WooCommerce Cart Reports*/
2430 );
2431
2432 $nicePostTypes = array(
2433 "post" => "Post",
2434 "page" => "Page",
2435 "tribe_events" => "Calendar Event",
2436 );
2437 $postType = isset( $post->post_type ) ? $post->post_type : "post";
2438 $nicePostTypeLabel = nitropack_get_nice_post_type_label( $postType );
2439
2440 if ( in_array( $postType, $ignoredPostTypes ) )
2441 return;
2442
2443 switch ( $postType ) {
2444 case "nav_menu_item":
2445 nitropack_invalidate( NULL, NULL, sprintf( "Invalidation of all pages due to modifying menu entries" ) );
2446 break;
2447 case "customize_changeset":
2448 nitropack_invalidate( NULL, NULL, sprintf( "Invalidation of all pages due to applying appearance customization" ) );
2449 break;
2450 case "custom_css":
2451 nitropack_invalidate( NULL, NULL, sprintf( "Invalidation of all pages due to modifying custom CSS" ) );
2452 break;
2453 default:
2454 if ( $new == "future" ) {
2455 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 ) );
2456 } else if ( $new === 'publish' && $old === 'trash' ) {
2457 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 ) );
2458 } else if ( $new == "publish" && $old != "publish" ) {
2459 /* Handle first publish */
2460 // set_transient($post->ID . '_np_first_publish', $post, 120);
2461 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post->ID );
2462 if ( ! defined( 'NITROPACK_PURGE_CACHE' ) ) {
2463 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 );
2464 }
2465 if ( $post->post_type === 'post' ) {
2466 nitropack_invalidate( NULL, "pageType:blogindex", 'Invalidation of blog page due to changing related post status' );
2467 }
2468 } else if ( $new == "trash" && $old == "publish" ) {
2469 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 );
2470 } else if ( $new == "private" && $old == "publish" ) {
2471 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 );
2472 } else if ( $new == "draft" && $old == "publish" ) {
2473 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 );
2474 } else if ( $new != "trash" ) {
2475 if ( ! defined( 'NITROPACK_PURGE_CACHE' ) ) {
2476 nitropack_detect_changes_and_clean_post_cache( $post );
2477 }
2478 if ( $new == 'publish' ) {
2479 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post->ID );
2480 }
2481 }
2482 break;
2483 }
2484 } catch (\Exception $e) {
2485 // TODO: Log the error
2486 }
2487 }
2488
2489 function nitropack_handle_first_publish( $post_id ) {
2490 $first_publish_post = get_transient( $post_id . '_np_first_publish', false );
2491
2492 if ( ! $first_publish_post ) {
2493 return;
2494 }
2495
2496 try {
2497 nitropack_clean_post_cache( $first_publish_post, array( 'added' => nitropack_get_taxonomies( $first_publish_post ) ), true, sprintf( "Invalidate related pages due to publishing %s '%s'", $first_publish_post->nicePostTypeLabel, $first_publish_post->post_title ) );
2498 nitropack_invalidate( NULL, "pageType:blogindex", 'Invalidation of blog page due to changing related post status' );
2499 delete_transient( $post_id . '_np_first_publish' );
2500 } catch (\Exception $e) {
2501 // TODO: Log the error
2502 }
2503 }
2504
2505 function nitropack_sot( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
2506 if ( ! get_option( "nitropack-autoCachePurge", 1 ) )
2507 return;
2508
2509 $post = get_post( $object_id );
2510 $post_status = $post->post_status;
2511
2512 if ( $post_status === 'auto-draft' || $post_status === 'draft' ) {
2513 return;
2514 }
2515
2516 if ( ! defined( 'NITROPACK_PURGE_CACHE' ) ) {
2517 $purgeCache = ! nitropack_compare_posts( $tt_ids, $old_tt_ids );
2518 $cleanCache = $purgeCache ? "YES" : "NO";
2519 if ( $purgeCache ) {
2520 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post );
2521 nitropack_clean_post_cache( $post );
2522 define( 'NITROPACK_PURGE_CACHE', true );
2523 }
2524 }
2525 }
2526
2527 function nitropack_handle_product_updates( $product, $updated ) {
2528 if ( ! get_option( "nitropack-autoCachePurge", 1 ) ) {
2529 return;
2530 }
2531
2532 if ( ! defined( 'NITROPACK_PURGE_CACHE' ) ) {
2533 try {
2534 $post = get_post( $product->get_id() );
2535 $reasons = 'updated ';
2536 $reasons .= implode( ',', $updated );
2537 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink( $post );
2538 nitropack_clean_post_cache( $post, NULL, true, sprintf( "Invalidate product '%s'. Reason '%s'", $product->get_name(), $reasons ) ); // Update the product page and all related pages, because a quantity change might have to add/remove "Out of stock" labels
2539 define( 'NITROPACK_PURGE_CACHE', true );
2540 } catch (\Exception $e) {
2541 // TODO: Log the error
2542 }
2543 }
2544 }
2545
2546 function nitropack_post_link_listener( $permalink, $post, $leavename ) {
2547 if ( is_object( $post ) ) {
2548 nitropack_handle_the_post( $post );
2549 }
2550
2551 return $permalink;
2552 }
2553
2554 function nitropack_handle_the_post( $post ) {
2555 global $np_customExpirationTimes, $np_queriedObj;
2556 if ( defined( 'POSTEXPIRATOR_VERSION' ) ) {
2557 $postExpiryDate = get_post_meta( $post->ID, "_expiration-date", true );
2558 if ( ! empty( $postExpiryDate ) && $postExpiryDate > time() ) { // We only need to look at future dates
2559 $np_customExpirationTimes[] = $postExpiryDate;
2560 }
2561 }
2562
2563 if ( function_exists( "sort_portfolio" ) ) { // Portfolio Sorting plugin
2564 $portfolioStartDate = get_post_meta( $post->ID, "start_date", true );
2565 $portfolioEndDate = get_post_meta( $post->ID, "end_date", true );
2566 if ( ! empty( $portfolioStartDate ) && strtotime( $portfolioStartDate ) > time() ) { // We only need to look at future dates
2567 $np_customExpirationTimes[] = strtotime( $portfolioStartDate );
2568 } else if ( ! empty( $portfolioEndDate ) && strtotime( $portfolioEndDate ) > time() ) { // We only need to look at future dates
2569 $np_customExpirationTimes[] = strtotime( $portfolioEndDate );
2570 }
2571 }
2572
2573 $GLOBALS["NitroPack.tags"][ "post:" . $post->ID ] = 1;
2574 $GLOBALS["NitroPack.tags"][ "author:" . $post->post_author ] = 1;
2575 if ( $np_queriedObj ) {
2576 $GLOBALS["NitroPack.tags"][ "taxpost:" . $np_queriedObj->term_taxonomy_id . ":" . $post->ID ] = 1;
2577 }
2578 }
2579
2580 function nitropack_ignore_post_updates( $postID ) {
2581 \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs[] = $postID;
2582 }
2583
2584 function nitropack_get_taxonomies( $post ) {
2585 $term_taxonomy_ids = array();
2586 $taxonomies = get_object_taxonomies( $post->post_type );
2587 foreach ( $taxonomies as $taxonomy ) {
2588 $terms = get_the_terms( $post->ID, $taxonomy );
2589 if ( ! empty( $terms ) ) {
2590 foreach ( $terms as $term ) {
2591 $term_taxonomy_ids[] = $term->term_taxonomy_id;
2592 }
2593 }
2594 }
2595 return $term_taxonomy_ids;
2596 }
2597
2598 function nitropack_get_taxonomies_for_update( $post ) {
2599 $prevTaxonomies = nitropack_get_taxonomies_pre_update( $post );
2600 $newTaxonomies = nitropack_get_taxonomies( $post );
2601 $intersection = array_intersect( $newTaxonomies, $prevTaxonomies );
2602 $prevTaxonomies = array_diff( $prevTaxonomies, $intersection );
2603 $newTaxonomies = array_diff( $newTaxonomies, $intersection );
2604 return array(
2605 "added" => array_diff( $newTaxonomies, $prevTaxonomies ),
2606 "deleted" => array_diff( $prevTaxonomies, $newTaxonomies )
2607 );
2608 }
2609
2610 function nitropack_get_post_pre_update( $post ) {
2611 return ! empty( \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $post->ID ] ) ? \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $post->ID ] : NULL;
2612 }
2613
2614 function nitropack_get_taxonomies_pre_update( $post ) {
2615 return ! empty( \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $post->ID ] ) ? \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $post->ID ] : array();
2616 }
2617
2618 function nitropack_get_meta_pre_update( $post ) {
2619 return ! empty( \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $post->ID ] ) ? \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $post->ID ] : array();
2620 }
2621
2622 function nitropack_log_post_pre_update( $postID ) {
2623 if ( in_array( $postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs ) )
2624 return;
2625
2626
2627 $post = get_post( $postID );
2628 \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $postID ] = $post;
2629 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $postID ] = nitropack_get_taxonomies( $post );
2630 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2631 \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $postID ] = get_post_meta( $postID );
2632 }
2633
2634 function nitropack_log_product_pre_api_update( $product, $request, $creating ) {
2635
2636 if ( ! $creating ) {
2637
2638 $postID = $product->get_id();
2639 if ( in_array( $postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs ) )
2640 return;
2641
2642
2643 $post = get_post( $postID );
2644 \NitroPack\WordPress\NitroPack::$preUpdatePosts[ $postID ] = $post;
2645 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[ $postID ] = nitropack_get_taxonomies( $post );
2646 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2647 \NitroPack\WordPress\NitroPack::$preUpdateMeta[ $postID ] = get_post_meta( $postID );
2648 }
2649
2650 return $product;
2651 }
2652
2653 function nitropack_compare_posts( array $p1, array $p2, $ignoredKeys = null ) {
2654 $p1keys = array_keys( $p1 );
2655 $p2keys = array_keys( $p2 );
2656 if ( count( $p1keys ) !== count( $p2keys ) ) {
2657 return false;
2658 }
2659 if ( array_diff( $p1keys, $p2keys ) ) {
2660 return false;
2661 }
2662
2663 $isP1assoc = false;
2664 $expectedKey = 0;
2665 foreach ( $p2 as $i => $_ ) {
2666 if ( $i !== $expectedKey ) {
2667 $isP1assoc = true;
2668 }
2669 $expectedKey++;
2670 }
2671
2672 $isP2assoc = false;
2673 $expectedKey = 0;
2674 foreach ( $p2 as $i => $_ ) {
2675 if ( $i !== $expectedKey ) {
2676 $isP2assoc = true;
2677 }
2678 $expectedKey++;
2679 }
2680
2681 if ( $isP1assoc !== $isP2assoc ) {
2682 return false;
2683 }
2684
2685 if ( ! $isP1assoc && ! $isP2assoc ) {
2686 sort( $p1 );
2687 sort( $p2 );
2688 }
2689
2690 foreach ( $p1 as $poKey => $poVal ) {
2691 if ( $ignoredKeys && in_array( $poKey, $ignoredKeys, true ) ) {
2692 continue;
2693 }
2694 $checkpoint01 = is_array( $poVal );
2695 $checkpoint02 = is_array( $p2[ $poKey ] );
2696 if ( $checkpoint01 && $checkpoint02 ) {
2697 if ( ! nitropack_compare_posts( $poVal, $p2[ $poKey ], $ignoredKeys, 'Re:' ) ) { //'Re:' left for debug purpose to destinguish between main and recursive call
2698 return false;
2699 }
2700 } elseif ( ! $checkpoint01 && ! $checkpoint02 ) {
2701 if ( $poVal != $p2[ $poKey ] ) {
2702 return false;
2703 }
2704 } else {
2705 return false;
2706 }
2707 }
2708 return true;
2709 }
2710
2711 function nitropack_filter_tag( $tag ) {
2712 return preg_replace( "/[^a-zA-Z0-9:]/", ":", $tag );
2713 }
2714
2715 function nitropack_log_tags() {
2716 if ( ! empty( $GLOBALS["NitroPack.instance"] ) && ! empty( $GLOBALS["NitroPack.tags"] ) ) {
2717 $nitro = $GLOBALS["NitroPack.instance"];
2718 $layout = nitropack_get_layout();
2719 try {
2720 $config = $nitro->getConfig();
2721 $useHeader = ! empty( $config->TagsViaHeader );
2722
2723 if ( $layout == "home" ) {
2724 if ( $useHeader ) {
2725 nitropack_header( "x-nitro-tags:pageType:home" );
2726 } else {
2727 $nitro->getApi()->tagUrl( $nitro->getUrl(), "pageType:home" );
2728 }
2729 } else if ( $layout == "archive" ) {
2730 if ( $useHeader ) {
2731 nitropack_header( "x-nitro-tags:pageType:archive" );
2732 } else {
2733 $nitro->getApi()->tagUrl( $nitro->getUrl(), "pageType:archive" );
2734 }
2735 } else {
2736 if ( $useHeader && count( $GLOBALS["NitroPack.tags"] ) <= 100 ) {
2737 nitropack_header( "x-nitro-tags:" . implode( "|", array_map( "nitropack_filter_tag", array_keys( $GLOBALS["NitroPack.tags"] ) ) ) );
2738 } else {
2739 $nitro->getApi()->tagUrl( $nitro->getUrl(), array_map( "nitropack_filter_tag", array_keys( $GLOBALS["NitroPack.tags"] ) ) );
2740 }
2741 }
2742 } catch (\Exception $e) {
2743 }
2744 }
2745 }
2746
2747 function nitropack_extend_nonce_life( $life ) {
2748 // Nonce life should be extended only:
2749 // - if NitroPack is connected for this site
2750 // - if the current value is shorter than the life time of a cache file
2751 // - if no user is logged in
2752 // - for cacheable requests
2753 //
2754 // Reasons why we might need to extend the nonce life time even for requests that are not cacheable:
2755 // - 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)
2756 // - 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.)
2757
2758 if ( ( null !== $nitro = get_nitropack_sdk() ) ) {
2759 $siteConfig = nitropack_get_site_config();
2760 if ( $siteConfig && ! empty( $siteConfig["isDlmActive"] ) && ! empty( $siteConfig["dlm_downloading_url"] ) && ! empty( $siteConfig["dlm_download_endpoint"] ) ) {
2761 $currentUrl = $nitro->getUrl();
2762 if ( strpos( $currentUrl, $siteConfig["dlm_downloading_url"] ) !== false || strpos( $currentUrl, $siteConfig["dlm_download_endpoint"] ) !== false ) {
2763 // Do not modify the nonce times on pages of Download Monitor
2764 return $life;
2765 }
2766 }
2767 $cacheExpiration = $nitro->getConfig()->PageCache->ExpireTime;
2768 return $cacheExpiration > $life ? $cacheExpiration : $life; // Extend the life of cacheable nonces up to the cache expiration time if needed
2769 }
2770 return $life;
2771 }
2772
2773 function nitropack_reconfigure_webhooks() {
2774 nitropack_verify_ajax_nonce( $_REQUEST );
2775 $siteConfig = nitropack_get_site_config();
2776
2777 if ( $siteConfig && ! empty( $siteConfig["siteId"] ) ) {
2778 $siteId = $siteConfig["siteId"];
2779 if ( null !== $nitro = get_nitropack_sdk() ) {
2780 $token = nitropack_generate_webhook_token( $siteId );
2781 try {
2782 nitropack_setup_webhooks( $nitro, $token );
2783 update_option( "nitropack-webhookToken", $token );
2784 nitropack_json_and_exit( array( "status" => "success", 'message' => __( 'Connection reconfigured successfully', 'nitropack' ) ) );
2785 } catch (\NitroPack\SDK\WebhookException $e) {
2786 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Webhook Error: ' . $e );
2787 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Webhook Error: ', 'nitropack' ) . $e->getTraceAsString() ) );
2788 }
2789 } else {
2790 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Unable to get SDK instance' );
2791 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Unable to get SDK instance', 'nitropack' ) ) );
2792 }
2793 } else {
2794 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Incomplete site config. Please reinstall the plugin' );
2795 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Incomplete site config. Please reinstall the plugin!', 'nitropack' ) ) );
2796 }
2797 }
2798
2799 function nitropack_generate_webhook_token( $siteId ) {
2800 return md5( __FILE__ . ":" . $siteId );
2801 }
2802
2803 function nitropack_verify_connect_ajax() {
2804 nitropack_verify_ajax_nonce( $_REQUEST );
2805 $siteId = ! empty( $_POST["siteId"] ) ? $_POST["siteId"] : "";
2806 $siteSecret = ! empty( $_POST["siteSecret"] ) ? $_POST["siteSecret"] : "";
2807 nitropack_verify_connect( $siteId, $siteSecret );
2808 }
2809
2810 function nitropack_check_func_availability( $func_name ) {
2811 if ( function_exists( 'ini_get' ) ) {
2812 $existsResult = stripos( ini_get( 'disable_functions' ), $func_name ) === false;
2813 } else {
2814 $existsResult = function_exists( $func_name );
2815 }
2816 return $existsResult;
2817 }
2818
2819 function nitropack_prevent_connecting( $nitroSDK ) {
2820 $remoteUrl = $nitroSDK->getApi()->getWebhook( "config" );
2821 if ( empty( $remoteUrl ) ) {
2822 return false;
2823 }
2824 $siteConfig = nitropack_get_site_config();
2825 $localUrl = new \NitroPack\Url\Url( $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url() );
2826 $localHome = strtolower( $localUrl->getHost() . $localUrl->getPath() );
2827 $storedUrl = new \NitroPack\Url\Url( $remoteUrl );
2828 $remoteHome = strtolower( $storedUrl->getHost() . $storedUrl->getPath() );
2829 if ( $localHome === $remoteHome ) {
2830 return false;
2831 }
2832 return array( 'local' => $localHome, 'remote' => $remoteHome );
2833 }
2834
2835 function nitropack_verify_connect( $siteId, $siteSecret ) {
2836
2837 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Verifying connection to NitroPack API' );
2838
2839 if ( ! nitropack_check_func_availability( 'stream_socket_client' ) ) {
2840
2841 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'stream_socket_client function is not allowed by your host.' );
2842
2843 nitropack_json_and_exit( array( "status" => "error", "message" => "stream_socket_client function is not allowed by your host. <a href=\"https://support.nitropack.io/hc/en-us/articles/360020898137\" target=\"_blank\" rel=\"noreferrer noopener\">Read more</a>" ) );
2844 }
2845
2846 if ( ! nitropack_check_func_availability( 'stream_context_create' ) ) {
2847 // <a href=\"https://support.nitropack.io/hc/en-us/articles/360020898137\" target=\"_blank\" rel=\"noreferrer noopener\">Read more</a>
2848 // ^ Similar article needed on website for stream_context_create function
2849 nitropack_json_and_exit( array( "status" => "error", "message" => "stream_context_create function is not allowed by your host." ) );
2850 }
2851
2852 if ( empty( $siteId ) || empty( $siteSecret ) ) {
2853
2854 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Invalid API key or API secret key value' );
2855
2856 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Invalid API key or API secret key value', 'nitropack' ) ) );
2857 }
2858
2859 //remove tags and whitespaces
2860 $siteId = trim( esc_attr( $siteId ) );
2861 $siteSecret = trim( esc_attr( $siteSecret ) );
2862
2863 if ( ! nitropack_validate_site_id( $siteId ) || ! nitropack_validate_site_secret( $siteSecret ) ) {
2864
2865 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Invalid API key or API secret key value' );
2866
2867 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Invalid API key or API secret key value', 'nitropack' ) ) );
2868 }
2869
2870 try {
2871 $blogId = get_current_blog_id();
2872 if ( null !== $nitro = get_nitropack_sdk( $siteId, $siteSecret, NULL, true ) ) {
2873 if ( ! $nitro->checkHealthStatus() ) {
2874
2875 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Error when trying to communicate with NitroPack\'s servers. Current health status: ' . $nitro->getHealthStatus() );
2876
2877 nitropack_json_and_exit( array(
2878 "status" => "error",
2879 "message" => __( 'Error when trying to communicate with NitroPack\'s servers. Please try again in a few minutes. If the issue persists, please', 'nitropack' ) . " <a href='https://support." . NITROPACK_HOST . "/hc/en-us' target='_blank'>contact us</a>."
2880 ) );
2881 }
2882
2883 $preventParing = apply_filters( 'nitropack_prevent_connect', nitropack_prevent_connecting( $nitro ) );
2884 if ( $preventParing ) {
2885
2886 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'It looks like another site ' . $preventParing['remote'] . ' is already connected using these credentials. Either disconnect it or register a new site in your NitroPack dashboard.' );
2887
2888 nitropack_json_and_exit( array(
2889 "status" => "error",
2890 "message" => "It looks like another site <strong>({$preventParing['remote']})</strong> is already connected using these credentials. Either disconnect it or register a new site in your NitroPack dashboard.<br/>
2891 <a href='https://support.nitropack.io/hc/en-us/articles/4405254569745' target='_blank' rel='noreferrer noopener'>Read more</a>"
2892 ) );
2893 }
2894 $token = nitropack_generate_webhook_token( $siteId );
2895 get_nitropack()->settings->set_required_settings( $token );
2896
2897 nitropack_setup_webhooks( $nitro, $token );
2898
2899 // _icl_current_language is WPML cookie, it is added here for compatibility with this module
2900 $customVariationCookies = array( "np_wc_currency", "np_wc_currency_language", "_icl_current_language" );
2901 $variationCookies = $nitro->getApi()->getVariationCookies();
2902 foreach ( $variationCookies as $cookie ) {
2903 $index = array_search( $cookie["name"], $customVariationCookies );
2904 if ( $index !== false ) {
2905 array_splice( $customVariationCookies, $index, 1 );
2906 }
2907 }
2908
2909 foreach ( $customVariationCookies as $cookieName ) {
2910 $nitro->getApi()->setVariationCookie( $cookieName );
2911 }
2912
2913 $nitro->fetchConfig(); // Reload the variation cookies
2914
2915 get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId );
2916 nitropack_install_advanced_cache();
2917
2918 try {
2919 do_action( 'nitropack_integration_purge_all' );
2920 } catch (\Exception $e) {
2921 // Exception while signaling our 3rd party integration addons to purge their cache
2922 }
2923
2924 nitropack_event( "connect", $nitro );
2925 nitropack_event( "enable_extension", $nitro );
2926
2927 // Optimize front page
2928 $siteConfig = nitropack_get_site_config();
2929 if ( $siteConfig ) {
2930 $nitro->getApi()->runWarmup( [ $siteConfig['home_url'] ], true ); // force run a warmup on the home page
2931 }
2932
2933 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'NitroPack connected' );
2934
2935 $onboarding = get_option( 'nitropack-onboardingPassed' );
2936 $url = $onboarding === '1' ? get_admin_url( $blogId, "admin.php?page=nitropack" ) : get_admin_url( $blogId, "admin.php?page=nitropack&onboarding=1" );
2937 nitropack_json_and_exit( array(
2938 "status" => "success",
2939 "url" => $url,
2940 "message" => __( "Connected", "nitropack" )
2941 ) );
2942 }
2943 } catch (\NitroPack\SDK\WebhookException $e) {
2944
2945 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( $e );
2946
2947 nitropack_json_and_exit( array( "status" => "error", "message" => $e ) );
2948 } catch (\NitroPack\SDK\StorageException $e) {
2949
2950 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Permission Error: ' . $e );
2951
2952 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Permission Error: ', 'nitropack' ) . $e ) );
2953 } catch (\NitroPack\SDK\EmptyConfigException $e) {
2954
2955 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Error while fetching remote config: ' . $e );
2956
2957 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Error while fetching remote config: ', 'nitropack' ) . $e ) );
2958 } catch (\NitroPack\SocketOpenException $e) {
2959
2960 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Can\'t establish connection with NitroPack\'s servers. ' . $e );
2961
2962 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Can\'t establish connection with NitroPack\'s servers', 'nitropack' ) ) );
2963 } catch (\Exception $e) {
2964
2965 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Incorrect API credentials. Please make sure that you copied them correctly and try again. ' . $e );
2966
2967 nitropack_json_and_exit( array( "status" => "error", "message" => __( 'Incorrect API credentials. Please make sure that you copied them correctly and try again.', 'nitropack' ) ) );
2968 }
2969
2970 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Error verifying connection to NitroPack.' );
2971
2972 nitropack_json_and_exit( array( "status" => "error" ) );
2973 }
2974
2975 function nitropack_reset_webhooks( $nitroSDK ) {
2976 $nitroSDK->getApi()->unsetWebhook( "config" );
2977 $nitroSDK->getApi()->unsetWebhook( "cache_clear" );
2978 $nitroSDK->getApi()->unsetWebhook( "cache_ready" );
2979 }
2980
2981 function nitropack_setup_webhooks( $nitro, $token = NULL ) {
2982 if ( ! $nitro || ! $token ) {
2983 throw new \NitroPack\SDK\WebhookException( 'Webhook token cannot be empty.' );
2984 }
2985
2986 $homeUrl = strtolower( get_home_url() );
2987 $configUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=config&token=$token" );
2988 $cacheClearUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=cache_clear&token=$token" );
2989 $cacheReadyUrl = new \NitroPack\Url\Url( $homeUrl . "?nitroWebhook=cache_ready&token=$token" );
2990
2991 $nitro->getApi()->setWebhook( "config", $configUrl );
2992 $nitro->getApi()->setWebhook( "cache_clear", $cacheClearUrl );
2993 $nitro->getApi()->setWebhook( "cache_ready", $cacheReadyUrl );
2994 }
2995
2996 function nitropack_disconnect() {
2997 nitropack_verify_ajax_nonce( $_REQUEST );
2998
2999 nitropack_uninstall_advanced_cache();
3000
3001 try {
3002 nitropack_event( "disconnect" );
3003 if ( null !== $nitro = get_nitropack_sdk() ) {
3004 nitropack_reset_webhooks( $nitro );
3005 }
3006 } catch (\Exception $e) {
3007 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'NitroPack cannot be disconnected. Error: ' . $e );
3008 nitropack_json_and_exit( array( "status" => "error", "message" => $e ) );
3009 }
3010
3011 get_nitropack()->unsetCurrentBlogConfig();
3012
3013 $hostingNoticeFile = nitropack_get_hosting_notice_file();
3014 if ( file_exists( $hostingNoticeFile ) ) {
3015 if ( WP_DEBUG ) {
3016 unlink( $hostingNoticeFile );
3017 } else {
3018 @unlink( $hostingNoticeFile );
3019 }
3020 }
3021 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'NitroPack disconnected' );
3022 nitropack_json_and_exit( array( "status" => "success", "message" => __( "Disconnected", "nitropack" ) ) );
3023 }
3024
3025 function nitropack_set_compression_ajax() {
3026 nitropack_verify_ajax_nonce( $_REQUEST );
3027 $option = (int) ! empty( $_POST["data"]["compressionStatus"] );
3028 $updated = update_option( "nitropack-enableCompression", $option );
3029
3030 if ( $updated ) {
3031 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'HTML Compression is ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3032 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ), "hasCompression" => $option ) );
3033 } else {
3034 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'HTML Compression cannot be ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3035 nitropack_json_and_exit( array(
3036 "type" => "error",
3037 "message" => nitropack_admin_toast_msgs( 'error' )
3038 ) );
3039 }
3040 }
3041 function nitropack_set_can_editor_clear_cache() {
3042 nitropack_verify_ajax_nonce( $_REQUEST );
3043 $option = (int) ! empty( $_POST["data"]["canEditorClearCache"] );
3044 $updated = update_option( "nitropack-canEditorClearCache", $option );
3045 if ( $updated ) {
3046 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Allow Editors to purge cache is ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3047 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ), "allowedEditors" => $option ) );
3048 } else {
3049 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Allow Editors to purge cache cannot be ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3050 nitropack_json_and_exit( array(
3051 "type" => "error",
3052 "message" => nitropack_admin_toast_msgs( 'error' )
3053 ) );
3054 }
3055 }
3056
3057
3058 function nitropack_set_auto_cache_purge_ajax() {
3059 nitropack_verify_ajax_nonce( $_REQUEST );
3060 $option = (int) ! empty( $_POST["autoCachePurgeStatus"] );
3061 $updated = update_option( "nitropack-autoCachePurge", $option );
3062 if ( $updated ) {
3063 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Auto cache purge is ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3064 nitropack_json_and_exit( [ "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ), 'autoCachePurgeStatus' => $option ] );
3065 } else {
3066 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Auto cache purge cannot be ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3067 nitropack_json_and_exit( [
3068 "type" => "error",
3069 "message" => nitropack_admin_toast_msgs( 'error' )
3070 ] );
3071 }
3072 }
3073 function nitropack_set_ajax_shortcodes_ajax() {
3074 nitropack_verify_ajax_nonce( $_REQUEST );
3075
3076 $new_shortcodes = isset( $_POST['shortcodes'] ) ? $_POST['shortcodes'] : null;
3077 $enabled = isset( $_POST['enabled'] ) ? $_POST['enabled'] : null;
3078
3079 if ( $new_shortcodes === null && $enabled === null ) {
3080 nitropack_json_and_exit( array(
3081 "type" => "error",
3082 "message" => nitropack_admin_toast_msgs( 'error' )
3083 ) );
3084 }
3085 $nitropack = get_nitropack();
3086 $siteConfig = $nitropack->Config->get();
3087 $configKey = \NitroPack\WordPress\NitroPack::getConfigKey();
3088
3089 if ( ! is_null( $enabled ) ) {
3090 $siteConfig[ $configKey ]['options_cache']['ajaxShortcodes']['enabled'] = $enabled === '1';
3091 }
3092
3093 if ( ! is_null( $new_shortcodes ) ) {
3094 $existing_options = ( is_array( $new_shortcodes ) && $new_shortcodes[0] === '' ) ? [] : $new_shortcodes;
3095 if ( $existing_options )
3096 $siteConfig[ $configKey ]['options_cache']['ajaxShortcodes']['shortcodes'] = $existing_options;
3097 }
3098 $updated = $nitropack->Config->set( $siteConfig );
3099
3100 if ( $updated ) {
3101
3102 if ( $enabled ) {
3103 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Shortcodes are enabled' );
3104 } elseif ( ! $enabled && ! $new_shortcodes ) {
3105 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Shortcodes are disabled' );
3106 }
3107
3108 if ( is_array( $new_shortcodes ) && $new_shortcodes[0] === '' ) {
3109 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( "Shortcodes are empty" );
3110 } elseif ( is_array( $new_shortcodes ) ) {
3111 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( "Shortcodes are: " . implode( ", ", $new_shortcodes ) );
3112 }
3113
3114 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ) ) );
3115 } else {
3116
3117 if ( $enabled ) {
3118 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Shortcodes are ' . $enabled ? 'enabled' : 'disabled' );
3119 } elseif ( ! $enabled && ! $new_shortcodes ) {
3120 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Shortcodes are disabled' );
3121 }
3122 if ( is_array( $new_shortcodes ) && $new_shortcodes[0] === '' ) {
3123 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( "Shortcodes are empty" );
3124 } elseif ( is_array( $new_shortcodes ) ) {
3125 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( "Shortcodes are: " . implode( ", ", $new_shortcodes ) );
3126 }
3127
3128 nitropack_json_and_exit( array(
3129 "type" => "error",
3130 "message" => nitropack_admin_toast_msgs( 'error' )
3131 ) );
3132 }
3133 }
3134
3135
3136 function nitropack_set_cart_cache_ajax() {
3137 nitropack_verify_ajax_nonce( $_REQUEST );
3138 if ( get_nitropack()->isConnected() && nitropack_render_woocommerce_cart_cache_option() ) {
3139 $cartCacheStatus = (int) ( ! empty( $_POST["cartCacheStatus"] ) );
3140
3141 if ( $cartCacheStatus == 1 ) {
3142 nitropack_enable_cart_cache();
3143 } else {
3144 nitropack_disable_cart_cache();
3145 }
3146 }
3147
3148 nitropack_json_and_exit( array(
3149 "type" => "error",
3150 "message" => nitropack_admin_toast_msgs( 'error' )
3151 ) );
3152 }
3153
3154 function nitropack_set_stock_reduce_status() {
3155 nitropack_verify_ajax_nonce( $_REQUEST );
3156 $option = (int) ! empty( $_POST["data"]["stockReduceStatus"] );
3157 $updated = update_option( "nitropack-stockReduceStatus", $option );
3158 if ( $updated ) {
3159 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Stock Reduce Status is ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3160 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ), "stockReduceStatus" => $option ) );
3161 } else {
3162 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Stock Reduce Status cannot be' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3163 nitropack_json_and_exit( array(
3164 "type" => "error",
3165 "message" => nitropack_admin_toast_msgs( 'error' )
3166 ) );
3167 }
3168 }
3169
3170 function nitropack_set_bb_cache_purge_sync_ajax() {
3171 nitropack_verify_ajax_nonce( $_REQUEST );
3172 $option = (int) ! empty( $_POST["bbCachePurgeSyncStatus"] );
3173 $updated = update_option( "nitropack-bbCacheSyncPurge", $option );
3174 if ( $updated ) {
3175 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Beaver Builder Status is ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3176 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ), 'bbCacheSyncPurgeStatus' => $option ) );
3177 } else {
3178 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Beaver Builder Status cannot be ' . ( $option === 1 ? 'enabled' : 'disabled' ) );
3179 nitropack_json_and_exit( array(
3180 "type" => "error",
3181 "message" => nitropack_admin_toast_msgs( 'error' )
3182 ) );
3183 }
3184 }
3185
3186 function nitropack_set_cacheable_post_types() {
3187 nitropack_verify_ajax_nonce( $_REQUEST );
3188 $currentCacheableObjectTypes = nitropack_get_cacheable_object_types();
3189 $cacheableObjectTypes = ! empty( $_POST["cacheableObjectTypes"] ) ? $_POST["cacheableObjectTypes"] : array();
3190 $noncacheableObjectTypes = ! empty( $_POST["noncacheableObjectTypes"] ) ? $_POST["noncacheableObjectTypes"] : array();
3191
3192 /* Used for non optimized CPT modal which is shown only once */
3193 if ( isset( $_POST["append"] ) && $_POST["append"] === "yes" ) {
3194 $cacheableObjectTypes = array_merge( $currentCacheableObjectTypes, $cacheableObjectTypes );
3195 }
3196
3197 update_option( "nitropack-cacheableObjectTypes", $cacheableObjectTypes );
3198 update_option( "nitropack-nonCacheableObjectTypes", $noncacheableObjectTypes );
3199
3200 foreach ( $currentCacheableObjectTypes as $objectType ) {
3201 if ( ! in_array( $objectType, $cacheableObjectTypes ) ) {
3202 nitropack_purge( NULL, "pageType:" . $objectType, "Optimizing '$objectType' pages was manually disabled" );
3203 }
3204 }
3205
3206 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( "Optimized CPTs: " . implode( ", ", $cacheableObjectTypes ) );
3207 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( "Non-optimized CPTs: " . ( ! empty( $noncacheableObjectTypes ) && is_array( $noncacheableObjectTypes ) ? implode( ", ", $noncacheableObjectTypes ) : 'N/A' ) );
3208
3209 nitropack_json_and_exit( array(
3210 "type" => "success",
3211 "message" => nitropack_admin_toast_msgs( 'success' )
3212 ) );
3213 }
3214
3215 function nitropack_test_compression_ajax() {
3216 nitropack_verify_ajax_nonce( $_REQUEST );
3217 $hasCompression = true;
3218 try {
3219 if ( \NitroPack\Integration\Hosting\Flywheel::detect() ) { // Flywheel: Compression is enabled by default
3220 $updated = update_option( "nitropack-enableCompression", 0 );
3221 } else {
3222 require_once plugin_dir_path( __FILE__ ) . nitropack_trailingslashit( 'nitropack-sdk' ) . 'autoload.php';
3223 $http = new NitroPack\HttpClient\HttpClient( get_site_url() );
3224 $http->setHeader( "X-NitroPack-Request", 1 );
3225 $http->timeout = 25;
3226 $http->fetch();
3227 $headers = $http->getHeaders();
3228 if ( ! empty( $headers["content-encoding"] ) && strtolower( $headers["content-encoding"] ) == "gzip" ) { // compression is present, so there is no need to enable it in NitroPack. We only check for GZIP, because this is the only supported compression in the HttpClient
3229 $updated = update_option( "nitropack-enableCompression", 0 );
3230 $hasCompression = true;
3231 } else { // no compression, we must enable it from NitroPack
3232 $updated = update_option( "nitropack-enableCompression", 1 );
3233 $hasCompression = false;
3234 }
3235 }
3236 update_option( "nitropack-checkedCompression", 1 );
3237 } catch (\Exception $e) {
3238 nitropack_json_and_exit( array( "type" => "error", "message" => nitropack_admin_toast_msgs( 'error' ) ) );
3239 }
3240 if ( $updated )
3241 nitropack_json_and_exit( array( "type" => "success", "message" => nitropack_admin_toast_msgs( 'success' ), "hasCompression" => $hasCompression ) );
3242 }
3243
3244 function nitropack_render_woocommerce_cart_cache_option() {
3245 return class_exists( 'WooCommerce' );
3246 }
3247
3248 function nitropack_is_cart_cache_active() {
3249 $nitro = get_nitropack()->getSdk();
3250 if ( $nitro ) {
3251 $config = $nitro->getConfig();
3252 if ( ! empty( $config->StatefulCache->Status ) && ! empty( $config->StatefulCache->CartCache ) ) {
3253 return nitropack_is_cart_cache_available();
3254 }
3255 }
3256 return false;
3257 }
3258
3259 function nitropack_is_cart_cache_available() {
3260 $nitro = get_nitropack()->getSdk();
3261 if ( $nitro ) {
3262 $config = $nitro->getConfig();
3263 if ( ! empty( $config->StatefulCache->isCartCacheAvailable ) ) {
3264 return true;
3265 }
3266 }
3267 return false;
3268 }
3269
3270 function nitropack_handle_compression_toggle( $old_value, $new_value ) {
3271 nitropack_update_blog_compression( $new_value == 1 );
3272 }
3273
3274 function nitropack_update_blog_compression( $enableCompression = false ) {
3275 if ( get_nitropack()->isConnected() ) {
3276 $siteConfig = nitropack_get_site_config();
3277 $siteId = $siteConfig["siteId"];
3278 $siteSecret = $siteConfig["siteSecret"];
3279 $blogId = get_current_blog_id();
3280 get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId, $enableCompression );
3281 }
3282 }
3283
3284 function nitropack_enable_warmup() {
3285 nitropack_verify_ajax_nonce( $_REQUEST );
3286 $append = '';
3287 if ( nitropack_is_wp_cli() )
3288 $append = '[CLI] ';
3289 if ( null !== $nitro = get_nitropack_sdk() ) {
3290 try {
3291 $nitro->getApi()->enableWarmup();
3292 $nitro->getApi()->setWarmupHomepage( get_home_url() );
3293 $nitro->getApi()->runWarmup();
3294 } catch (\Exception $e) {
3295 }
3296 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Cache warmup is enabled' );
3297 nitropack_json_and_exit( array(
3298 "type" => "success",
3299 "message" => __( 'Cache warmup has been enabled successfully!', 'nitropack' )
3300 ) );
3301 }
3302 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Cache warmup cannot be enabled' );
3303 nitropack_json_and_exit( array(
3304 "type" => "error",
3305 "message" => __( 'There was an error while enabling the cache warmup!', 'nitropack' )
3306 ) );
3307 }
3308
3309 function nitropack_disable_warmup() {
3310 nitropack_verify_ajax_nonce( $_REQUEST );
3311 if ( null !== $nitro = get_nitropack_sdk() ) {
3312 try {
3313 $nitro->getApi()->disableWarmup();
3314 $nitro->getApi()->resetWarmup();
3315 delete_option( 'nitropack-warmup-sitemap' );
3316 } catch (\Exception $e) {
3317 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Cache warmup cannot be disabled. Error: ' . $e->getTraceAsString() );
3318 }
3319 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Cache warmup is disabled' );
3320 nitropack_json_and_exit( array(
3321 "type" => "success",
3322 "message" => __( 'Cache warmup has been disabled successfully!', 'nitropack' )
3323 ) );
3324 }
3325 nitropack_json_and_exit( array(
3326 "type" => "error",
3327 "message" => __( 'There was an error while disabling the cache warmup!', 'nitropack' )
3328 ) );
3329 }
3330
3331 function nitropack_run_warmup() {
3332 nitropack_verify_ajax_nonce( $_REQUEST );
3333
3334 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Running warmup' );
3335
3336 if ( null !== $nitro = get_nitropack_sdk() ) {
3337 try {
3338 $nitro->getApi()->runWarmup();
3339 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Cache warmup has been started' );
3340 nitropack_json_and_exit( array(
3341 "type" => "success",
3342 "message" => __( 'Success! Cache warmup has been started successfully!', 'nitropack' )
3343 ) );
3344 } catch (\Exception $e) {
3345 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'There was an error while starting the cache warmup. Error: ' . $e->getTraceAsString() );
3346 }
3347 }
3348
3349 nitropack_json_and_exit( array(
3350 "type" => "error",
3351 "message" => __( 'Error! There was an error while starting the cache warmup!', 'nitropack' )
3352 ) );
3353 }
3354
3355 function nitropack_estimate_warmup() {
3356 nitropack_verify_ajax_nonce( $_REQUEST );
3357 if ( null !== $nitro = get_nitropack_sdk() ) {
3358 try {
3359 if ( ! session_id() ) {
3360 session_start();
3361 }
3362 $id = ! empty( $_POST["estId"] ) ? preg_replace( "/[^a-fA-F0-9]/", "", (string) $_POST["estId"] ) : NULL;
3363 if ( $id !== NULL && ( ! is_string( $id ) || $id != $_SESSION["nitroEstimateId"] ) ) {
3364 nitropack_json_and_exit( array(
3365 "type" => "error",
3366 "message" => __( 'Invalid estimation ID!', 'nitropack' )
3367 ) );
3368 }
3369
3370 $sitemapUrls = nitropack_active_sitemap_plugins() ? nitropack_get_site_maps() : NULL;
3371 $configuredSitemap = false;
3372
3373 if ( $sitemapUrls === NULL ) {
3374
3375 $defaultSitemap = get_default_sitemap();
3376 if ( $defaultSitemap ) {
3377 $nitro->getApi()->setWarmupSitemap( $defaultSitemap );
3378 $configuredSitemap = true;
3379 }
3380
3381 delete_option( 'nitropack-warmup-sitemap' );
3382 } else {
3383
3384 $warmupSitemap = evaluate_warmup_sitemap( $sitemapUrls );
3385 if ( $warmupSitemap ) {
3386 $nitro->getApi()->setWarmupSitemap( $warmupSitemap );
3387 $configuredSitemap = true;
3388 }
3389 }
3390
3391 if ( ! $configuredSitemap ) {
3392 $nitro->getApi()->setWarmupSitemap( NULL );
3393 }
3394
3395 $nitro->getApi()->setWarmupHomepage( get_home_url() );
3396
3397 $optimizationsEstimate = $nitro->getApi()->estimateWarmup( $id );
3398
3399 if ( $id === NULL ) {
3400 $_SESSION["nitroEstimateId"] = $optimizationsEstimate; // When id is NULL, $optimizationsEstimate holds the ID for the newly started estimate
3401 }
3402 } catch (\Exception $e) {
3403 }
3404 $json_data = array(
3405 "type" => "success",
3406 "res" => $optimizationsEstimate,
3407 "sitemap_indication" => get_option( 'nitropack-warmup-sitemap', false ),
3408 "message" => __( 'Warmup estimation failed.', 'nitropack' ),
3409 );
3410 if ( is_int( $optimizationsEstimate ) && $optimizationsEstimate > 0 ) {
3411 $json_data["message"] = __( 'Cache warmup has been estimated successfully.', 'nitropack' );
3412 } else if ( $optimizationsEstimate === 0 ) {
3413 $json_data["message"] = __( 'We could not find any links for warming up on your home page.', 'nitropack' );
3414 } else {
3415 $json_data["message"] = __( 'Warmup estimation failed. Please try again or contact support if the issue persists', 'nitropack' );
3416 }
3417 nitropack_json_and_exit( $json_data );
3418 }
3419
3420 nitropack_json_and_exit( array(
3421 "type" => "error",
3422 "message" => __( 'Warmup estimation failed.', 'nitropack' )
3423 ) );
3424 }
3425
3426 function nitropack_warmup_stats() {
3427 nitropack_verify_ajax_nonce( $_REQUEST );
3428 if ( null !== $nitro = get_nitropack_sdk() ) {
3429 try {
3430 $stats = $nitro->getApi()->getWarmupStats();
3431 } catch (\Exception $e) {
3432 nitropack_json_and_exit( array(
3433 "type" => "error",
3434 "message" => __( 'Error! There was an error while fetching warmup stats!', 'nitropack' )
3435 ) );
3436 }
3437
3438 nitropack_json_and_exit( array(
3439 "type" => "success",
3440 "stats" => $stats
3441 ) );
3442 }
3443
3444
3445 nitropack_json_and_exit( array(
3446 "type" => "error",
3447 "message" => __( 'Error! There was an error while fetching warmup stats!', 'nitropack' )
3448 ) );
3449 }
3450
3451
3452 function nitropack_enable_cart_cache() {
3453 if ( null !== $nitro = get_nitropack_sdk() ) {
3454 try {
3455 $nitro->enableCartCache();
3456 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Cart cache is enabled' );
3457 nitropack_json_and_exit( array(
3458 "type" => "success",
3459 "message" => nitropack_admin_toast_msgs( 'success' )
3460 ) );
3461 } catch (\Exception $e) {
3462 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Cart cache cannot be enabled. Error: ' . $e );
3463 }
3464 }
3465
3466 nitropack_json_and_exit( array(
3467 "type" => "error",
3468 "message" => nitropack_admin_toast_msgs( 'error' )
3469 ) );
3470 }
3471
3472 function nitropack_disable_cart_cache() {
3473 if ( null !== $nitro = get_nitropack_sdk() ) {
3474 try {
3475 $nitro->disableCartCache();
3476 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->notice( 'Cart cache is be disabled' );
3477 nitropack_json_and_exit( array(
3478 "type" => "success",
3479 "message" => nitropack_admin_toast_msgs( 'success' )
3480 ) );
3481 } catch (\Exception $e) {
3482 NitroPack\WordPress\NitroPack::getInstance()->getLogger()->error( 'Cart cache cannot be disabled. Error: ' . $e );
3483 }
3484 }
3485
3486 nitropack_json_and_exit( array(
3487 "type" => "error",
3488 "message" => nitropack_admin_toast_msgs( 'error' )
3489 ) );
3490 }
3491
3492
3493
3494 function nitropack_get_site_config() {
3495 return get_nitropack()->getSiteConfig();
3496 }
3497
3498 function nitropack_get_current_site_id() {
3499
3500 $site_config = nitropack_get_site_config();
3501
3502 if ( $site_config && isset( $site_config['siteId'] ) ) {
3503 return $site_config['siteId'];
3504 }
3505 }
3506
3507 function get_nitropack() {
3508 return \NitroPack\WordPress\NitroPack::getInstance();
3509 }
3510
3511 function nitropack_event( $event, $nitro = null, $additional_meta_data = null ) {
3512 global $wp_version;
3513
3514 try {
3515 $eventUrl = get_nitropack_integration_url( "extensionEvent", $nitro );
3516 $domain = ! empty( $_SERVER["HTTP_HOST"] ) ? $_SERVER["HTTP_HOST"] : "Unknown";
3517
3518
3519 if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
3520 $platform = 'WooCommerce';
3521 } else {
3522 $platform = 'WordPress';
3523 }
3524
3525 $query_data = array(
3526 'event' => $event,
3527 'platform' => $platform,
3528 'platform_version' => $wp_version,
3529 'nitropack_extension_version' => NITROPACK_VERSION,
3530 'additional_meta_data' => $additional_meta_data ? json_encode( $additional_meta_data ) : "{}",
3531 'domain' => $domain
3532 );
3533
3534 $client = new NitroPack\HttpClient\HttpClient( $eventUrl . '&' . http_build_query( $query_data ) );
3535 $client->doNotDownload = true;
3536 $client->fetch();
3537 } catch (\Exception $e) {
3538 }
3539 }
3540
3541 function nitropack_get_wpconfig_path() {
3542 $configFilePath = nitropack_trailingslashit( ABSPATH ) . "wp-config.php";
3543 if ( ! file_exists( $configFilePath ) ) {
3544 $configFilePath = nitropack_trailingslashit( dirname( ABSPATH ) ) . "wp-config.php";
3545 $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.
3546 if ( ! file_exists( $configFilePath ) || file_exists( $settingsFilePath ) ) {
3547 return false;
3548 }
3549 }
3550
3551
3552 if ( ! is_writable( $configFilePath ) ) {
3553 return false;
3554 }
3555
3556 return $configFilePath;
3557 }
3558
3559 function nitropack_get_htaccess_path() {
3560 $configFilePath = nitropack_trailingslashit( ABSPATH ) . ".htaccess";
3561 if ( ! file_exists( $configFilePath ) ) {
3562 return false;
3563 }
3564
3565
3566 if ( ! is_writable( $configFilePath ) ) {
3567 return false;
3568 }
3569
3570 return $configFilePath;
3571 }
3572
3573 function nitropack_detect_hosting() {
3574 if ( \NitroPack\Integration\Hosting\Flywheel::detect() ) {
3575 return "flywheel";
3576 } else if ( \NitroPack\Integration\Hosting\Cloudways::detect() ) {
3577 return "cloudways";
3578 } else if ( \NitroPack\Integration\Hosting\WPEngine::detect() ) {
3579 return "wpengine";
3580 } else if ( \NitroPack\Integration\Hosting\SiteGround::detect() ) {
3581 return "siteground";
3582 } else if ( \NitroPack\Integration\Hosting\GoDaddyWPaaS::detect() ) {
3583 return "godaddy_wpaas";
3584 } else if ( \NitroPack\Integration\Hosting\GridPane::detect() ) {
3585 return "gridpane";
3586 } else if ( \NitroPack\Integration\Hosting\Kinsta::detect() ) {
3587 return "kinsta";
3588 } else if ( \NitroPack\Integration\Hosting\Closte::detect() ) {
3589 return "closte";
3590 } else if ( \NitroPack\Integration\Hosting\Pagely::detect() ) {
3591 return "pagely";
3592 } else if ( \NitroPack\Integration\Hosting\WPX::detect() ) {
3593 return "wpx";
3594 } else if ( \NitroPack\Integration\Hosting\Vimexx::detect() ) {
3595 return "vimexx";
3596 } else if ( \NitroPack\Integration\Hosting\Pressable::detect() ) {
3597 return "pressable";
3598 } else if ( \NitroPack\Integration\Hosting\RocketNet::detect() ) {
3599 return "rocketnet";
3600 } else if ( \NitroPack\Integration\Hosting\Savvii::detect() ) {
3601 return "savvii";
3602 } else if ( \NitroPack\Integration\Hosting\DreamHost::detect() ) {
3603 return "dreamhost";
3604 } else if ( \NitroPack\Integration\Hosting\Raidboxes::detect() ) {
3605 return "raidboxes";
3606 } else {
3607 return "unknown";
3608 }
3609 }
3610
3611 function nitropack_removeCacheBustParam( $content ) {
3612 $content = preg_replace( "/(\?|%26|&#0?38;|&#x0?26;|&(amp;)?)ignorenitro(%3D|=)[a-fA-F0-9]{32}(?!%26|&#0?38;|&#x0?26;|&(amp;)?)\/?/mu", "", $content );
3613 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 );
3614 }
3615
3616 function nitropack_handle_request( $servedFrom = "unknown" ) {
3617
3618 global $np_integrationSetupEvent;
3619
3620 if ( isset( $_GET["ignorenitro"] ) ) {
3621 unset( $_GET["ignorenitro"] );
3622 }
3623
3624 if ( defined( "NITROPACK_STRIP_IGNORENITRO" ) && NITROPACK_STRIP_IGNORENITRO && $_SERVER['REQUEST_URI'] != '' ) {
3625 $_SERVER['REQUEST_URI'] = nitropack_removeCacheBustParam( $_SERVER['REQUEST_URI'] );
3626 }
3627
3628 nitropack_header( 'Cache-Control: no-cache' );
3629 do_action( "nitropack_early_cache_headers" ); // Overrides the Cache-Control header on supported platforms
3630 $isManageWpRequest = ! empty( $_GET["mwprid"] );
3631 $isWpCli = nitropack_is_wp_cli();
3632
3633 if ( file_exists( NITROPACK_CONFIG_FILE ) && ! empty( $_SERVER["HTTP_HOST"] ) && ! empty( $_SERVER["REQUEST_URI"] ) && ! $isManageWpRequest && ! $isWpCli ) {
3634 try {
3635 $siteConfig = nitropack_get_site_config();
3636 if ( $siteConfig && null !== $nitro = get_nitropack_sdk( $siteConfig["siteId"], $siteConfig["siteSecret"] ) ) {
3637 if ( is_valid_nitropack_webhook() ) {
3638 nitropack_handle_webhook();
3639 } else if ( is_valid_nitropack_beacon() ) {
3640 nitropack_handle_beacon();
3641 } else if ( is_valid_nitropack_heartbeat() ) {
3642 nitropack_handle_heartbeat();
3643 } else {
3644 $GLOBALS["NitroPack.instance"] = $nitro;
3645
3646 if ( nitropack_passes_cookie_requirements() || ( nitropack_is_ajax() && ! empty( $_COOKIE["nitroCachedPage"] ) ) ) {
3647 // Check whether the current URL is cacheable
3648 // 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.
3649 // If we are not checking the referer, the AJAX requests on these pages can fail.
3650 $urlToCheck = nitropack_is_ajax() && ! empty( $_SERVER["HTTP_REFERER"] ) ? $_SERVER["HTTP_REFERER"] : $nitro->getUrl();
3651 if ( $nitro->isAllowedUrl( $urlToCheck ) ) {
3652 add_filter( 'nonce_life', 'nitropack_extend_nonce_life' );
3653 }
3654 }
3655
3656 if ( nitropack_passes_cookie_requirements() && apply_filters( "nitropack_can_serve_cache", true ) ) {
3657 if ( $nitro->isCacheAllowed() ) {
3658 if ( ! nitropack_is_ajax() ) {
3659 do_action( "nitropack_cacheable_cache_headers" );
3660 }
3661
3662 if ( ! empty( $siteConfig["compression"] ) ) {
3663 $nitro->enableCompression();
3664 }
3665
3666 if ( $nitro->hasLocalCache() ) {
3667 // TODO: Make this work so we can provide the reverse proxies with this information $remainingTtl = $nitr->pageCache->getRemainingTtl();
3668 do_action( "nitropack_cachehit_cache_headers" ); // TODO: Pass the remaining TTL here
3669 $cacheControlOverride = defined( "NITROPACK_CACHE_CONTROL_OVERRIDE" ) ? NITROPACK_CACHE_CONTROL_OVERRIDE : NULL;
3670 if ( $cacheControlOverride ) {
3671 nitropack_header( 'Cache-Control: ' . $cacheControlOverride );
3672 }
3673
3674 nitropack_header( 'X-Nitro-Cache: HIT' );
3675 nitropack_header( 'X-Nitro-Cache-From: ' . $servedFrom );
3676 $cjHandler = new \NitroPack\SDK\Utils\CjHandler( $nitro );
3677 $cjHandler->handleQueryParams();
3678 $nitro->pageCache->readfile();
3679 exit;
3680 } else {
3681 // We need the following if..else block to handle bot requests which will not be firing our beacon
3682 if ( nitropack_is_warmup_request() ) {
3683 if ( ! empty( $_SERVER["HTTP_ACCEPT_LANGUAGE"] ) ) {
3684 add_action( "init", function () use ($nitro) {
3685 $nitro->hasRemoteCache( "default" ); // Only ping the API letting our service know that this page must be cached.
3686 exit;
3687 }, 9999 );
3688 return; // We need to wait for a language plugin (if present) to redirect
3689 } else {
3690 $nitro->hasRemoteCache( "default" ); // Only ping the API letting our service know that this page must be cached.
3691 exit; // No need to continue handling this request. The response is not important.
3692 }
3693 } else if ( nitropack_is_lighthouse_request() || nitropack_is_gtmetrix_request() || nitropack_is_pingdom_request() ) {
3694 $nitro->hasRemoteCache( "default" ); // Ping the API letting our service know that this page must be cached.
3695 }
3696
3697 $nitro->pageCache->useInvalidated( true );
3698 if ( $nitro->hasLocalCache() ) {
3699 nitropack_header( 'X-Nitro-Cache: STALE' );
3700 nitropack_header( 'X-Nitro-Cache-From: ' . $servedFrom );
3701 $cjHandler = new \NitroPack\SDK\Utils\CjHandler( $nitro );
3702 $cjHandler->handleQueryParams();
3703 $nitro->pageCache->readfile();
3704 exit;
3705 } else {
3706 $nitro->pageCache->useInvalidated( false );
3707 }
3708 }
3709 }
3710 }
3711 }
3712 }
3713 } catch (\Exception $e) {
3714 // Do nothing, cache serving will be handled by nitropack_init
3715 }
3716 }
3717 }
3718
3719 function nitropack_is_dropin_cache_allowed() {
3720 $siteConfig = nitropack_get_site_config();
3721 return $siteConfig && empty( $siteConfig["isEzoicActive"] );
3722 }
3723
3724
3725
3726 function nitropack_admin_bar_menu( $wp_admin_bar ) {
3727 if ( nitropack_is_amp_page() )
3728 return;
3729 $notifications = get_nitropack()->Notifications;
3730 $counter_data = $notifications->admin_bar_notices_counter();
3731
3732 if ( ! get_nitropack()->isConnected() ) {
3733 $node = array(
3734 'id' => 'nitropack-top-menu',
3735 'title' => '&nbsp;&nbsp;<i style="" class="circle nitro nitro-status nitro-status-not-connected" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack is disconnected',
3736 'href' => admin_url( 'admin.php?page=nitropack' ),
3737 'meta' => array(
3738 'class' => 'nitropack-menu'
3739 )
3740 );
3741
3742 $wp_admin_bar->add_node(
3743 array(
3744 'parent' => 'nitropack-top-menu',
3745 'id' => 'optimizations-plugin-status',
3746 'title' => __( 'Connect NitroPack&nbsp;&nbsp;', 'nitropack' ),
3747 'href' => admin_url( 'admin.php?page=nitropack' ),
3748 'meta' => array(
3749 'class' => 'nitropack-plugin-status',
3750 )
3751 )
3752 );
3753 } else {
3754 $title = '&nbsp;&nbsp;<i style="" class="circle nitro nitro-status nitro-status-' . $counter_data['status'] . '" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack';
3755 if ( $counter_data['status'] != "ok" ) {
3756 $title .= ' <span class="circle-with-text nitro-color-issues" id="nitro-total-issues-count">' . ( $counter_data['issues'] + $counter_data['notifications'] ) . '</span>';
3757 } else if ( $counter_data['notifications'] > 0 ) {
3758 $title .= ' <span class="circle-with-text nitro-color-notification" id="nitro-total-issues-count">' . $counter_data['notifications'] . '</span>';
3759 }
3760 $node = array(
3761 'id' => 'nitropack-top-menu',
3762 'title' => $title,
3763 'href' => admin_url( 'admin.php?page=nitropack' ),
3764 'meta' => array(
3765 'class' => 'nitropack-menu'
3766 )
3767 );
3768
3769 $settings_extra = '';
3770 if ( $counter_data['notifications'] ) {
3771 $settings_extra .= ' <span class="circle-with-text nitro-color-notification" id="nitro-notification-issues-count">' . $counter_data['notifications'] . '</span>';
3772 }
3773 $wp_admin_bar->add_node( array(
3774 'id' => 'nitropack-top-menu-settings',
3775 'parent' => 'nitropack-top-menu',
3776 'title' => __( 'Settings', 'nitropack' ) . ' ' . $settings_extra . '',
3777 'href' => admin_url( 'admin.php?page=nitropack' ),
3778 'meta' => array(
3779 'class' => 'nitropack-settings'
3780 )
3781
3782 ) );
3783
3784 $wp_admin_bar->add_node(
3785 array(
3786 'id' => 'nitropack-top-menu-purge-entire-cache',
3787 'parent' => 'nitropack-top-menu',
3788 'title' => __( 'Purge Entire Cache', 'nitropack' ),
3789 'href' => '#',
3790 'meta' => array(
3791 'class' => 'nitropack-purge-cache-entire-site',
3792 ),
3793 )
3794 );
3795
3796 if ( ! is_admin() ) { // menu otions available when browsing front-end pages
3797
3798 $wp_admin_bar->add_node(
3799 array(
3800 'parent' => 'nitropack-top-menu',
3801 'id' => 'optimizations-purge-cache',
3802 'title' => __( 'Purge Current Page', 'nitropack' ),
3803 'href' => "#",
3804 'meta' => array(
3805 'class' => 'nitropack-purge-cache',
3806 )
3807 )
3808 );
3809
3810 $wp_admin_bar->add_node(
3811 array(
3812 'parent' => 'nitropack-top-menu',
3813 'id' => 'optimizations-invalidate-cache',
3814 'title' => __( 'Invalidate Current Page', 'nitropack' ),
3815 'href' => "#",
3816 'meta' => array(
3817 'class' => 'nitropack-invalidate-cache',
3818 )
3819 )
3820 );
3821 }
3822
3823 if ( $counter_data['status'] != "ok" ) {
3824 $wp_admin_bar->add_node(
3825 array(
3826 'parent' => 'nitropack-top-menu',
3827 'id' => 'optimizations-plugin-status',
3828 'title' => 'Issues <span class="circle-with-text nitro-color-issues">' . $counter_data['issues'] . '</span>',
3829 'href' => admin_url( 'admin.php?page=nitropack' ),
3830 'meta' => array(
3831 'class' => 'nitropack-plugin-status',
3832 )
3833 )
3834 );
3835 }
3836 }
3837
3838 $wp_admin_bar->add_node( $node );
3839 }
3840
3841 function nitropack_admin_bar_script( $hook ) {
3842 if ( ! nitropack_is_amp_page() ) {
3843 wp_enqueue_script( 'nitropack_admin_bar_menu_script', plugin_dir_url( __FILE__ ) . 'view/javascript/admin_bar_menu.js?np_v=' . NITROPACK_VERSION, [ 'jquery' ], false, true );
3844 wp_localize_script( 'nitropack_admin_bar_menu_script', 'frontendajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'nitroNonce' => wp_create_nonce( NITROPACK_NONCE ), 'nitro_plugin_url' => plugin_dir_url( __FILE__ ) ) );
3845 }
3846 }
3847
3848
3849 function enqueue_nitropack_admin_bar_menu_stylesheet() {
3850 if ( ! nitropack_is_amp_page() ) {
3851 wp_enqueue_style( 'nitropack_admin_bar_menu_stylesheet', plugin_dir_url( __FILE__ ) . 'view/stylesheet/admin_bar_menu.min.css?np_v=' . NITROPACK_VERSION );
3852 }
3853 }
3854
3855 function nitropack_cookiepath() {
3856 $siteConfig = nitropack_get_site_config();
3857 $homeUrl = $siteConfig && ! empty( $siteConfig["home_url"] ) ? $siteConfig["home_url"] : get_home_url();
3858 $url = new \NitroPack\Url\Url( $homeUrl );
3859 return $url ? $url->getPath() : "/";
3860 }
3861
3862 function nitropack_setcookie( $name, $value, $expires = NULL, $options = [] ) {
3863 if ( headers_sent() )
3864 return;
3865 $cookie_options = '';
3866 $cookie_path = nitropack_cookiepath();
3867
3868 if ( $expires && is_numeric( $expires ) ) {
3869 $options["Expires"] = date( "D, d M Y H:i:s", (int) $expires ) . ' GMT';
3870 }
3871
3872 if ( empty( $options["SameSite"] ) ) {
3873 $options["SameSite"] = "Lax";
3874 }
3875
3876 foreach ( $options as $optName => $optValue ) {
3877 $cookie_options .= "$optName=$optValue; ";
3878 }
3879 nitropack_header( "set-cookie: $name=$value; Path=$cookie_path; " . $cookie_options, false );
3880 }
3881
3882 function nitropack_header( $header, $replace = true, $response_code = 0 ) {
3883 if ( ! nitropack_is_wp_cron() && ! nitropack_is_wp_cli() ) {
3884 header( $header, $replace, $response_code );
3885 }
3886 }
3887
3888
3889 function nitropack_upgrade_handler( $entity ) {
3890 $np = 'nitropack/main.php';
3891 $trigger = $entity;
3892 if ( $entity instanceof Plugin_Upgrader ) {
3893 $trigger = $entity->plugin_info();
3894 if ( ! is_plugin_active( $trigger ) ) {
3895 return;
3896 }
3897 }
3898
3899 if ( $entity instanceof Theme_Upgrader ) {
3900 if ( $entity->theme_info()->Name === wp_get_theme()->Name ) {
3901 nitropack_theme_handler( 'Theme updated' );
3902 }
3903 return;
3904 }
3905
3906 if ( $trigger !== $np ) {
3907 $cookie_expires = date( "D, d M Y H:i:s", time() + 600 ) . ' GMT';
3908 nitropack_setcookie( 'nitropack_apwarning', "1", time() + 600 );
3909 }
3910 }
3911 /**
3912 * Caches some options in the config so that we can access them before get_option() is defined
3913 * which is in advanced_cache.php, functions.php and Integrations
3914 */
3915 function nitropack_updated_option( $option, $oldValue, $value ) {
3916 $neededOptions = \NitroPack\WordPress\NitroPack::$optionsToCache;
3917 if ( ! in_array( $option, $neededOptions ) )
3918 return;
3919
3920 $np = get_nitropack();
3921 $siteConfig = $np->Config->get();
3922
3923 if ( function_exists( 'get_home_url' ) ) {
3924 $configKey = \NitroPack\WordPress\NitroPack::getConfigKey();
3925 $siteConfig[ $configKey ]['options_cache'][ $option ] = $value;
3926 $np->Config->set( $siteConfig );
3927 }
3928 }
3929
3930 function nitropack_is_late_integration_init_required() {
3931 return \NitroPack\Integration\Plugin\NginxHelper::isActive() || \NitroPack\Integration\Plugin\Cloudflare::isApoActive();
3932 }
3933
3934 function nitropack_get_notice_id( $message ) {
3935 return md5( $message );
3936 }
3937
3938 function nitropack_active_sitemap_plugins() {
3939 return
3940 NitroPack\Integration\Plugin\YoastSEO::isActive() ||
3941 NitroPack\Integration\Plugin\JetPackNP::isActive() ||
3942 NitroPack\Integration\Plugin\SquirrlySEO::isActive() ||
3943 NitroPack\Integration\Plugin\RankMathNP::isActive();
3944 }
3945
3946 function nitropack_get_site_maps() {
3947 $sitemapUrls['YoastSEO'] = NitroPack\Integration\Plugin\YoastSEO::getSitemapURL();
3948 $sitemapUrls['JetPack'] = NitroPack\Integration\Plugin\JetPackNP::getSitemapURL();
3949 $sitemapUrls['SquirrlySEO'] = NitroPack\Integration\Plugin\SquirrlySEO::getSitemapURL();
3950 $sitemapUrls['RankMath'] = NitroPack\Integration\Plugin\RankMathNP::getSitemapURL();
3951
3952 return $sitemapUrls;
3953 }
3954
3955 function get_default_sitemap() {
3956
3957 $defaultSiteMap = NitroPack\Integration\Plugin\WPCacheHelper::getSitemapURL();
3958 if ( $defaultSiteMap ) {
3959 set_sitemap_indication_msg( 'WordPress', $defaultSiteMap );
3960 return $defaultSiteMap;
3961 }
3962
3963 return false;
3964 }
3965
3966 function evaluate_warmup_sitemap( $sitemapUrls ) {
3967
3968 $sitemapProviders = array(
3969 'YoastSEO' => 'Yoast!',
3970 'SquirrlySEO' => 'Squirrly SEO',
3971 'RankMath' => 'Rank Math',
3972 'JetPack' => 'Jetpack',
3973 );
3974
3975 foreach ( $sitemapProviders as $provider => $name ) {
3976 if ( isset( $sitemapUrls[ $provider ] ) && $sitemapUrls[ $provider ] ) {
3977 set_sitemap_indication_msg( $name, $sitemapUrls[ $provider ] );
3978 return $sitemapUrls[ $provider ];
3979 }
3980 }
3981
3982 return get_default_sitemap();
3983 }
3984
3985 function set_sitemap_indication_msg( $pluginName, $sitemapURL ) {
3986 $sitemapURI = explode( "/", parse_url( $sitemapURL, PHP_URL_PATH ) );
3987 $msg = $sitemapURI[1] . ' used by ' . $pluginName;
3988 update_option( 'nitropack-warmup-sitemap', $msg );
3989 }
3990
3991 function get_date_midpoint( $endDate ) {
3992 return ( time() + strtotime( $endDate ) ) / 2;
3993 }
3994
3995
3996 function initVariationCookies( $customVariationCookies ) {
3997 $api = get_nitropack_sdk()->getApi();
3998 try {
3999 $variationCookies = $api->getVariationCookies();
4000 foreach ( $variationCookies as $cookie ) {
4001 $index = array_search( $cookie["name"], $customVariationCookies );
4002 if ( $index !== false ) {
4003 array_splice( $customVariationCookies, $index, 1 );
4004 }
4005 }
4006
4007 foreach ( $customVariationCookies as $cookieName ) {
4008 $api->setVariationCookie( $cookieName );
4009 }
4010 } catch (\Exception $e) {
4011 // what to do here? possible reason for exception is the API not responding
4012 return false;
4013 }
4014 }
4015
4016 function removeVariationCookies( $cookiesToRemove ) {
4017 $api = get_nitropack_sdk()->getApi();
4018 try {
4019 $variationCookies = $api->getVariationCookies();
4020 foreach ( $variationCookies as $cookie ) {
4021 if ( in_array( $cookie["name"], $cookiesToRemove ) ) {
4022 $api->unsetVariationCookie( $cookie["name"] );
4023 }
4024 }
4025 } catch (\Exception $e) {
4026 // what to do here? possible reason for exception is the API not responding
4027 return false;
4028 }
4029 }
4030
4031 function getNewCookie( $name ) {
4032 $cookies = getNewCookies();
4033 return ! empty( $cookies[ $name ] ) ? $cookies[ $name ] : null;
4034 }
4035
4036 /**
4037 * Returns an array of newly set cookies (not in $_COOKIE), that will be sent along with the headers of the current response.
4038 */
4039 function getNewCookies() {
4040 $cookies = [];
4041 $headers = headers_list();
4042 foreach ( $headers as $header ) {
4043 if ( strpos( $header, 'Set-Cookie: ' ) === 0 ) {
4044 $value = str_replace( '&', urlencode( '&' ), substr( $header, 12 ) );
4045 parse_str( current( explode( ';', $value ) ), $pair );
4046 $cookies = array_merge_recursive( $cookies, $pair );
4047 }
4048 }
4049
4050 return array_filter( array_map( function ( $val ) {
4051 if ( is_array( $val ) ) {
4052 $lastEl = end( $val );
4053 if ( is_array( $lastEl ) ) {
4054 return NULL;
4055 }
4056 return $lastEl;
4057 }
4058
4059 return $val;
4060 }, $cookies ) );
4061 }
4062
4063 /**
4064 * Purge entire cache when permalink structure is changed.
4065 *
4066 * @param string $old_permalink_structure The previous permalink structure.
4067 * @param string $permalink_structure The new permalink structure.
4068 *
4069 * @return void
4070 */
4071 function nitropack_permalink_structure_changed_handler( $old_permalink_structure, $permalink_structure ) {
4072
4073 if ( $old_permalink_structure != $permalink_structure && get_option( "nitropack-autoCachePurge", 1 ) ) {
4074 $msg = 'The permalink structure is changed. Purging the cache for the home page.';
4075 $url = get_home_url();
4076
4077 try {
4078 nitropack_sdk_purge( $url, NULL, $msg ); // purge cache for the home page
4079 } catch (\Exception $e) {
4080 }
4081
4082 // run warmup
4083 if ( null !== $nitro = get_nitropack_sdk() ) {
4084 try {
4085 $nitro->getApi()->runWarmup();
4086 } catch (\Exception $e) {
4087 }
4088 }
4089 }
4090 }
4091
4092 add_action( 'permalink_structure_changed', 'nitropack_permalink_structure_changed_handler', 10, 2 );
4093
4094 /**
4095 * Purge entire cache when front page is changed.
4096 *
4097 * @param array $old_value An array of previous settings values.
4098 * @param array $value An array of submitted settings values.
4099 *
4100 * @return void
4101 */
4102 function nitropack_frontpage_changed_handler( $old_value, $value ) {
4103
4104 if ( $old_value !== $value ) {
4105 $msg = 'The front page is changed';
4106 $url = get_home_url();
4107
4108 try {
4109 nitropack_sdk_purge( $url, NULL, $msg ); // purge entire cache
4110 } catch (\Exception $e) {
4111 }
4112 }
4113 }
4114
4115 add_action( 'update_option_show_on_front', 'nitropack_frontpage_changed_handler', 10, 2 );
4116 add_action( 'update_option_page_on_front', 'nitropack_frontpage_changed_handler', 10, 2 );
4117 add_action( 'update_option_page_for_posts', 'nitropack_frontpage_changed_handler', 10, 2 );
4118
4119 // Init integration action handlers
4120 $modHandler = NitroPack\ModuleHandler::getInstance();
4121 $modHandler->init();
4122