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