PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.15.3
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.15.3
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / functions.php
nitropack Last commit date
classes 2 years ago languages 2 years ago nitropack-sdk 2 years ago view 2 years ago advanced-cache.php 2 years ago batcache-compat.php 4 years ago constants.php 2 years ago diagnostics.php 2 years ago functions.php 2 years ago helpers.php 3 years ago main.php 2 years ago readme.txt 2 years ago uninstall.php 2 years ago wp-cli.php 2 years ago
functions.php
4212 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 delete_transient($post_id . '_np_first_publish');
2317 } catch (\Exception $e) {
2318 // TODO: Log the error
2319 }
2320 }
2321
2322 function nitropack_postmeta_updated($meta_id, $object_id, $meta_key, $meta_value) {
2323 if ($meta_key !== '_edit_lock') {
2324 if (get_post_type($object_id) === 'product') {
2325 !defined('NITROPACK_PURGE_PRODUCT') && define('NITROPACK_PURGE_PRODUCT', true);
2326 }
2327 }
2328 }
2329
2330 function nitropack_sot($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) {
2331 if (!get_option("nitropack-autoCachePurge", 1)) return;
2332
2333 $post = get_post($object_id);
2334 $post_status = $post->post_status;
2335
2336 if ($post_status === 'auto-draft' || $post_status === 'draft') {
2337 return;
2338 }
2339
2340 if (!defined('NITROPACK_PURGE_CACHE')) {
2341 $purgeCache = !nitropack_compare_posts($tt_ids, $old_tt_ids);
2342 $cleanCache = $purgeCache ? "YES" : "NO";
2343 if ($purgeCache) {
2344 $post = get_post($object_id);
2345 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink($post);
2346 nitropack_clean_post_cache($post);
2347 define('NITROPACK_PURGE_CACHE', true);
2348 }
2349 }
2350 }
2351
2352 function nitropack_handle_product_updates($product, $updated) {
2353 if (!get_option("nitropack-autoCachePurge", 1)) return;
2354
2355 if (!defined('NITROPACK_PURGE_CACHE') && defined('NITROPACK_PURGE_PRODUCT')) {
2356 try {
2357 $post = get_post($product->get_id());
2358 $reasons = 'updated ';
2359 $reasons .= implode(',', $updated);
2360 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink($post);
2361 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
2362 define('NITROPACK_PURGE_CACHE', true);
2363 } catch (\Exception $e) {
2364 // TODO: Log the error
2365 }
2366 }
2367 }
2368
2369 function nitropack_post_link_listener($permalink, $post, $leavename) {
2370 if (is_object($post)) {
2371 nitropack_handle_the_post($post);
2372 }
2373
2374 return $permalink;
2375 }
2376
2377 function nitropack_handle_the_post($post) {
2378 global $np_customExpirationTimes, $np_queriedObj;
2379 if (defined('POSTEXPIRATOR_VERSION')) {
2380 $postExpiryDate = get_post_meta($post->ID, "_expiration-date", true);
2381 if (!empty($postExpiryDate) && $postExpiryDate > time()) { // We only need to look at future dates
2382 $np_customExpirationTimes[] = $postExpiryDate;
2383 }
2384 }
2385
2386 if (function_exists("sort_portfolio")) { // Portfolio Sorting plugin
2387 $portfolioStartDate = get_post_meta($post->ID, "start_date", true);
2388 $portfolioEndDate = get_post_meta($post->ID, "end_date", true);
2389 if (!empty($portfolioStartDate) && strtotime($portfolioStartDate) > time()) { // We only need to look at future dates
2390 $np_customExpirationTimes[] = strtotime($portfolioStartDate);
2391 } else if (!empty($portfolioEndDate) && strtotime($portfolioEndDate) > time()) { // We only need to look at future dates
2392 $np_customExpirationTimes[] = strtotime($portfolioEndDate);
2393 }
2394 }
2395
2396 $GLOBALS["NitroPack.tags"]["post:" . $post->ID] = 1;
2397 $GLOBALS["NitroPack.tags"]["author:" . $post->post_author] = 1;
2398 if ($np_queriedObj) {
2399 $GLOBALS["NitroPack.tags"]["taxpost:" . $np_queriedObj->term_taxonomy_id . ":" . $post->ID] = 1;
2400 }
2401 }
2402
2403 function nitropack_ignore_post_updates($postID) {
2404 \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs[] = $postID;
2405 }
2406
2407 function nitropack_get_taxonomies($post) {
2408 $term_taxonomy_ids = array();
2409 $taxonomies = get_object_taxonomies($post->post_type);
2410 foreach ($taxonomies as $taxonomy) {
2411 $terms = get_the_terms($post->ID, $taxonomy);
2412 if (!empty($terms)) {
2413 foreach ($terms as $term) {
2414 $term_taxonomy_ids[] = $term->term_taxonomy_id;
2415 }
2416 }
2417 }
2418 return $term_taxonomy_ids;
2419 }
2420
2421 function nitropack_get_taxonomies_for_update($post) {
2422 $prevTaxonomies = nitropack_get_taxonomies_pre_update($post);
2423 $newTaxonomies = nitropack_get_taxonomies($post);
2424 $intersection = array_intersect($newTaxonomies, $prevTaxonomies);
2425 $prevTaxonomies = array_diff($prevTaxonomies, $intersection);
2426 $newTaxonomies = array_diff($newTaxonomies, $intersection);
2427 return array(
2428 "added" => array_diff($newTaxonomies, $prevTaxonomies),
2429 "deleted" => array_diff($prevTaxonomies, $newTaxonomies)
2430 );
2431 }
2432
2433 function nitropack_get_post_pre_update($post) {
2434 return !empty(\NitroPack\WordPress\NitroPack::$preUpdatePosts[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdatePosts[$post->ID] : NULL;
2435 }
2436
2437 function nitropack_get_taxonomies_pre_update($post) {
2438 return !empty(\NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$post->ID] : array();
2439 }
2440
2441 function nitropack_get_meta_pre_update($post) {
2442 return !empty(\NitroPack\WordPress\NitroPack::$preUpdateMeta[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdateMeta[$post->ID] : array();
2443 }
2444
2445 function nitropack_log_post_pre_update($postID) {
2446 if (in_array($postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs)) return;
2447
2448
2449 $post = get_post($postID);
2450 \NitroPack\WordPress\NitroPack::$preUpdatePosts[$postID] = $post;
2451 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$postID] = nitropack_get_taxonomies($post);
2452 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2453 \NitroPack\WordPress\NitroPack::$preUpdateMeta[$postID] = get_post_meta($postID);
2454 }
2455
2456 function nitropack_log_product_pre_api_update($product, $request, $creating) {
2457
2458 if (!$creating) {
2459
2460 $postID = $product->get_id();
2461 if (in_array($postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs)) return;
2462
2463
2464 $post = get_post($postID);
2465 \NitroPack\WordPress\NitroPack::$preUpdatePosts[$postID] = $post;
2466 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$postID] = nitropack_get_taxonomies($post);
2467 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2468 \NitroPack\WordPress\NitroPack::$preUpdateMeta[$postID] = get_post_meta($postID);
2469 }
2470
2471 return $product;
2472 }
2473
2474 function nitropack_compare_posts(array $p1, array $p2, $ignoredKeys = null) {
2475 $p1keys = array_keys($p1);
2476 $p2keys = array_keys($p2);
2477 if (count($p1keys) !== count($p2keys)) {
2478 return false;
2479 }
2480 if (array_diff($p1keys, $p2keys)) {
2481 return false;
2482 }
2483
2484 $isP1assoc = false;
2485 $expectedKey = 0;
2486 foreach ($p2 as $i => $_) {
2487 if ($i !== $expectedKey) {
2488 $isP1assoc = true;
2489 }
2490 $expectedKey++;
2491 }
2492
2493 $isP2assoc = false;
2494 $expectedKey = 0;
2495 foreach ($p2 as $i => $_) {
2496 if ($i !== $expectedKey) {
2497 $isP2assoc = true;
2498 }
2499 $expectedKey++;
2500 }
2501
2502 if ($isP1assoc !== $isP2assoc) {
2503 return false;
2504 }
2505
2506 if (!$isP1assoc && !$isP2assoc) {
2507 sort($p1);
2508 sort($p2);
2509 }
2510
2511 foreach ($p1 as $poKey => $poVal) {
2512 if ($ignoredKeys && in_array($poKey, $ignoredKeys, true)) {
2513 continue;
2514 }
2515 $checkpoint01 = is_array($poVal);
2516 $checkpoint02 = is_array($p2[$poKey]);
2517 if ($checkpoint01 && $checkpoint02) {
2518 if (!nitropack_compare_posts($poVal, $p2[$poKey], $ignoredKeys, 'Re:')) { //'Re:' left for debug purpose to destinguish between main and recursive call
2519 return false;
2520 }
2521 } elseif (!$checkpoint01 && !$checkpoint02) {
2522 if ($poVal != $p2[$poKey]) {
2523 return false;
2524 }
2525 } else {
2526 return false;
2527 }
2528 }
2529 return true;
2530 }
2531
2532 function nitropack_filter_tag($tag) {
2533 return preg_replace("/[^a-zA-Z0-9:]/", ":", $tag);
2534 }
2535
2536 function nitropack_log_tags() {
2537 if (!empty($GLOBALS["NitroPack.instance"]) && !empty($GLOBALS["NitroPack.tags"])) {
2538 $nitro = $GLOBALS["NitroPack.instance"];
2539 $layout = nitropack_get_layout();
2540 try {
2541 if ($layout == "home") {
2542 $nitro->getApi()->tagUrl($nitro->getUrl(), "pageType:home");
2543 } else if ($layout == "archive") {
2544 $nitro->getApi()->tagUrl($nitro->getUrl(), "pageType:archive");
2545 } else {
2546 $nitro->getApi()->tagUrl($nitro->getUrl(), array_map("nitropack_filter_tag", array_keys($GLOBALS["NitroPack.tags"])));
2547 }
2548 } catch (\Exception $e) {
2549 }
2550 }
2551 }
2552
2553 function nitropack_extend_nonce_life($life) {
2554 // Nonce life should be extended only:
2555 // - if NitroPack is connected for this site
2556 // - if the current value is shorter than the life time of a cache file
2557 // - if no user is logged in
2558 // - for cacheable requests
2559 //
2560 // Reasons why we might need to extend the nonce life time even for requests that are not cacheable:
2561 // - 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)
2562 // - 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.)
2563
2564 if ((null !== $nitro = get_nitropack_sdk())) {
2565 $siteConfig = nitropack_get_site_config();
2566 if ($siteConfig && !empty($siteConfig["isDlmActive"]) && !empty($siteConfig["dlm_downloading_url"]) && !empty($siteConfig["dlm_download_endpoint"])) {
2567 $currentUrl = $nitro->getUrl();
2568 if (strpos($currentUrl, $siteConfig["dlm_downloading_url"]) !== false || strpos($currentUrl, $siteConfig["dlm_download_endpoint"]) !== false) {
2569 // Do not modify the nonce times on pages of Download Monitor
2570 return $life;
2571 }
2572 }
2573 $cacheExpiration = $nitro->getConfig()->PageCache->ExpireTime;
2574 return $cacheExpiration > $life ? $cacheExpiration : $life; // Extend the life of cacheable nonces up to the cache expiration time if needed
2575 }
2576 return $life;
2577 }
2578
2579 function nitropack_reconfigure_webhooks() {
2580 nitropack_verify_ajax_nonce($_REQUEST);
2581 $siteConfig = nitropack_get_site_config();
2582
2583 if ($siteConfig && !empty($siteConfig["siteId"])) {
2584 $siteId = $siteConfig["siteId"];
2585 if (null !== $nitro = get_nitropack_sdk()) {
2586 $token = nitropack_generate_webhook_token($siteId);
2587 try {
2588 nitropack_setup_webhooks($nitro, $token);
2589 update_option("nitropack-webhookToken", $token);
2590 nitropack_json_and_exit(array("status" => "success", 'message' => __('Connection reconfigured successfully', 'nitropack')));
2591 } catch (\NitroPack\SDK\WebhookException $e) {
2592 nitropack_json_and_exit(array("status" => "error", "message" => __('Webhook Error: ', 'nitropack') . $e->getMessage()));
2593 }
2594 } else {
2595 nitropack_json_and_exit(array("status" => "error", "message" => __('Unable to get SDK instance', 'nitropack')));
2596 }
2597 } else {
2598 nitropack_json_and_exit(array("status" => "error", "message" => __('Incomplete site config. Please reinstall the plugin!', 'nitropack')));
2599 }
2600 }
2601
2602 function nitropack_generate_webhook_token($siteId) {
2603 return md5(__FILE__ . ":" . $siteId);
2604 }
2605
2606 function nitropack_verify_connect_ajax() {
2607 nitropack_verify_ajax_nonce($_REQUEST);
2608 $siteId = !empty($_POST["siteId"]) ? $_POST["siteId"] : "";
2609 $siteSecret = !empty($_POST["siteSecret"]) ? $_POST["siteSecret"] : "";
2610 nitropack_verify_connect($siteId, $siteSecret);
2611 }
2612
2613 function nitropack_check_func_availability($func_name) {
2614 if (function_exists('ini_get')) {
2615 $existsResult = stripos(ini_get('disable_functions'), $func_name) === false;
2616 } else {
2617 $existsResult = function_exists($func_name);
2618 }
2619 return $existsResult;
2620 }
2621
2622 function nitropack_prevent_connecting($nitroSDK) {
2623 $remoteUrl = $nitroSDK->getApi()->getWebhook("config");
2624 if (empty($remoteUrl)) {
2625 return false;
2626 }
2627 $siteConfig = nitropack_get_site_config();
2628 $localUrl = new \NitroPack\Url\Url($siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url());
2629 $localHome = strtolower($localUrl->getHost() . $localUrl->getPath());
2630 $storedUrl = new \NitroPack\Url\Url($remoteUrl);
2631 $remoteHome = strtolower($storedUrl->getHost() . $storedUrl->getPath());
2632 if ($localHome === $remoteHome) {
2633 return false;
2634 }
2635 return array('local' => $localHome, 'remote' => $remoteHome);
2636 }
2637
2638 function nitropack_verify_connect($siteId, $siteSecret) {
2639 if (!nitropack_check_func_availability('stream_socket_client')) {
2640 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>"));
2641 }
2642
2643 if (!nitropack_check_func_availability('stream_context_create')) {
2644 // <a href=\"https://support.nitropack.io/hc/en-us/articles/360020898137\" target=\"_blank\" rel=\"noreferrer noopener\">Read more</a>
2645 // ^ Similar article needed on website for stream_context_create function
2646 nitropack_json_and_exit(array("status" => "error", "message" => "stream_context_create function is not allowed by your host."));
2647 }
2648
2649 if (empty($siteId) || empty($siteSecret)) {
2650 nitropack_json_and_exit(array("status" => "error", "message" => __('API Key and API Secret Key cannot be empty', 'nitropack')));
2651 }
2652
2653 //remove tags and whitespaces
2654 $siteId = trim(esc_attr($siteId));
2655 $siteSecret = trim(esc_attr($siteSecret));
2656
2657 if (!nitropack_validate_site_id($siteId) || !nitropack_validate_site_secret($siteSecret)) {
2658 nitropack_json_and_exit(array("status" => "error", "message" => __('Invalid API Key or API Secret Key value', 'nitropack')));
2659 }
2660
2661 try {
2662 $blogId = get_current_blog_id();
2663 if (null !== $nitro = get_nitropack_sdk($siteId, $siteSecret, NULL, true)) {
2664 if (!$nitro->checkHealthStatus()) {
2665 nitropack_json_and_exit(array(
2666 "status" => "error",
2667 "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>."
2668 ));
2669 }
2670
2671 $preventParing = apply_filters('nitropack_prevent_connect', nitropack_prevent_connecting($nitro));
2672 if ($preventParing) {
2673 nitropack_json_and_exit(array(
2674 "status" => "error",
2675 "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/>
2676 <a href='https://support.nitropack.io/hc/en-us/articles/4405254569745' target='_blank' rel='noreferrer noopener'>Read more</a>"
2677 ));
2678 }
2679 $token = nitropack_generate_webhook_token($siteId);
2680 update_option("nitropack-webhookToken", $token);
2681 update_option("nitropack-enableCompression", -1);
2682 update_option("nitropack-autoCachePurge", get_option("nitropack-autoCachePurge", 1));
2683 update_option("nitropack-cacheableObjectTypes", nitropack_get_default_cacheable_object_types());
2684
2685
2686 nitropack_setup_webhooks($nitro, $token);
2687
2688 // _icl_current_language is WPML cookie, it is added here for compatibility with this module
2689 $customVariationCookies = array("np_wc_currency", "np_wc_currency_language", "_icl_current_language");
2690 $variationCookies = $nitro->getApi()->getVariationCookies();
2691 foreach ($variationCookies as $cookie) {
2692 $index = array_search($cookie["name"], $customVariationCookies);
2693 if ($index !== false) {
2694 array_splice($customVariationCookies, $index, 1);
2695 }
2696 }
2697
2698 foreach ($customVariationCookies as $cookieName) {
2699 $nitro->getApi()->setVariationCookie($cookieName);
2700 }
2701
2702 $nitro->fetchConfig(); // Reload the variation cookies
2703
2704 get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId);
2705 nitropack_install_advanced_cache();
2706
2707 try {
2708 do_action('nitropack_integration_purge_all');
2709 } catch (\Exception $e) {
2710 // Exception while signaling our 3rd party integration addons to purge their cache
2711 }
2712
2713 nitropack_event("connect", $nitro);
2714 nitropack_event("enable_extension", $nitro);
2715
2716 // Optimize front page
2717 $siteConfig = nitropack_get_site_config();
2718 if ($siteConfig) {
2719 $nitro->getApi()->runWarmup([$siteConfig['home_url']], true); // force run a warmup on the home page
2720 }
2721
2722
2723 nitropack_json_and_exit(array(
2724 "status" => "success",
2725 "message" => __("Connected", "nitropack")
2726 ));
2727 }
2728 } catch (\NitroPack\SDK\WebhookException $e) {
2729 nitropack_json_and_exit(array("status" => "error", "message" => $e->getMessage()));
2730 } catch (\NitroPack\SDK\StorageException $e) {
2731 nitropack_json_and_exit(array("status" => "error", "message" => __('Permission Error: ', 'nitropack') . $e->getMessage()));
2732 } catch (\NitroPack\SDK\EmptyConfigException $e) {
2733 nitropack_json_and_exit(array("status" => "error", "message" => __('Error while fetching remote config: ', 'nitropack') . $e->getMessage()));
2734 } catch (\NitroPack\HttpClient\Exceptions\SocketOpenException $e) {
2735 nitropack_json_and_exit(array("status" => "error", "message" => __('Can\'t establish connection with NitroPack\'s servers', 'nitropack')));
2736 } catch (\Exception $e) {
2737 nitropack_json_and_exit(array("status" => "error", "message" => __('Incorrect API credentials. Please make sure that you copied them correctly and try again.', 'nitropack')));
2738 }
2739
2740 nitropack_json_and_exit(array("status" => "error"));
2741 }
2742
2743 function nitropack_reset_webhooks($nitroSDK) {
2744 $nitroSDK->getApi()->unsetWebhook("config");
2745 $nitroSDK->getApi()->unsetWebhook("cache_clear");
2746 $nitroSDK->getApi()->unsetWebhook("cache_ready");
2747 }
2748
2749 function nitropack_setup_webhooks($nitro, $token = NULL) {
2750 if (!$nitro || !$token) {
2751 throw new \NitroPack\SDK\WebhookException('Webhook token cannot be empty.');
2752 }
2753
2754 $homeUrl = strtolower(get_home_url());
2755 $configUrl = new \NitroPack\Url\Url($homeUrl . "?nitroWebhook=config&token=$token");
2756 $cacheClearUrl = new \NitroPack\Url\Url($homeUrl . "?nitroWebhook=cache_clear&token=$token");
2757 $cacheReadyUrl = new \NitroPack\Url\Url($homeUrl . "?nitroWebhook=cache_ready&token=$token");
2758
2759 $nitro->getApi()->setWebhook("config", $configUrl);
2760 $nitro->getApi()->setWebhook("cache_clear", $cacheClearUrl);
2761 $nitro->getApi()->setWebhook("cache_ready", $cacheReadyUrl);
2762 }
2763
2764 function nitropack_disconnect() {
2765 nitropack_verify_ajax_nonce($_REQUEST);
2766 nitropack_uninstall_advanced_cache();
2767
2768 try {
2769 nitropack_event("disconnect");
2770 if (null !== $nitro = get_nitropack_sdk()) {
2771 nitropack_reset_webhooks($nitro);
2772 }
2773 } catch (\Exception $e) {
2774 nitropack_json_and_exit(array("status" => "error", "message" => $e->getMessage()));
2775 }
2776
2777 get_nitropack()->unsetCurrentBlogConfig();
2778
2779 $hostingNoticeFile = nitropack_get_hosting_notice_file();
2780 if (file_exists($hostingNoticeFile)) {
2781 if (WP_DEBUG) {
2782 unlink($hostingNoticeFile);
2783 } else {
2784 @unlink($hostingNoticeFile);
2785 }
2786 }
2787
2788 nitropack_json_and_exit(array("status" => "success", "message" => __("Disconnected", "nitropack")));
2789 }
2790
2791 function nitropack_set_compression_ajax() {
2792 nitropack_verify_ajax_nonce($_REQUEST);
2793 $compressionStatus = !empty($_POST["data"]["compressionStatus"]);
2794 $updated = update_option("nitropack-enableCompression", (int)$compressionStatus);
2795 if ($updated) {
2796 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), "hasCompression" => $compressionStatus));
2797 } else {
2798 nitropack_json_and_exit(array(
2799 "type" => "error",
2800 "message" => nitropack_admin_toast_msgs('error')
2801 ));
2802 }
2803 }
2804
2805 function nitropack_set_auto_cache_purge_ajax() {
2806 nitropack_verify_ajax_nonce($_REQUEST);
2807 $autoCachePurgeStatus = !empty($_POST["autoCachePurgeStatus"]);
2808 $updated = update_option("nitropack-autoCachePurge", (int)$autoCachePurgeStatus);
2809 if ($updated) {
2810 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), 'autoCachePurgeStatus' => $autoCachePurgeStatus));
2811 } else {
2812 nitropack_json_and_exit(array(
2813 "type" => "error",
2814 "message" => nitropack_admin_toast_msgs('error')
2815 ));
2816 }
2817 }
2818
2819 function nitropack_set_cart_cache_ajax() {
2820 nitropack_verify_ajax_nonce($_REQUEST);
2821 if (get_nitropack()->isConnected() && nitropack_render_woocommerce_cart_cache_option()) {
2822 $cartCacheStatus = (int) (!empty($_POST["cartCacheStatus"]));
2823
2824 if ($cartCacheStatus == 1) {
2825 nitropack_enable_cart_cache();
2826 } else {
2827 nitropack_disable_cart_cache();
2828 }
2829 }
2830
2831 nitropack_json_and_exit(array(
2832 "type" => "error",
2833 "message" => nitropack_admin_toast_msgs('error')
2834 ));
2835 }
2836
2837 function nitropack_set_stock_reduce_status() {
2838 nitropack_verify_ajax_nonce($_REQUEST);
2839 $stockReduceStatus = !empty($_POST["data"]["stockReduceStatus"]);
2840 $updated = update_option("nitropack-stockReduceStatus", (int)$stockReduceStatus);
2841 if ($updated) {
2842 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), "stockReduceStatus" => $stockReduceStatus));
2843 } else {
2844 nitropack_json_and_exit(array(
2845 "type" => "error",
2846 "message" => nitropack_admin_toast_msgs('error')
2847 ));
2848 }
2849 }
2850
2851 function nitropack_set_bb_cache_purge_sync_ajax() {
2852 nitropack_verify_ajax_nonce($_REQUEST);
2853 $bbCacheSyncPurgeStatus = !empty($_POST["bbCachePurgeSyncStatus"]);
2854 $updated = update_option("nitropack-bbCacheSyncPurge", (int)$bbCacheSyncPurgeStatus);
2855 if ($updated) {
2856 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), 'bbCacheSyncPurgeStatus' => $bbCacheSyncPurgeStatus));
2857 } else {
2858 nitropack_json_and_exit(array(
2859 "type" => "error",
2860 "message" => nitropack_admin_toast_msgs('error')
2861 ));
2862 }
2863 }
2864
2865 function nitropack_set_legacy_purge_ajax() {
2866 nitropack_verify_ajax_nonce($_REQUEST);
2867 $legacyPurgeStatus = !empty($_POST["legacyPurgeStatus"]);
2868 $updated = update_option("nitropack-legacyPurge", (int)$legacyPurgeStatus);
2869 if ($updated) {
2870 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), 'legacyPurgeStatus' => $legacyPurgeStatus));
2871 } else {
2872 nitropack_json_and_exit(array(
2873 "type" => "error",
2874 "message" => nitropack_admin_toast_msgs('error')
2875 ));
2876 }
2877 }
2878
2879 function nitropack_set_cacheable_post_types() {
2880 nitropack_verify_ajax_nonce($_REQUEST);
2881 $currentCacheableObjectTypes = nitropack_get_cacheable_object_types();
2882 $cacheableObjectTypes = !empty($_POST["cacheableObjectTypes"]) ? $_POST["cacheableObjectTypes"] : array();
2883 update_option("nitropack-cacheableObjectTypes", $cacheableObjectTypes);
2884
2885 foreach ($currentCacheableObjectTypes as $objectType) {
2886 if (!in_array($objectType, $cacheableObjectTypes)) {
2887 nitropack_purge(NULL, "pageType:" . $objectType, "Optimizing '$objectType' pages was manually disabled");
2888 }
2889 }
2890
2891 nitropack_json_and_exit(array(
2892 "type" => "success",
2893 "message" => nitropack_admin_toast_msgs('success')
2894 ));
2895 }
2896
2897 function nitropack_test_compression_ajax() {
2898 nitropack_verify_ajax_nonce($_REQUEST);
2899 $hasCompression = true;
2900 try {
2901 if (\NitroPack\Integration\Hosting\Flywheel::detect()) { // Flywheel: Compression is enabled by default
2902 update_option("nitropack-enableCompression", 0);
2903 } else {
2904 require_once plugin_dir_path(__FILE__) . nitropack_trailingslashit('nitropack-sdk') . 'autoload.php';
2905 $http = new NitroPack\HttpClient\HttpClient(get_site_url());
2906 $http->setHeader("X-NitroPack-Request", 1);
2907 $http->timeout = 25;
2908 $http->fetch();
2909 $headers = $http->getHeaders();
2910 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
2911 update_option("nitropack-enableCompression", 0);
2912 $hasCompression = true;
2913 } else { // no compression, we must enable it from NitroPack
2914 update_option("nitropack-enableCompression", 1);
2915 $hasCompression = false;
2916 }
2917 }
2918 update_option("nitropack-checkedCompression", 1);
2919 } catch (\Exception $e) {
2920 nitropack_json_and_exit(array("type" => "error", "message" => nitropack_admin_toast_msgs('error')));
2921 }
2922
2923 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), "hasCompression" => $hasCompression));
2924 }
2925
2926 function nitropack_render_woocommerce_cart_cache_option() {
2927 return class_exists('WooCommerce');
2928 }
2929
2930 function nitropack_is_cart_cache_active() {
2931 $nitro = get_nitropack()->getSdk();
2932 if ($nitro) {
2933 $config = $nitro->getConfig();
2934 if (!empty($config->StatefulCache->Status) && !empty($config->StatefulCache->CartCache)) {
2935 return nitropack_is_cart_cache_available();
2936 }
2937 }
2938 return false;
2939 }
2940
2941 function nitropack_is_cart_cache_available() {
2942 $nitro = get_nitropack()->getSdk();
2943 if ($nitro) {
2944 $config = $nitro->getConfig();
2945 if (!empty($config->StatefulCache->isCartCacheAvailable)) {
2946 return true;
2947 }
2948 }
2949 return false;
2950 }
2951
2952 function nitropack_handle_compression_toggle($old_value, $new_value) {
2953 nitropack_update_blog_compression($new_value == 1);
2954 }
2955
2956 function nitropack_update_blog_compression($enableCompression = false) {
2957 if (get_nitropack()->isConnected()) {
2958 $siteConfig = nitropack_get_site_config();
2959 $siteId = $siteConfig["siteId"];
2960 $siteSecret = $siteConfig["siteSecret"];
2961 $blogId = get_current_blog_id();
2962 get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId, $enableCompression);
2963 }
2964 }
2965
2966 function nitropack_enable_warmup() {
2967 nitropack_verify_ajax_nonce($_REQUEST);
2968 if (null !== $nitro = get_nitropack_sdk()) {
2969 try {
2970 $nitro->getApi()->enableWarmup();
2971 $nitro->getApi()->setWarmupHomepage(get_home_url());
2972 $nitro->getApi()->runWarmup();
2973 } catch (\Exception $e) {
2974 }
2975
2976 nitropack_json_and_exit(array(
2977 "type" => "success",
2978 "message" => __('Success! Cache warmup has been enabled successfully!', 'nitropack')
2979 ));
2980 }
2981
2982 nitropack_json_and_exit(array(
2983 "type" => "error",
2984 "message" => __('Error! There was an error while enabling the cache warmup!', 'nitropack')
2985 ));
2986 }
2987
2988 function nitropack_disable_warmup() {
2989 nitropack_verify_ajax_nonce($_REQUEST);
2990 if (null !== $nitro = get_nitropack_sdk()) {
2991 try {
2992 $nitro->getApi()->disableWarmup();
2993 $nitro->getApi()->resetWarmup();
2994 delete_option('np_warmup_sitemap');
2995 } catch (\Exception $e) {
2996 }
2997
2998 nitropack_json_and_exit(array(
2999 "type" => "success",
3000 "message" => __('Success! Cache warmup has been disabled successfully!', 'nitropack')
3001 ));
3002 }
3003
3004 nitropack_json_and_exit(array(
3005 "type" => "error",
3006 "message" => __('Error! There was an error while disabling the cache warmup!', 'nitropack')
3007 ));
3008 }
3009
3010 function nitropack_run_warmup() {
3011 nitropack_verify_ajax_nonce($_REQUEST);
3012 if (null !== $nitro = get_nitropack_sdk()) {
3013 try {
3014 $nitro->getApi()->runWarmup();
3015 } catch (\Exception $e) {
3016 }
3017
3018 nitropack_json_and_exit(array(
3019 "type" => "success",
3020 "message" => __('Success! Cache warmup has been started successfully!', 'nitropack')
3021 ));
3022 }
3023
3024 nitropack_json_and_exit(array(
3025 "type" => "error",
3026 "message" => __('Error! There was an error while starting the cache warmup!', 'nitropack')
3027 ));
3028 }
3029
3030 function nitropack_estimate_warmup() {
3031 nitropack_verify_ajax_nonce($_REQUEST);
3032 if (null !== $nitro = get_nitropack_sdk()) {
3033 try {
3034 if (!session_id()) {
3035 session_start();
3036 }
3037 $id = !empty($_POST["estId"]) ? preg_replace("/[^a-fA-F0-9]/", "", (string)$_POST["estId"]) : NULL;
3038 if ($id !== NULL && (!is_string($id) || $id != $_SESSION["nitroEstimateId"])) {
3039 nitropack_json_and_exit(array(
3040 "type" => "error",
3041 "message" => __('Invalid estimation ID!', 'nitropack')
3042 ));
3043 }
3044
3045 $sitemapUrls = nitropack_active_sitemap_plugins() ? nitropack_get_site_maps() : NULL;
3046 $configuredSitemap = false;
3047
3048 if ($sitemapUrls === NULL) {
3049
3050 $defaultSitemap = get_default_sitemap();
3051 if ($defaultSitemap) {
3052 $nitro->getApi()->setWarmupSitemap($defaultSitemap);
3053 $configuredSitemap = true;
3054 }
3055
3056 delete_option('np_warmup_sitemap');
3057 } else {
3058
3059 $warmupSitemap = evaluate_warmup_sitemap($sitemapUrls);
3060 if ($warmupSitemap) {
3061 $nitro->getApi()->setWarmupSitemap($warmupSitemap);
3062 $configuredSitemap = true;
3063 }
3064 }
3065
3066 if (!$configuredSitemap) {
3067 $nitro->getApi()->setWarmupSitemap(NULL);
3068 }
3069
3070 $nitro->getApi()->setWarmupHomepage(get_home_url());
3071
3072 $optimizationsEstimate = $nitro->getApi()->estimateWarmup($id);
3073
3074 if ($id === NULL) {
3075 $_SESSION["nitroEstimateId"] = $optimizationsEstimate; // When id is NULL, $optimizationsEstimate holds the ID for the newly started estimate
3076 }
3077 } catch (\Exception $e) {
3078 }
3079 $json_data = array(
3080 "type" => "success",
3081 "res" => $optimizationsEstimate,
3082 "sitemap_indication" => get_option('np_warmup_sitemap', false),
3083 "message" => __('Warmup estimation failed.', 'nitropack'),
3084 );
3085 if (is_int($optimizationsEstimate) && $optimizationsEstimate > 0) {
3086 $json_data["message"] = __('Cache warmup has been estimated successfully.', 'nitropack');
3087 } else if ($optimizationsEstimate === 0) {
3088 $json_data["message"] = __('We could not find any links for warming up on your home page.', 'nitropack');
3089 } else {
3090 $json_data["message"] = __('Warmup estimation failed. Please try again or contact support if the issue persists', 'nitropack');
3091 }
3092 nitropack_json_and_exit($json_data);
3093 }
3094
3095 nitropack_json_and_exit(array(
3096 "type" => "error",
3097 "message" => __('Warmup estimation failed.', 'nitropack')
3098 ));
3099 }
3100
3101 function nitropack_warmup_stats() {
3102 nitropack_verify_ajax_nonce($_REQUEST);
3103 if (null !== $nitro = get_nitropack_sdk()) {
3104 try {
3105 $stats = $nitro->getApi()->getWarmupStats();
3106 } catch (\Exception $e) {
3107 nitropack_json_and_exit(array(
3108 "type" => "error",
3109 "message" => __('Error! There was an error while fetching warmup stats!', 'nitropack')
3110 ));
3111 }
3112
3113 nitropack_json_and_exit(array(
3114 "type" => "success",
3115 "stats" => $stats
3116 ));
3117 }
3118
3119 nitropack_json_and_exit(array(
3120 "type" => "error",
3121 "message" => __('Error! There was an error while fetching warmup stats!', 'nitropack')
3122 ));
3123 }
3124
3125 function nitropack_enable_safemode() {
3126 nitropack_verify_ajax_nonce($_REQUEST);
3127 if (null !== $nitro = get_nitropack_sdk()) {
3128 try {
3129 $nitro->enableSafeMode();
3130 } catch (\Exception $e) {
3131 }
3132
3133 nitropack_cache_safemode_status(true);
3134 nitropack_json_and_exit(array(
3135 "type" => "success",
3136 "message" => nitropack_admin_toast_msgs('success')
3137
3138 ));
3139 }
3140
3141 nitropack_json_and_exit(array(
3142 "type" => "error",
3143 "message" => nitropack_admin_toast_msgs('error')
3144 ));
3145 }
3146
3147 function nitropack_disable_safemode() {
3148 nitropack_verify_ajax_nonce($_REQUEST);
3149
3150
3151 if (null !== $nitro = get_nitropack_sdk()) {
3152 try {
3153 $nitro->disableSafeMode();
3154 } catch (\Exception $e) {
3155 }
3156
3157 nitropack_cache_safemode_status(false);
3158 nitropack_json_and_exit(array(
3159 "type" => "success",
3160 "message" => nitropack_admin_toast_msgs('success')
3161 ));
3162 }
3163
3164 nitropack_json_and_exit(array(
3165 "type" => "error",
3166 "message" => nitropack_admin_toast_msgs('error')
3167 ));
3168 }
3169
3170 function nitropack_enable_cart_cache() {
3171 if (null !== $nitro = get_nitropack_sdk()) {
3172 try {
3173 $nitro->enableCartCache();
3174
3175 nitropack_json_and_exit(array(
3176 "type" => "success",
3177 "message" => nitropack_admin_toast_msgs('success')
3178 ));
3179 } catch (\Exception $e) {
3180 }
3181 }
3182
3183 nitropack_json_and_exit(array(
3184 "type" => "error",
3185 "message" => nitropack_admin_toast_msgs('error')
3186 ));
3187 }
3188
3189 function nitropack_disable_cart_cache() {
3190 if (null !== $nitro = get_nitropack_sdk()) {
3191 try {
3192 $nitro->disableCartCache();
3193
3194 nitropack_json_and_exit(array(
3195 "type" => "success",
3196 "message" => nitropack_admin_toast_msgs('success')
3197 ));
3198 } catch (\Exception $e) {
3199 }
3200 }
3201
3202 nitropack_json_and_exit(array(
3203 "type" => "error",
3204 "message" => nitropack_admin_toast_msgs('error')
3205 ));
3206 }
3207
3208 function nitropack_safemode_status($dontExit = false) {
3209 nitropack_verify_ajax_nonce($_REQUEST);
3210 if (null !== $nitro = get_nitropack_sdk()) {
3211 try {
3212 $isEnabled = $nitro->getApi()->isSafeModeEnabled();
3213 } catch (\Exception $e) {
3214 if (!$dontExit) {
3215 nitropack_json_and_exit(array(
3216 "type" => "error",
3217 "message" => nitropack_admin_toast_msgs('success')
3218 ));
3219 }
3220 return NULL;
3221 }
3222
3223 nitropack_cache_safemode_status($isEnabled);
3224 if (!$dontExit) {
3225 nitropack_json_and_exit(array(
3226 "type" => "success",
3227 "isEnabled" => $isEnabled
3228 ));
3229 }
3230 return $isEnabled;
3231 }
3232
3233 nitropack_cache_safemode_status();
3234 if (!$dontExit) {
3235 nitropack_json_and_exit(array(
3236 "type" => "error",
3237 "message" => __('Error! There was an SDK error while fetching status of safe mode!', 'nitropack')
3238 ));
3239 }
3240 return NULL;
3241 }
3242
3243 function nitropack_cache_safemode_status($operation = null) {
3244 $sm = "-1";
3245 if (is_bool($operation)) {
3246 $sm = $operation ? '1' : '0';
3247 }
3248 return update_option('nitropack-safeModeStatus', $sm);
3249 }
3250
3251 function nitropack_get_site_config() {
3252 return get_nitropack()->getSiteConfig();
3253 }
3254
3255 function get_nitropack() {
3256 return \NitroPack\WordPress\NitroPack::getInstance();
3257 }
3258
3259 function nitropack_event($event, $nitro = null, $additional_meta_data = null) {
3260 global $wp_version;
3261
3262 try {
3263 $eventUrl = get_nitropack_integration_url("extensionEvent", $nitro);
3264 $domain = !empty($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : "Unknown";
3265
3266
3267 if (class_exists('WooCommerce')) {
3268 $platform = 'WooCommerce';
3269 } else {
3270 $platform = 'WordPress';
3271 }
3272
3273 $query_data = array(
3274 'event' => $event,
3275 'platform' => $platform,
3276 'platform_version' => $wp_version,
3277 'nitropack_extension_version' => NITROPACK_VERSION,
3278 'additional_meta_data' => $additional_meta_data ? json_encode($additional_meta_data) : "{}",
3279 'domain' => $domain
3280 );
3281
3282 $client = new NitroPack\HttpClient\HttpClient($eventUrl . '&' . http_build_query($query_data));
3283 $client->doNotDownload = true;
3284 $client->fetch();
3285 } catch (\Exception $e) {
3286 }
3287 }
3288
3289 function nitropack_get_wpconfig_path() {
3290 $configFilePath = nitropack_trailingslashit(ABSPATH) . "wp-config.php";
3291 if (!file_exists($configFilePath)) {
3292 $configFilePath = nitropack_trailingslashit(dirname(ABSPATH)) . "wp-config.php";
3293 $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.
3294 if (!file_exists($configFilePath) || file_exists($settingsFilePath)) {
3295 return false;
3296 }
3297 }
3298
3299
3300 if (!is_writable($configFilePath)) {
3301 return false;
3302 }
3303
3304 return $configFilePath;
3305 }
3306
3307 function nitropack_get_htaccess_path() {
3308 $configFilePath = nitropack_trailingslashit(ABSPATH) . ".htaccess";
3309 if (!file_exists($configFilePath)) {
3310 return false;
3311 }
3312
3313
3314 if (!is_writable($configFilePath)) {
3315 return false;
3316 }
3317
3318 return $configFilePath;
3319 }
3320
3321 function nitropack_detect_hosting() {
3322 if (\NitroPack\Integration\Hosting\Flywheel::detect()) {
3323 return "flywheel";
3324 } else if (\NitroPack\Integration\Hosting\Cloudways::detect()) {
3325 return "cloudways";
3326 } else if (\NitroPack\Integration\Hosting\WPEngine::detect()) {
3327 return "wpengine";
3328 } else if (\NitroPack\Integration\Hosting\SiteGround::detect()) {
3329 return "siteground";
3330 } else if (\NitroPack\Integration\Hosting\GoDaddyWPaaS::detect()) {
3331 return "godaddy_wpaas";
3332 } else if (\NitroPack\Integration\Hosting\GridPane::detect()) {
3333 return "gridpane";
3334 } else if (\NitroPack\Integration\Hosting\Kinsta::detect()) {
3335 return "kinsta";
3336 } else if (\NitroPack\Integration\Hosting\Closte::detect()) {
3337 return "closte";
3338 } else if (\NitroPack\Integration\Hosting\Pagely::detect()) {
3339 return "pagely";
3340 } else if (\NitroPack\Integration\Hosting\WPX::detect()) {
3341 return "wpx";
3342 } else if (\NitroPack\Integration\Hosting\Vimexx::detect()) {
3343 return "vimexx";
3344 } else if (\NitroPack\Integration\Hosting\Pressable::detect()) {
3345 return "pressable";
3346 } else if (\NitroPack\Integration\Hosting\RocketNet::detect()) {
3347 return "rocketnet";
3348 } else if (\NitroPack\Integration\Hosting\Savvii::detect()) {
3349 return "savvii";
3350 } else if (\NitroPack\Integration\Hosting\DreamHost::detect()) {
3351 return "dreamhost";
3352 } else if (\NitroPack\Integration\Hosting\Raidboxes::detect()) {
3353 return "raidboxes";
3354 } else {
3355 return "unknown";
3356 }
3357 }
3358
3359 function nitropack_removeCacheBustParam($content) {
3360 $content = preg_replace("/(\?|%26|&#0?38;|&#x0?26;|&(amp;)?)ignorenitro(%3D|=)[a-fA-F0-9]{32}(?!%26|&#0?38;|&#x0?26;|&(amp;)?)\/?/mu", "", $content);
3361 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);
3362 }
3363
3364 function nitropack_handle_request($servedFrom = "unknown") {
3365 global $np_integrationSetupEvent;
3366
3367 if (isset($_GET["ignorenitro"])) {
3368 unset($_GET["ignorenitro"]);
3369 }
3370
3371 if (defined("NITROPACK_STRIP_IGNORENITRO") && NITROPACK_STRIP_IGNORENITRO && $_SERVER['REQUEST_URI'] != '') {
3372 $_SERVER['REQUEST_URI'] = nitropack_removeCacheBustParam($_SERVER['REQUEST_URI']);
3373 }
3374
3375 nitropack_header('Cache-Control: no-cache');
3376 do_action("nitropack_early_cache_headers"); // Overrides the Cache-Control header on supported platforms
3377 $isManageWpRequest = !empty($_GET["mwprid"]);
3378 $isWpCli = nitropack_is_wp_cli();
3379
3380 if (file_exists(NITROPACK_CONFIG_FILE) && !empty($_SERVER["HTTP_HOST"]) && !empty($_SERVER["REQUEST_URI"]) && !$isManageWpRequest && !$isWpCli) {
3381 try {
3382 $siteConfig = nitropack_get_site_config();
3383 if ($siteConfig && null !== $nitro = get_nitropack_sdk($siteConfig["siteId"], $siteConfig["siteSecret"])) {
3384 if (is_valid_nitropack_webhook()) {
3385 nitropack_handle_webhook();
3386 } else if (is_valid_nitropack_beacon()) {
3387 nitropack_handle_beacon();
3388 } else if (is_valid_nitropack_heartbeat()) {
3389 nitropack_handle_heartbeat();
3390 } else {
3391 $GLOBALS["NitroPack.instance"] = $nitro;
3392
3393 if (nitropack_passes_cookie_requirements() || (nitropack_is_ajax() && !empty($_COOKIE["nitroCachedPage"]))) {
3394 // Check whether the current URL is cacheable
3395 // 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.
3396 // If we are not checking the referer, the AJAX requests on these pages can fail.
3397 $urlToCheck = nitropack_is_ajax() && !empty($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : $nitro->getUrl();
3398 if ($nitro->isAllowedUrl($urlToCheck)) {
3399 add_filter('nonce_life', 'nitropack_extend_nonce_life');
3400 }
3401 }
3402
3403 if (nitropack_passes_cookie_requirements() && apply_filters("nitropack_can_serve_cache", true)) {
3404 if ($nitro->isCacheAllowed()) {
3405 if (!nitropack_is_ajax()) {
3406 do_action("nitropack_cacheable_cache_headers");
3407 }
3408
3409 if (!empty($siteConfig["compression"])) {
3410 $nitro->enableCompression();
3411 }
3412
3413 if ($nitro->hasLocalCache()) {
3414 // TODO: Make this work so we can provide the reverse proxies with this information $remainingTtl = $nitr->pageCache->getRemainingTtl();
3415 do_action("nitropack_cachehit_cache_headers"); // TODO: Pass the remaining TTL here
3416 $cacheControlOverride = defined("NITROPACK_CACHE_CONTROL_OVERRIDE") ? NITROPACK_CACHE_CONTROL_OVERRIDE : NULL;
3417 if ($cacheControlOverride) {
3418 nitropack_header('Cache-Control: ' . $cacheControlOverride);
3419 }
3420
3421 nitropack_header('X-Nitro-Cache: HIT');
3422 nitropack_header('X-Nitro-Cache-From: ' . $servedFrom);
3423 $cjHandler = new \NitroPack\SDK\Utils\CjHandler($nitro);
3424 $cjHandler->handleQueryParams();
3425 $nitro->pageCache->readfile();
3426 exit;
3427 } else {
3428 // We need the following if..else block to handle bot requests which will not be firing our beacon
3429 if (nitropack_is_warmup_request()) {
3430 if (!empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
3431 add_action("init", function () use ($nitro) {
3432 $nitro->hasRemoteCache("default"); // Only ping the API letting our service know that this page must be cached.
3433 exit;
3434 }, 9999);
3435 return; // We need to wait for a language plugin (if present) to redirect
3436 } else {
3437 $nitro->hasRemoteCache("default"); // Only ping the API letting our service know that this page must be cached.
3438 exit; // No need to continue handling this request. The response is not important.
3439 }
3440 } else if (nitropack_is_lighthouse_request() || nitropack_is_gtmetrix_request() || nitropack_is_pingdom_request()) {
3441 $nitro->hasRemoteCache("default"); // Ping the API letting our service know that this page must be cached.
3442 }
3443
3444 $nitro->pageCache->useInvalidated(true);
3445 if ($nitro->hasLocalCache()) {
3446 nitropack_header('X-Nitro-Cache: STALE');
3447 nitropack_header('X-Nitro-Cache-From: ' . $servedFrom);
3448 $cjHandler = new \NitroPack\SDK\Utils\CjHandler($nitro);
3449 $cjHandler->handleQueryParams();
3450 $nitro->pageCache->readfile();
3451 exit;
3452 } else {
3453 $nitro->pageCache->useInvalidated(false);
3454 }
3455 }
3456 }
3457 }
3458 }
3459 }
3460 } catch (\Exception $e) {
3461 // Do nothing, cache serving will be handled by nitropack_init
3462 }
3463 }
3464 }
3465
3466 function nitropack_is_dropin_cache_allowed() {
3467 $siteConfig = nitropack_get_site_config();
3468 return $siteConfig && empty($siteConfig["isEzoicActive"]);
3469 }
3470
3471 function nitropack_is_dismissed_notice($id) {
3472 return isset($_COOKIE["dismissed_notice_" . $id]);
3473 }
3474
3475 function nitropack_admin_bar_menu($wp_admin_bar) {
3476 if (nitropack_is_amp_page()) return;
3477
3478
3479 $nitropackPluginNotices = nitropack_plugin_notices();
3480 $numberOfPluginErrors = 0;
3481 $numberOfPluginWarnings = 0;
3482 foreach (array("warning", "error") as $type) {
3483 foreach ($nitropackPluginNotices[$type] as $notice) {
3484 if (!nitropack_is_dismissed_notice(nitropack_get_notice_id($notice))) {
3485 switch ($type) {
3486 case "error":
3487 $numberOfPluginErrors++;
3488 break;
3489 case "warning":
3490 $numberOfPluginWarnings++;
3491 break;
3492 }
3493 }
3494 }
3495 }
3496
3497 $numberOfPluginIssues = $numberOfPluginErrors + $numberOfPluginWarnings;
3498 $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;';
3499 if ($numberOfPluginErrors > 0) {
3500 $pluginStatus = 'error';
3501 } else if ($numberOfPluginWarnings > 0) {
3502 $pluginStatus = 'warning';
3503 } else {
3504 $pluginStatus = 'ok';
3505 }
3506
3507
3508 if (!get_nitropack()->isConnected()) {
3509 $node = array(
3510 'id' => 'nitropack-top-menu',
3511 'title' => '&nbsp;&nbsp;<i style="" class="circle nitro nitro-status nitro-status-error" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack is disconnected',
3512 'href' => admin_url('admin.php?page=nitropack'),
3513 'meta' => array(
3514 'class' => 'nitropack-menu'
3515 )
3516 );
3517
3518 $wp_admin_bar->add_node(
3519 array(
3520 'parent' => 'nitropack-top-menu',
3521 'id' => 'optimizations-plugin-status',
3522 'title' => __('Connect NitroPack&nbsp;&nbsp;', 'nitropack'),
3523 'href' => admin_url('admin.php?page=nitropack'),
3524 'meta' => array(
3525 'class' => 'nitropack-plugin-status',
3526 )
3527 )
3528 );
3529 } else {
3530 $title = '&nbsp;&nbsp;<i style="" class="circle nitro nitro-status nitro-status-' . $pluginStatus . '" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack';
3531 if ($pluginStatus != "ok") {
3532 $title .= ' <span class="nitro-issues-count" style="' . $css_counter . '">' . $numberOfPluginIssues . '</span>';
3533 }
3534 $node = array(
3535 'id' => 'nitropack-top-menu',
3536 'title' => $title,
3537 'href' => admin_url('admin.php?page=nitropack'),
3538 'meta' => array(
3539 'class' => 'nitropack-menu'
3540 )
3541 );
3542
3543 $wp_admin_bar->add_node(array(
3544 'id' => 'nitropack-top-menu-settings',
3545 'parent' => 'nitropack-top-menu',
3546 'title' => __('Settings', 'nitropack'),
3547 'href' => admin_url('admin.php?page=nitropack'),
3548 'meta' => array(
3549 'class' => 'nitropack-settings'
3550 )
3551
3552 ));
3553 $wp_admin_bar->add_node(array(
3554 'id' => 'nitropack-top-menu-settings',
3555 'parent' => 'nitropack-top-menu',
3556 'title' => __('Settings', 'nitropack'),
3557 'href' => admin_url('admin.php?page=nitropack'),
3558 'meta' => array(
3559 'class' => 'nitropack-settings'
3560 )
3561
3562 ));
3563
3564 $wp_admin_bar->add_node(
3565 array(
3566 'id' => 'nitropack-top-menu-purge-entire-cache',
3567 'parent' => 'nitropack-top-menu',
3568 'title' => __('Purge Entire Cache', 'nitropack'),
3569 'href' => '#',
3570 'meta' => array(
3571 'class' => 'nitropack-purge-cache-entire-site',
3572 ),
3573 )
3574 );
3575
3576 if (!is_admin()) { // menu otions available when browsing front-end pages
3577
3578 $wp_admin_bar->add_node(
3579 array(
3580 'parent' => 'nitropack-top-menu',
3581 'id' => 'optimizations-purge-cache',
3582 'title' => __('Purge Current Page', 'nitropack'),
3583 'href' => "#",
3584 'meta' => array(
3585 'class' => 'nitropack-purge-cache',
3586 )
3587 )
3588 );
3589
3590 $wp_admin_bar->add_node(
3591 array(
3592 'parent' => 'nitropack-top-menu',
3593 'id' => 'optimizations-invalidate-cache',
3594 'title' => __('Invalidate Current Page', 'nitropack'),
3595 'href' => "#",
3596 'meta' => array(
3597 'class' => 'nitropack-invalidate-cache',
3598 )
3599 )
3600 );
3601 }
3602
3603 if ($pluginStatus != "ok") {
3604 $wp_admin_bar->add_node(
3605 array(
3606 'parent' => 'nitropack-top-menu',
3607 'id' => 'optimizations-plugin-status',
3608 'title' => 'Issues&nbsp;&nbsp;<span style="' . $css_counter . '">' . $numberOfPluginIssues . '</span>',
3609 'href' => admin_url('admin.php?page=nitropack'),
3610 'meta' => array(
3611 'class' => 'nitropack-plugin-status',
3612 )
3613 )
3614 );
3615 }
3616
3617 $notificationCount = 0;
3618 foreach (get_nitropack()->Notifications->get('system') as $notification) {
3619 if (!nitropack_is_dismissed_notice($notification["id"])) {
3620 $notificationCount++;
3621 }
3622 }
3623
3624 if ($notificationCount) {
3625 $node['title'] .= '&nbsp;&nbsp;<span style="' . $css_counter . '">' . $notificationCount . '</span>';
3626 $wp_admin_bar->add_node(
3627 array(
3628 'parent' => 'nitropack-top-menu',
3629 'id' => 'nitropack-notifications',
3630 'title' => 'Notifications&nbsp;&nbsp;<span style="color:#fff;background-color:#72aee6;border-radius:11px;padding: 2px 7px">' . $notificationCount . '</span>',
3631 'href' => admin_url('admin.php?page=nitropack'),
3632 'meta' => array(
3633 'class' => 'nitropack-notifications',
3634 )
3635 )
3636 );
3637 }
3638 }
3639
3640 $wp_admin_bar->add_node($node);
3641 }
3642
3643 function nitropack_admin_bar_script($hook) {
3644 if (!nitropack_is_amp_page()) {
3645 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);
3646 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__)));
3647 }
3648 }
3649
3650
3651 function enqueue_nitropack_admin_bar_menu_stylesheet() {
3652 if (!nitropack_is_amp_page()) {
3653 wp_enqueue_style('nitropack_admin_bar_menu_stylesheet', plugin_dir_url(__FILE__) . 'view/stylesheet/admin_bar_menu.min.css?np_v=' . NITROPACK_VERSION);
3654 }
3655 }
3656
3657 function nitropack_cookiepath() {
3658 $siteConfig = nitropack_get_site_config();
3659 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
3660 $url = new \NitroPack\Url\Url($homeUrl);
3661 return $url ? $url->getPath() : "/";
3662 }
3663
3664 function nitropack_setcookie($name, $value, $expires = NULL, $options = []) {
3665 if (headers_sent()) return;
3666 $cookie_options = '';
3667 $cookie_path = nitropack_cookiepath();
3668
3669 if ($expires && is_numeric($expires)) {
3670 $options["Expires"] = date("D, d M Y H:i:s", (int)$expires) . ' GMT';
3671 }
3672
3673 if (empty($options["SameSite"])) {
3674 $options["SameSite"] = "Lax";
3675 }
3676
3677 foreach ($options as $optName => $optValue) {
3678 $cookie_options .= "$optName=$optValue; ";
3679 }
3680 nitropack_header("set-cookie: $name=$value; Path=$cookie_path; " . $cookie_options, false);
3681 }
3682
3683 function nitropack_header($header, $replace = true, $response_code = 0) {
3684 if (!nitropack_is_wp_cron() && !nitropack_is_wp_cli()) {
3685 header($header, $replace, $response_code);
3686 }
3687 }
3688
3689
3690 function nitropack_upgrade_handler($entity) {
3691 $np = 'nitropack/main.php';
3692 $trigger = $entity;
3693 if ($entity instanceof Plugin_Upgrader) {
3694 $trigger = $entity->plugin_info();
3695 if (!is_plugin_active($trigger)) {
3696 return;
3697 }
3698 }
3699
3700 if ($entity instanceof Theme_Upgrader) {
3701 if ($entity->theme_info()->Name === wp_get_theme()->Name) {
3702 nitropack_theme_handler('Theme updated');
3703 }
3704 return;
3705 }
3706
3707 if ($trigger !== $np) {
3708 $cookie_expires = date("D, d M Y H:i:s", time() + 600) . ' GMT';
3709 nitropack_setcookie('nitropack_apwarning', "1", time() + 600);
3710 }
3711 }
3712
3713 function nitropack_plugin_notices() {
3714 static $npPluginNotices = NULL;
3715
3716 if ($npPluginNotices !== NULL) {
3717 return $npPluginNotices;
3718 }
3719
3720 $errors = [];
3721 $warnings = [];
3722 $infos = [];
3723
3724 // Add conficting plugins errors
3725 $conflictingPlugins = nitropack_get_conflicting_plugins();
3726 foreach ($conflictingPlugins as $clashingPlugin) {
3727 $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);
3728 }
3729
3730 // Add residual cache notices if found
3731 $residualCachePlugins = \NitroPack\Integration\Plugin\RC::detectThirdPartyCaches();
3732 foreach ($residualCachePlugins as $rcpName) {
3733 $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);
3734 }
3735
3736 // Add plugins state notices
3737 if (isset($_COOKIE['nitropack_apwarning'])) {
3738 $cookie_path = nitropack_cookiepath();
3739 $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>";
3740 }
3741
3742 // Add SM enabled notice
3743 $smStatus = get_option('nitropack-safeModeStatus', "-1");
3744 if ($smStatus === "-1") $smStatus = nitropack_safemode_status(true);
3745 if ($smStatus) {
3746 // $safeModeMessage = '
3747 // <div class="title-wrapper">
3748 // <img src="' . plugin_dir_url(__FILE__) . 'view/images/alert-triangle.svg" alt="alert" class="icon" />
3749 // <h5 class="title">' . esc_html__('Important', 'nitropack') . '</h5>
3750 // </div>';
3751 $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');
3752 // $safeModeMessage = '
3753 // <div class="title-wrapper">
3754 // <img src="' . plugin_dir_url(__FILE__) . 'view/images/alert-triangle.svg" alt="alert" class="icon" />
3755 // <h5 class="title">' . esc_html__('Important', 'nitropack') . '</h5>
3756 // </div>';
3757 $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');
3758 if (get_nitropack()->getDistribution() == "oneclick") {
3759 $safeModeMessage = apply_filters("nitropack_oneclick_safemode_message", $safeModeMessage);
3760 }
3761 $warnings[] = '<div id="nitropack-smenabled-notice">' . $safeModeMessage . '</div>';
3762 }
3763
3764 $nitropackIsConnected = get_nitropack()->isConnected();
3765
3766 if ($nitropackIsConnected) {
3767 if (nitropack_is_advanced_cache_allowed()) {
3768 if (!nitropack_has_advanced_cache()) {
3769 $advancedCacheFile = nitropack_trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';
3770 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 :(
3771 if (nitropack_install_advanced_cache()) {
3772 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.
3773 $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');
3774 }
3775 } else {
3776 if (!nitropack_is_conflicting_plugin_active()) {
3777 $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');
3778 }
3779 }
3780 }
3781 } else {
3782 if (!defined("NITROPACK_ADVANCED_CACHE_VERSION") || NITROPACK_VERSION != NITROPACK_ADVANCED_CACHE_VERSION) {
3783 if (!nitropack_install_advanced_cache()) {
3784 if (nitropack_is_conflicting_plugin_active()) {
3785 $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');
3786 } else {
3787 $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');
3788 }
3789 }
3790 }
3791 }
3792 } else {
3793 if (nitropack_has_advanced_cache()) {
3794 nitropack_uninstall_advanced_cache();
3795 }
3796 }
3797
3798 if ((!defined("WP_CACHE") || !WP_CACHE)) {
3799 if (\NitroPack\Integration\Hosting\Flywheel::detect()) { // Flywheel: This is configured throught the FW control panel
3800 $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');
3801 } else if (!nitropack_set_wp_cache_const(true)) {
3802 $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');
3803 }
3804 }
3805
3806 if (apply_filters('nitropack_needs_htaccess_changes', false)) {
3807 if (!nitropack_set_htaccess_rules(true)) {
3808 $warnings[] = __('Unable to configure LiteSpeed specific rules for maximum performance. Please make sure your .htaccess file is writable or contact support.', 'nitropack');
3809 }
3810 }
3811
3812 if (!get_nitropack()->dataDirExists() && !get_nitropack()->initDataDir()) {
3813 $errors[] = __('The NitroPack data directory cannot be created. Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack');
3814 return [
3815 'error' => $errors,
3816 'warning' => $warnings,
3817 'info' => $infos
3818 ];
3819 }
3820
3821 if (!get_nitropack()->pluginDataDirExists() && !get_nitropack()->initPluginDataDir()) {
3822 $errors[] = __('The NitroPack plugin data directory cannot be created. Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack');
3823 return [
3824 'error' => $errors,
3825 'warning' => $warnings,
3826 'info' => $infos
3827 ];
3828 }
3829
3830 $siteConfig = nitropack_get_site_config();
3831 $siteId = $siteConfig ? $siteConfig["siteId"] : NULL;
3832 $siteSecret = $siteConfig ? $siteConfig["siteSecret"] : NULL;
3833 $webhookToken = esc_attr(get_option('nitropack-webhookToken'));
3834 $blogId = get_current_blog_id();
3835 $isConfigOutdated = !nitropack_is_config_up_to_date();
3836
3837 if (!get_nitropack()->Config->exists() && !get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3838 $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');
3839 } else if ($isConfigOutdated) {
3840 if (!get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3841 $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');
3842 } else {
3843 if (!$siteConfig) {
3844 nitropack_event("update");
3845 } else {
3846 $prevVersion = !empty($siteConfig["pluginVersion"]) ? $siteConfig["pluginVersion"] : "1.1.4 or older";
3847 nitropack_event("update", null, array("previous_version" => $prevVersion));
3848
3849 if (empty($siteConfig["pluginVersion"]) || version_compare($siteConfig["pluginVersion"], "1.3", "<")) {
3850 if (!headers_sent()) {
3851 setcookie("nitropack_upgrade_to_1_3_notice", 1, time() + 3600);
3852 }
3853 $_COOKIE["nitropack_upgrade_to_1_3_notice"] = 1;
3854 }
3855 }
3856 }
3857
3858 try {
3859 nitropack_setup_webhooks(get_nitropack_sdk(), $webhookToken);
3860 } catch (\NitroPack\SDK\WebhookException $e) {
3861 $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');
3862 }
3863 } else {
3864 $optionsMistmatch = false;
3865 if (array_key_exists('options_cache', $siteConfig)) {
3866 foreach (\NitroPack\WordPress\NitroPack::$optionsToCache as $opt) {
3867 if (is_array($opt)) {
3868 foreach ($opt as $option => $suboption) {
3869 if (empty($siteConfig['options_cache'][$option][$suboption]) || $siteConfig['options_cache'][$option][$suboption] != get_option($option)[$suboption]) {
3870 $optionsMistmatch = true;
3871 break 2;
3872 }
3873 }
3874 } else {
3875 if (!array_key_exists($opt, $siteConfig['options_cache']) || $siteConfig['options_cache'][$opt] != get_option($opt)) {
3876 $optionsMistmatch = true;
3877 break;
3878 }
3879 }
3880 }
3881 } else {
3882 $optionsMistmatch = true;
3883 }
3884
3885 if (
3886 $optionsMistmatch ||
3887 (!array_key_exists("isEzoicActive", $siteConfig) || $siteConfig["isEzoicActive"] !== \NitroPack\Integration\Plugin\Ezoic::isActive()) ||
3888 (!array_key_exists("isLateIntegrationInitRequired", $siteConfig) || $siteConfig["isLateIntegrationInitRequired"] !== nitropack_is_late_integration_init_required()) ||
3889 (!array_key_exists("isDlmActive", $siteConfig) || $siteConfig["isDlmActive"] !== \NitroPack\Integration\Plugin\DownloadManager::isActive()) ||
3890 (!array_key_exists("isAeliaCurrencySwitcherActive", $siteConfig) || $siteConfig["isAeliaCurrencySwitcherActive"] !== \NitroPack\Integration\Plugin\AeliaCurrencySwitcher::isActive()) ||
3891 (!array_key_exists("isGeoTargetingWPActive", $siteConfig) || $siteConfig["isGeoTargetingWPActive"] !== \NitroPack\Integration\Plugin\GeoTargetingWP::isActive()) ||
3892 (!array_key_exists("isWoocommerceActive", $siteConfig) || $siteConfig["isWoocommerceActive"] !== \NitroPack\Integration\Plugin\Woocommerce::isActive()) ||
3893 (!array_key_exists("isWoocommerceCacheHandlerActive", $siteConfig) || $siteConfig["isWoocommerceCacheHandlerActive"] !== \NitroPack\Integration\Plugin\WoocommerceCacheHandler::isActive())
3894 ) {
3895 if (!get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3896 $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');
3897 }
3898 }
3899
3900 if (empty($_COOKIE["nitropack_webhook_sync"])) {
3901 if (null !== $nitro = get_nitropack_sdk()) {
3902 try {
3903 if (!headers_sent()) {
3904 nitropack_setcookie("nitropack_webhook_sync", "1", time() + 300); // Do these checks in 5 minute intervals.
3905 }
3906 $configWebhook = $nitro->getApi()->getWebhook("config");
3907 if (!empty($configWebhook)) {
3908 $query = parse_url($configWebhook, PHP_URL_QUERY);
3909 if ($query) {
3910 parse_str($query, $webhookParams);
3911 if (empty($webhookParams["token"]) || $webhookParams["token"] != $webhookToken) {
3912 $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>";
3913 }
3914 }
3915 }
3916 } catch (\Exception $e) {
3917 //Do nothing
3918 }
3919 }
3920 }
3921
3922 if (apply_filters('nitropack_should_modify_htaccess', false) && (empty($_SERVER["NitroPackHtaccessVersion"]) || NITROPACK_VERSION != $_SERVER["NitroPackHtaccessVersion"])) {
3923 if (!nitropack_set_htaccess_rules(true)) {
3924 $errors[] = "The .htaccess file cannot be modified. Please make sure that it is writable and refresh this page.";
3925 }
3926 }
3927 }
3928
3929 if (!empty($_COOKIE["nitropack_upgrade_to_1_3_notice"])) {
3930 $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>";
3931 }
3932
3933 if (\NitroPack\Integration\Plugin\Cloudflare::isApoActive() && !\NitroPack\Integration\Plugin\Cloudflare::isApoCacheByDeviceTypeEnabled()) {
3934 $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.";
3935 }
3936 }
3937
3938 $npPluginNotices = [
3939 'error' => $errors,
3940 'warning' => $warnings,
3941 'info' => $infos
3942 ];
3943
3944
3945 return $npPluginNotices;
3946 }
3947
3948 /**
3949 * Caches some options in the config so that we can access them before get_option() is defined
3950 * which is in advanced_cache.php, functions.php and Integrations
3951 */
3952 function nitropack_updated_option($option, $oldValue, $value) {
3953 $neededOptions = \NitroPack\WordPress\NitroPack::$optionsToCache;
3954 if (!in_array($option, $neededOptions)) return;
3955
3956 $np = get_nitropack();
3957 $siteConfig = $np->Config->get();
3958
3959 if (function_exists('get_home_url')) {
3960 $configKey = \NitroPack\WordPress\NitroPack::getConfigKey();
3961 $siteConfig[$configKey]['options_cache'][$option] = $value;
3962 $np->Config->set($siteConfig);
3963 }
3964 }
3965
3966 function nitropack_is_late_integration_init_required() {
3967 return \NitroPack\Integration\Plugin\NginxHelper::isActive() || \NitroPack\Integration\Plugin\Cloudflare::isApoActive();
3968 }
3969
3970 function nitropack_get_notice_id($message) {
3971 return md5($message);
3972 }
3973
3974 function nitropack_display_admin_notices() {
3975 $noticesArray = nitropack_plugin_notices();
3976 foreach ($noticesArray as $type => $notices) {
3977 foreach ($notices as $notice) {
3978 nitropack_print_notice($type, $notice, false);
3979 }
3980 }
3981 }
3982
3983 function nitropack_offer_safemode() {
3984 global $pagenow;
3985 if ($pagenow == 'plugins.php') {
3986 $smStatus = get_option('nitropack-safeModeStatus', "-1");
3987 if ($smStatus === "0") {
3988 add_action('admin_enqueue_scripts', function () {
3989 wp_enqueue_script('np_safemode', plugin_dir_url(__FILE__) . 'view/javascript/np_safemode.js', array('jquery'));
3990 wp_enqueue_style('np_safemode', plugin_dir_url(__FILE__) . 'view/stylesheet/safemode.min.css');
3991 });
3992 add_action('admin_footer', function () {
3993 require_once NITROPACK_PLUGIN_DIR . 'view/safemode.php';
3994 });
3995 }
3996 }
3997 }
3998
3999 function nitropack_active_sitemap_plugins() {
4000 return
4001 NitroPack\Integration\Plugin\YoastSEO::isActive() ||
4002 NitroPack\Integration\Plugin\JetPackNP::isActive() ||
4003 NitroPack\Integration\Plugin\SquirrlySEO::isActive() ||
4004 NitroPack\Integration\Plugin\RankMathNP::isActive();
4005 }
4006
4007 function nitropack_get_site_maps() {
4008 $sitemapUrls['YoastSEO'] = NitroPack\Integration\Plugin\YoastSEO::getSitemapURL();
4009 $sitemapUrls['JetPack'] = NitroPack\Integration\Plugin\JetPackNP::getSitemapURL();
4010 $sitemapUrls['SquirrlySEO'] = NitroPack\Integration\Plugin\SquirrlySEO::getSitemapURL();
4011 $sitemapUrls['RankMath'] = NitroPack\Integration\Plugin\RankMathNP::getSitemapURL();
4012
4013 return $sitemapUrls;
4014 }
4015
4016 function get_default_sitemap() {
4017
4018 $defaultSiteMap = NitroPack\Integration\Plugin\WPCacheHelper::getSitemapURL();
4019 if ($defaultSiteMap) {
4020 set_sitemap_indication_msg('WordPress', $defaultSiteMap);
4021 return $defaultSiteMap;
4022 }
4023
4024 return false;
4025 }
4026
4027 function evaluate_warmup_sitemap($sitemapUrls) {
4028
4029 $sitemapProviders = array(
4030 'YoastSEO' => 'Yoast!',
4031 'SquirrlySEO' => 'Squirrly SEO',
4032 'RankMath' => 'Rank Math',
4033 'JetPack' => 'Jetpack',
4034 );
4035
4036 foreach ($sitemapProviders as $provider => $name) {
4037 if (isset($sitemapUrls[$provider]) && $sitemapUrls[$provider]) {
4038 set_sitemap_indication_msg($name, $sitemapUrls[$provider]);
4039 return $sitemapUrls[$provider];
4040 }
4041 }
4042
4043 return get_default_sitemap();
4044 }
4045
4046 function set_sitemap_indication_msg($pluginName, $sitemapURL) {
4047 $sitemapURI = explode("/", parse_url($sitemapURL, PHP_URL_PATH));
4048 $msg = $sitemapURI[1] . ' used by ' . $pluginName;
4049 update_option('np_warmup_sitemap', $msg);
4050 }
4051
4052 function nitropack_rml_notification() {
4053
4054 if (!isset($_POST)) {
4055 return;
4056 }
4057
4058 nitropack_verify_ajax_nonce($_REQUEST);
4059
4060 $notification_id = $_POST['notification_id'];
4061 $notification_end = $_POST['notification_end'];
4062 $midpoint = get_date_midpoint($notification_end);
4063 $notification_end = strtotime($notification_end) - time();
4064 $transient_status = set_transient($notification_id, $midpoint, $notification_end);
4065
4066 nitropack_json_and_exit(array(
4067 "transient_status" => $transient_status,
4068 ));
4069 }
4070
4071 function get_date_midpoint($endDate) {
4072 return (time() + strtotime($endDate)) / 2;
4073 }
4074
4075 function nitropack_ignore_dismissed_notifications($notifications, $type) {
4076 foreach ($notifications as $key => $notification) {
4077 $display_time = get_transient($notification['id']);
4078 if ($display_time && time() < $display_time) {
4079 unset($notifications[$key]);
4080 }
4081 }
4082
4083 return $notifications;
4084 }
4085
4086 function initVariationCookies($customVariationCookies) {
4087 $api = get_nitropack_sdk()->getApi();
4088 try {
4089 $variationCookies = $api->getVariationCookies();
4090 foreach ($variationCookies as $cookie) {
4091 $index = array_search($cookie["name"], $customVariationCookies);
4092 if ($index !== false) {
4093 array_splice($customVariationCookies, $index, 1);
4094 }
4095 }
4096
4097 foreach ($customVariationCookies as $cookieName) {
4098 $api->setVariationCookie($cookieName);
4099 }
4100 } catch (\Exception $e) {
4101 // what to do here? possible reason for exception is the API not responding
4102 return false;
4103 }
4104 }
4105
4106 function removeVariationCookies($cookiesToRemove) {
4107 $api = get_nitropack_sdk()->getApi();
4108 try {
4109 $variationCookies = $api->getVariationCookies();
4110 foreach ($variationCookies as $cookie) {
4111 if (in_array($cookie["name"], $cookiesToRemove)) {
4112 $api->unsetVariationCookie($cookie["name"]);
4113 }
4114 }
4115 } catch (\Exception $e) {
4116 // what to do here? possible reason for exception is the API not responding
4117 return false;
4118 }
4119 }
4120
4121 function getNewCookie($name) {
4122 $cookies = getNewCookies();
4123 return !empty($cookies[$name]) ? $cookies[$name] : null;
4124 }
4125
4126 /**
4127 * Returns an array of newly set cookies (not in $_COOKIE), that will be sent along with the headers of the current response.
4128 */
4129 function getNewCookies() {
4130 $cookies = [];
4131 $headers = headers_list();
4132 foreach ($headers as $header) {
4133 if (strpos($header, 'Set-Cookie: ') === 0) {
4134 $value = str_replace('&', urlencode('&'), substr($header, 12));
4135 parse_str(current(explode(';', $value)), $pair);
4136 $cookies = array_merge_recursive($cookies, $pair);
4137 }
4138 }
4139
4140 return array_filter(array_map(function ($val) {
4141 if (is_array($val)) {
4142 $lastEl = end($val);
4143 if (is_array($lastEl)) {
4144 return NULL;
4145 }
4146 return $lastEl;
4147 }
4148
4149 return $val;
4150 }, $cookies));
4151 }
4152
4153 /**
4154 * Purge entire cache when permalink structure is changed.
4155 *
4156 * @param string $old_permalink_structure The previous permalink structure.
4157 * @param string $permalink_structure The new permalink structure.
4158 *
4159 * @return void
4160 */
4161 function nitropack_permalink_structure_changed_handler($old_permalink_structure, $permalink_structure) {
4162
4163 if ($old_permalink_structure != $permalink_structure && get_option("nitropack-autoCachePurge", 1)) {
4164 $msg = 'The permalink structure is changed. Purging the cache for the home page.';
4165 $url = get_home_url();
4166
4167 try {
4168 nitropack_sdk_purge($url, NULL, $msg); // purge cache for the home page
4169 } catch (\Exception $e) {
4170 }
4171
4172 // run warmup
4173 if (null !== $nitro = get_nitropack_sdk()) {
4174 try {
4175 $nitro->getApi()->runWarmup();
4176 } catch (\Exception $e) {
4177 }
4178 }
4179 }
4180 }
4181
4182 add_action('permalink_structure_changed', 'nitropack_permalink_structure_changed_handler', 10, 2);
4183
4184 /**
4185 * Purge entire cache when front page is changed.
4186 *
4187 * @param array $old_value An array of previous settings values.
4188 * @param array $value An array of submitted settings values.
4189 *
4190 * @return void
4191 */
4192 function nitropack_frontpage_changed_handler($old_value, $value) {
4193
4194 if ($old_value !== $value) {
4195 $msg = 'The front page is changed';
4196 $url = get_home_url();
4197
4198 try {
4199 nitropack_sdk_purge($url, NULL, $msg); // purge entire cache
4200 } catch (\Exception $e) {
4201 }
4202 }
4203 }
4204
4205 add_action('update_option_show_on_front', 'nitropack_frontpage_changed_handler', 10, 2);
4206 add_action('update_option_page_on_front', 'nitropack_frontpage_changed_handler', 10, 2);
4207 add_action('update_option_page_for_posts', 'nitropack_frontpage_changed_handler', 10, 2);
4208
4209 // Init integration action handlers
4210 $modHandler = NitroPack\ModuleHandler::getInstance();
4211 $modHandler->init();
4212