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