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