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