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