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