PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.16.4
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.16.4
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / functions.php
nitropack Last commit date
classes 1 year ago languages 2 years ago nitropack-sdk 1 year ago view 1 year ago advanced-cache.php 2 years ago batcache-compat.php 4 years ago constants.php 1 year ago diagnostics.php 2 years ago functions.php 1 year ago helpers.php 3 years ago main.php 1 year ago readme.txt 1 year ago uninstall.php 2 years ago wp-cli.php 2 years ago
functions.php
4236 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, $app_notification = []) {
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 $htmlMessage .= '<div class="actions">';
1143 if ($app_notification) {
1144 $htmlMessage .= '<a class="btn btn-secondary btn-dismiss rml_btn" data-notification_end="' . $app_notification['end_date'] . '" data-notification_id="' . $app_notification['id'] . '">' . esc_html__('Dismiss', 'nitropack') . '</a>';
1145 } else if ($dismissibleId) {
1146 $htmlMessage .= '<a class="btn btn-secondary btn-dismiss notice-dismiss" onclick="jQuery.post(ajaxurl, {action: "' . $dismissibleId . '", nonce: "' . wp_create_nonce(NITROPACK_NONCE) . '"}); jQuery(this).closest(\".is-dismissible\").hide();">' . esc_html__('Dismiss', 'nitropack') . '</a>';
1147 }
1148 $htmlMessage .= '</div>';
1149 echo $htmlMessage;
1150 echo '</div>
1151 </div>';
1152 }
1153
1154 function nitropack_get_conflicting_plugins() {
1155 $clashingPlugins = array();
1156
1157 if (defined('BREEZE_PLUGIN_DIR')) { // Breeze cache plugin
1158 $clashingPlugins[] = "Breeze";
1159 }
1160
1161 if (defined('WP_ROCKET_VERSION')) { // WP-Rocket
1162 $clashingPlugins[] = "WP-Rocket";
1163 }
1164
1165 if (defined('W3TC')) { // W3 Total Cache
1166 $clashingPlugins[] = "W3 Total Cache";
1167 }
1168
1169 if (defined('WPFC_MAIN_PATH')) { // WP Fastest Cache
1170 $clashingPlugins[] = "WP Fastest Cache";
1171 }
1172
1173 if (defined('PHASTPRESS_VERSION')) { // PhastPress
1174 $clashingPlugins[] = "PhastPress";
1175 }
1176
1177 if (defined('WPCACHEHOME') && function_exists("wp_cache_phase2")) { // WP Super Cache
1178 $clashingPlugins[] = "WP Super Cache";
1179 }
1180
1181 if (defined('LSCACHE_ADV_CACHE') || defined('LSCWP_DIR')) { // LiteSpeed Cache
1182 $clashingPlugins[] = "LiteSpeed Cache";
1183 }
1184
1185 if (class_exists('Swift_Performance') || class_exists('Swift_Performance_Lite')) { // Swift Performance
1186 $clashingPlugins[] = "Swift Performance";
1187 }
1188
1189 if (class_exists('PagespeedNinja')) { // PageSpeed Ninja
1190 $clashingPlugins[] = "PageSpeed Ninja";
1191 }
1192
1193 if (defined('AUTOPTIMIZE_PLUGIN_VERSION')) { // Autoptimize
1194 $clashingPlugins[] = "Autoptimize";
1195 }
1196
1197 if (defined('PEGASAAS_ACCELERATOR_VERSION')) { // Pegasaas Accelerator WP
1198 $clashingPlugins[] = "Pegasaas Accelerator WP";
1199 }
1200
1201 if (class_exists('WP_Hummingbird') || class_exists('Hummingbird\\WP_Hummingbird')) { // Hummingbird
1202 $clashingPlugins[] = "Hummingbird";
1203 }
1204
1205 if (defined('WP_SMUSH_VERSION')) { // Smush by WPMU DEV
1206 if (class_exists('Smush\\Core\\Settings') && defined('WP_SMUSH_PREFIX')) {
1207 $smushLazy = Smush\Core\Settings::get_instance()->get('lazy_load');
1208 if ($smushLazy) {
1209 $clashingPlugins[] = "Smush Lazy Load";
1210 }
1211 } else {
1212 $clashingPlugins[] = "Smush";
1213 }
1214 }
1215
1216 if (defined('COMET_CACHE_PLUGIN_FILE')) { // Comet Cache by WP Sharks
1217 $clashingPlugins[] = "Comet Cache";
1218 }
1219
1220 if (defined('WPO_VERSION') && class_exists('WPO_Cache_Config')) { // WP Optimize
1221 $wpo_cache_config = WPO_Cache_Config::instance();
1222 if ($wpo_cache_config->get_option('enable_page_caching', false)) {
1223 $clashingPlugins[] = "WP Optimize page caching";
1224 }
1225 }
1226
1227 if (class_exists('BJLL')) { // BJ Lazy Load
1228 $clashingPlugins[] = "BJ Lazy Load";
1229 }
1230
1231 if (defined('SHORTPIXEL_IMAGE_OPTIMISER_VERSION') && class_exists('\ShortPixel\ShortPixelPlugin')) { //ShortPixel WebP
1232 $sp_config = \ShortPixel\ShortPixelPlugin::getInstance();
1233 if ($sp_config->settings()->createWebp) {
1234 $clashingPlugins[] = "ShortPixel WebP image creation";
1235 }
1236 }
1237
1238 return $clashingPlugins;
1239 }
1240
1241 function nitropack_is_conflicting_plugin_active() {
1242 $conflictingPlugins = nitropack_get_conflicting_plugins();
1243 return !empty($conflictingPlugins);
1244 }
1245
1246 function nitropack_is_advanced_cache_allowed() {
1247 return !in_array(nitropack_detect_hosting(), array(
1248 "pressable"
1249 ));
1250 }
1251
1252 function nitropack_admin_notices() {
1253 if (defined('NITROPACK_DATA_DIR_WARNING')) {
1254 nitropack_print_notice('warning', NITROPACK_DATA_DIR_WARNING);
1255 }
1256
1257 if (defined('NITROPACK_PLUGIN_DATA_DIR_WARNING')) {
1258 nitropack_print_notice('warning', NITROPACK_PLUGIN_DATA_DIR_WARNING);
1259 }
1260
1261 if (!empty($_COOKIE["nitropack_after_activate_notice"])) {
1262 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!");
1263 }
1264
1265 $screen = get_current_screen();
1266 if ($screen->id != 'settings_page_nitropack') {
1267 foreach (get_nitropack()->Notifications->get('system') as $notification) {
1268 nitropack_print_notice('info', $notification['message'], $notification["id"], false, $notification);
1269 }
1270 }
1271
1272 nitropack_print_hosting_notice();
1273 nitropack_print_woocommerce_notice();
1274 }
1275
1276 function nitropack_get_hosting_notice_file() {
1277 return nitropack_trailingslashit(NITROPACK_DATA_DIR) . "hosting_notice";
1278 }
1279
1280 function nitropack_print_hosting_notice() {
1281 $hostingNoticeFile = nitropack_get_hosting_notice_file();
1282 if (!get_nitropack()->isConnected() || file_exists($hostingNoticeFile)) return;
1283
1284 $documentedHostingSetups = array(
1285 "flywheel" => array(
1286 "name" => "Flywheel",
1287 "helpUrl" => "https://getflywheel.com/wordpress-support/how-to-enable-wp_cache/"
1288 ),
1289 "cloudways" => array(
1290 "name" => "Cloudways",
1291 "helpUrl" => "https://support.nitropack.io/hc/en-us/articles/360060916674-Cloudways-Hosting-Configuration-for-NitroPack"
1292 )
1293 );
1294
1295 $siteConfig = nitropack_get_site_config();
1296 if ($siteConfig && !empty($siteConfig["hosting"]) && array_key_exists($siteConfig["hosting"], $documentedHostingSetups)) {
1297 $hostingInfo = $documentedHostingSetups[$siteConfig["hosting"]];
1298 $showNotice = true;
1299 if ($siteConfig["hosting"] == "flywheel" && defined("WP_CACHE") && WP_CACHE) $showNotice = false;
1300
1301 if ($showNotice) {
1302 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');
1303 }
1304 }
1305 }
1306
1307 function nitropack_dismiss_hosting_notice() {
1308 nitropack_verify_ajax_nonce($_REQUEST);
1309 $hostingNoticeFile = nitropack_get_hosting_notice_file();
1310 if (WP_DEBUG) {
1311 touch($hostingNoticeFile);
1312 } else {
1313 @touch($hostingNoticeFile);
1314 }
1315 }
1316
1317 function nitropack_print_woocommerce_notice() {
1318 if (get_nitropack()->isConnected()) {
1319 if (class_exists('WooCommerce')) {
1320 $wcOneTimeNotice = get_option('nitropack-wcNotice');
1321 if ($wcOneTimeNotice === false) {
1322 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');
1323 }
1324 }
1325 }
1326 }
1327
1328 function nitropack_dismiss_woocommerce_notice() {
1329 nitropack_verify_ajax_nonce($_REQUEST);
1330 update_option('nitropack-wcNotice', 1);
1331 }
1332
1333 function nitropack_is_config_up_to_date() {
1334 $siteConfig = nitropack_get_site_config();
1335 return !empty($siteConfig) && !empty($siteConfig["pluginVersion"]) && $siteConfig["pluginVersion"] == NITROPACK_VERSION;
1336 }
1337
1338 function nitropack_filter_non_original_cookies(&$cookies) {
1339 global $np_originalRequestCookies;
1340 $ogNames = is_array($np_originalRequestCookies) ? array_keys($np_originalRequestCookies) : array();
1341 foreach ($cookies as $name => $val) {
1342 if (!in_array($name, $ogNames)) {
1343 unset($cookies[$name]);
1344 }
1345 }
1346 }
1347
1348 function nitropack_add_meta_box() {
1349 if (current_user_can('manage_options') || current_user_can('nitropack_meta_box')) {
1350 foreach (nitropack_get_cacheable_object_types() as $objectType) {
1351 add_meta_box('nitropack_manage_cache_box', 'NitroPack', 'nitropack_print_meta_box', $objectType, 'side');
1352 }
1353 }
1354 }
1355
1356 // This is only used for post types that can have "single" pages
1357 function nitropack_print_meta_box($post) {
1358 wp_enqueue_script('nitropack_metabox_js', plugin_dir_url(__FILE__) . 'view/javascript/metabox.js?np_v=' . NITROPACK_VERSION, true);
1359 wp_localize_script('nitropack_metabox_js', 'metaboxdata', array('nitroNonce' => wp_create_nonce(NITROPACK_NONCE), 'nitro_plugin_url' => plugin_dir_url(__FILE__)));
1360
1361 $html = '';
1362 $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>';
1363 $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>';
1364 $html .= '<p id="nitropack-status-msg" style="display:none;"></p>';
1365 echo $html;
1366 }
1367
1368 function get_nitropack_sdk($siteId = null, $siteSecret = null, $urlOverride = NULL, $forwardExceptions = false) {
1369 return get_nitropack()->getSdk($siteId, $siteSecret, $urlOverride, $forwardExceptions);
1370 }
1371
1372 function get_nitropack_integration_url($integration, $nitro = null) {
1373 if ($nitro || (null !== $nitro = get_nitropack_sdk())) {
1374 return $nitro->integrationUrl($integration);
1375 }
1376
1377 return "#";
1378 }
1379
1380 function register_nitropack_settings() {
1381 register_setting(NITROPACK_OPTION_GROUP, 'nitropack-enableCompression', array('default' => -1));
1382 }
1383
1384 function nitropack_get_layout() {
1385 $layout = "default";
1386
1387 if (nitropack_is_home()) {
1388 $layout = "home";
1389 } else if (nitropack_is_blogindex()) {
1390 $layout = "blogindex";
1391 } else if (is_page()) {
1392 $layout = "page";
1393 } else if (is_attachment()) {
1394 $layout = "attachment";
1395 } else if (is_author()) {
1396 $layout = "author";
1397 } else if (is_search()) {
1398 $layout = "search";
1399 } else if (is_tag()) {
1400 $layout = "tag";
1401 } else if (is_tax()) {
1402 $layout = "taxonomy";
1403 } else if (is_category()) {
1404 $layout = "category";
1405 } else if (nitropack_is_archive()) {
1406 $layout = "archive";
1407 } else if (is_feed()) {
1408 $layout = "feed";
1409 } else if (is_page()) {
1410 $layout = "page";
1411 } else if (is_single()) {
1412 $layout = get_post_type();
1413 }
1414
1415 return $layout;
1416 }
1417
1418 function nitropack_sdk_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
1419 if (null !== $nitro = get_nitropack_sdk()) {
1420 try {
1421 $siteConfig = nitropack_get_site_config();
1422 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
1423
1424 if ($tag) {
1425 if (is_array($tag)) {
1426 $tag = array_map('nitropack_filter_tag', $tag);
1427 } else {
1428 $tag = nitropack_filter_tag($tag);
1429 }
1430 }
1431
1432 $nitro->invalidateCache($url, $tag, $reason);
1433
1434 try {
1435
1436 if (defined('NITROPACK_DEBUG_MODE')) {
1437 do_action('nitropack_debug_invalidate', $url, $tag, $reason);
1438 }
1439
1440 do_action('nitropack_integration_purge_url', $homeUrl);
1441
1442 if ($tag) {
1443 do_action('nitropack_integration_purge_all');
1444 } else if ($url) {
1445 do_action('nitropack_integration_purge_url', $url);
1446 } else {
1447 do_action('nitropack_integration_purge_all');
1448 }
1449 } catch (\Exception $e) {
1450 // Exception while signaling 3rd party integration addons to purge their cache
1451 }
1452 } catch (\Exception $e) {
1453 return false;
1454 }
1455
1456 return true;
1457 }
1458
1459 return false;
1460 }
1461
1462 /* Start Heartbeat Related Functions */
1463 function nitropack_is_heartbeat_needed() {
1464 return !nitropack_is_optimizer_request() &&
1465 !nitropack_is_amp_page() &&
1466 !nitropack_is_heartbeat_running() &&
1467 (!nitropack_is_heartbeat_completed() || time() - nitropack_last_heartbeat() > NITROPACK_HEARTBEAT_INTERVAL);
1468 }
1469
1470 function nitropack_print_heartbeat_script() {
1471 if (nitropack_is_heartbeat_needed()) {
1472 if (defined("NITROPACK_HEARTBEAT_PRINTED")) return;
1473 define("NITROPACK_HEARTBEAT_PRINTED", true);
1474 echo apply_filters("nitro_script_output", nitropack_get_heartbeat_script());
1475 }
1476 }
1477
1478 function nitropack_get_heartbeat_script() {
1479 $siteConfig = nitropack_get_site_config();
1480 if ($siteConfig && !empty($siteConfig["siteId"]) && !empty($siteConfig["siteSecret"])) {
1481 if (null !== $nitro = get_nitropack_sdk($siteConfig["siteId"], $siteConfig["siteSecret"])) {
1482 if (is_admin()) {
1483 $credentials = "same-origin";
1484 } else {
1485 $credentials = "omit";
1486 }
1487
1488 return "
1489 <script nitro-exclude>
1490 var heartbeatData = new FormData(); heartbeatData.append('nitroHeartbeat', '1');
1491 fetch(location.href, {method: 'POST', body: heartbeatData, credentials: '$credentials'});
1492 </script>";
1493 }
1494 }
1495 }
1496
1497 function is_valid_nitropack_heartbeat() {
1498 return !empty($_POST['nitroHeartbeat']);
1499 }
1500
1501 function nitropack_get_heartbeat_file() {
1502 if (null !== $nitro = get_nitropack_sdk()) {
1503 return nitropack_trailingslashit($nitro->getCacheDir()) . "heartbeat";
1504 } else {
1505 return nitropack_trailingslashit(NITROPACK_DATA_DIR) . "heartbeat";
1506 }
1507 }
1508
1509 function nitropack_last_heartbeat() {
1510 if (null !== $nitro = get_nitropack_sdk()) {
1511 try {
1512 return \NitroPack\SDK\Filesystem::fileMTime(nitropack_get_heartbeat_file());
1513 } catch (\Exception $e) {
1514 return 0;
1515 }
1516 }
1517 }
1518
1519 function nitropack_is_heartbeat_running() {
1520 if (null !== $nitro = get_nitropack_sdk()) {
1521 try {
1522 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents(nitropack_get_heartbeat_file());
1523 if ($heartbeatContent == "1") {
1524 return time() - nitropack_last_heartbeat() < NITROPACK_HEARTBEAT_INTERVAL;
1525 }
1526 } catch (\Exception $e) {
1527 return false;
1528 }
1529 }
1530 }
1531
1532 function nitropack_is_heartbeat_completed() {
1533 if (null !== $nitro = get_nitropack_sdk()) {
1534 try {
1535 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents(nitropack_get_heartbeat_file());
1536 return $heartbeatContent == "0"; // 0 - Job Done, 1 - Job Running, 2 - Job Needs Repeat
1537 } catch (\Exception $e) {
1538 return true;
1539 }
1540 }
1541 }
1542
1543 function nitropack_handle_heartbeat() {
1544 // TODO: Lock the file before checking this
1545 if (nitropack_is_heartbeat_running()) return;
1546
1547 session_write_close();
1548 if (null !== $nitro = get_nitropack_sdk()) {
1549 try {
1550 $success = true;
1551 \NitroPack\SDK\Filesystem::filePutContents(nitropack_get_heartbeat_file(), 1);
1552 if (nitropack_healthcheck()) {
1553 $success &= nitropack_flush_backlog();
1554 }
1555 $success &= nitropack_cache_cleanup();
1556
1557 if ($success) {
1558 \NitroPack\SDK\Filesystem::filePutContents(nitropack_get_heartbeat_file(), 0);
1559 } else {
1560 \NitroPack\SDK\Filesystem::filePutContents(nitropack_get_heartbeat_file(), 2);
1561 }
1562 } catch (\Exception $e) {
1563 return false;
1564 }
1565 }
1566 exit;
1567 }
1568
1569 function nitropack_healthcheck() {
1570 if (null !== $nitro = get_nitropack_sdk()) {
1571 return $nitro->getHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY || $nitro->checkHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY;
1572 }
1573 return true;
1574 }
1575
1576 function nitropack_flush_backlog() {
1577 if (null !== $nitro = get_nitropack_sdk()) {
1578 try {
1579 if ($nitro->backlog->exists()) {
1580 return $nitro->backlog->replay(30);
1581 }
1582 } catch (\NitroPack\SDK\BacklogReplayTimeoutException $e) {
1583 $nitro->backlog->delete();
1584 return nitropack_sdk_purge(NULL, NULL, "Full purge after backlog timeout");
1585 } catch (\Exception $e) {
1586 return false;
1587 }
1588 }
1589 return true;
1590 }
1591
1592 function nitropack_cache_cleanup() {
1593 if (null !== $nitro = get_nitropack_sdk()) {
1594 $cacheDirParent = dirname($nitro->getCacheDir());
1595 $entries = scandir($cacheDirParent);
1596 foreach ($entries as $entry) {
1597 if (strpos($entry, ".stale.") !== false) {
1598 $cacheDir = nitropack_trailingslashit($cacheDirParent) . $entry;
1599 try {
1600 \NitroPack\SDK\Filesystem::deleteDir($cacheDir);
1601 } catch (\Exception $e) {
1602 // TODO: Log this
1603 return false;
1604 }
1605 }
1606 }
1607 }
1608 return true;
1609 }
1610 /* End Heartbeat Related Functions */
1611
1612 function nitropack_sdk_purge($url = NULL, $tag = NULL, $reason = NULL, $type = \NitroPack\SDK\PurgeType::COMPLETE) {
1613 if (null !== $nitro = get_nitropack_sdk()) {
1614 try {
1615 $siteConfig = nitropack_get_site_config();
1616 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
1617
1618 if ($tag) {
1619 if (is_array($tag)) {
1620 $tag = array_map('nitropack_filter_tag', $tag);
1621 } else {
1622 $tag = nitropack_filter_tag($tag);
1623 }
1624 }
1625
1626 if (!$url && !$tag) {
1627 $nitro->purgeLocalCache(true);
1628 }
1629
1630 $nitro->purgeCache($url, $tag, $type, $reason);
1631
1632 if (defined('NITROPACK_DEBUG_MODE')) {
1633 do_action('nitropack_debug_purge', $url, $tag, $reason);
1634 }
1635
1636 try {
1637 do_action('nitropack_integration_purge_url', $homeUrl);
1638
1639 if ($tag) {
1640 do_action('nitropack_integration_purge_all');
1641 } else if ($url) {
1642 do_action('nitropack_integration_purge_url', $url);
1643 } else {
1644 do_action('nitropack_integration_purge_all');
1645 }
1646 } catch (\Exception $e) {
1647 // Exception while signaling 3rd party integration addons to purge their cache
1648 }
1649 } catch (\Exception $e) {
1650 return false;
1651 }
1652
1653 return true;
1654 }
1655
1656 return false;
1657 }
1658
1659 /**
1660 * @param string|null $url
1661 * @return bool
1662 */
1663 function nitropack_sdk_purge_local($url = NULL) {
1664 if (null === $nitro = get_nitropack_sdk()) {
1665 return false;
1666 }
1667
1668 try {
1669 if ($url) {
1670 $nitro->purgeLocalUrlCache($url);
1671 do_action('nitropack_integration_purge_url', $url);
1672 return true;
1673 }
1674
1675 $nitro->purgeLocalCache(true);
1676
1677 try {
1678 do_action('nitropack_integration_purge_all');
1679 } catch (\Exception $e) {
1680 // Exception while signaling our 3rd party integration addons to purge their cache
1681 }
1682
1683 return true;
1684 } catch (\Exception $e) {
1685 return false;
1686 }
1687 }
1688
1689 /**
1690 * @param string|null $url
1691 * @return bool
1692 */
1693 function nitropack_sdk_invalidate_local($url = NULL) {
1694 if (null === $nitro = get_nitropack_sdk()) {
1695 return false;
1696 }
1697
1698 try {
1699 if ($url) {
1700 $nitro->invalidateLocalUrlCache($url);
1701 do_action('nitropack_integration_purge_url', $url);
1702 return true;
1703 }
1704
1705 $nitro->invalidateLocalCache(true);
1706
1707 try {
1708 do_action('nitropack_integration_purge_all');
1709 } catch (\Exception $e) {
1710 // Exception while signaling our 3rd party integration addons to purge their cache
1711 }
1712
1713 return true;
1714 } catch (\Exception $e) {
1715 return false;
1716 }
1717 }
1718
1719 function nitropack_sdk_delete_backlog() {
1720 if (null !== $nitro = get_nitropack_sdk()) {
1721 try {
1722 if ($nitro->backlog->exists()) {
1723 $nitro->backlog->delete();
1724 }
1725 } catch (\Exception $e) {
1726 return false;
1727 }
1728
1729 return true;
1730 }
1731
1732 return false;
1733 }
1734
1735 function nitropack_purge($url = NULL, $tag = NULL, $reason = NULL) {
1736 if ($tag != "pageType:home") {
1737 $siteConfig = nitropack_get_site_config();
1738 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
1739 nitropack_log_invalidate($homeUrl, "pageType:home", $reason);
1740 }
1741
1742 if ($tag != "pageType:archive") {
1743 nitropack_log_invalidate(NULL, "pageType:archive", $reason);
1744 }
1745
1746 nitropack_log_purge($url, $tag, $reason);
1747 }
1748
1749 function nitropack_log_purge($url = NULL, $tag = NULL, $reason = NULL) {
1750 global $np_loggedPurges;
1751 if ($tag && is_array($tag)) {
1752 foreach ($tag as $tagSingle) {
1753 nitropack_log_purge($url, $tagSingle, $reason);
1754 }
1755 return;
1756 }
1757
1758 $keyBase = "";
1759 if ($url) {
1760 $keyBase .= $url;
1761 }
1762
1763 if ($tag) {
1764 $tag = nitropack_filter_tag($tag);
1765 $keyBase .= $tag;
1766 }
1767
1768 $purgeRequestKey = md5($keyBase);
1769 if (is_array($np_loggedPurges) && array_key_exists($purgeRequestKey, $np_loggedPurges)) {
1770 $np_loggedPurges[$purgeRequestKey]["reason"] = $reason;
1771 $np_loggedPurges[$purgeRequestKey]["priority"]++;
1772 } else {
1773 $np_loggedPurges[$purgeRequestKey] = array(
1774 "url" => $url,
1775 "tag" => $tag,
1776 "reason" => $reason,
1777 "priority" => 1
1778 );
1779 }
1780 }
1781
1782 function nitropack_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
1783 if ($tag != "pageType:home") {
1784 $siteConfig = nitropack_get_site_config();
1785 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
1786 nitropack_log_invalidate($homeUrl, "pageType:home", $reason);
1787 }
1788
1789 if ($tag != "pageType:archive") {
1790 nitropack_log_invalidate(NULL, "pageType:archive", $reason);
1791 }
1792
1793 nitropack_log_invalidate($url, $tag, $reason);
1794 }
1795
1796 function nitropack_log_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
1797 global $np_loggedInvalidations;
1798 if ($tag && is_array($tag)) {
1799 foreach ($tag as $tagSingle) {
1800 nitropack_log_invalidate($url, $tagSingle, $reason);
1801 }
1802 return;
1803 }
1804
1805 $keyBase = "";
1806 if ($url) {
1807 $keyBase .= $url;
1808 }
1809
1810 if ($tag) {
1811 $tag = nitropack_filter_tag($tag);
1812 $keyBase .= $tag;
1813 }
1814
1815 $invalidateRequestKey = md5($keyBase);
1816 if (is_array($np_loggedInvalidations) && array_key_exists($invalidateRequestKey, $np_loggedInvalidations)) {
1817 $np_loggedInvalidations[$invalidateRequestKey]["reason"] = $reason;
1818 $np_loggedInvalidations[$invalidateRequestKey]["priority"]++;
1819 } else {
1820 $np_loggedInvalidations[$invalidateRequestKey] = array(
1821 "url" => $url,
1822 "tag" => $tag,
1823 "reason" => $reason,
1824 "priority" => 1
1825 );
1826 }
1827 }
1828
1829 function nitropack_queue_sort($a, $b) {
1830 if ($a["priority"] == $b["priority"]) {
1831 return 0;
1832 }
1833 return ($a["priority"] < $b["priority"]) ? -1 : 1;
1834 }
1835
1836 function nitropack_execute_purges() {
1837 global $np_loggedPurges;
1838 // if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1839 // return;
1840 // }
1841 if (!empty($np_loggedPurges)) {
1842 uasort($np_loggedPurges, "nitropack_queue_sort");
1843 foreach ($np_loggedPurges as $requestKey => $data) {
1844 nitropack_sdk_purge($data["url"], $data["tag"], $data["reason"]);
1845 }
1846 }
1847 }
1848
1849 function nitropack_execute_invalidations() {
1850 global $np_loggedInvalidations;
1851 // if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1852 // return;
1853 // }
1854 if (!empty($np_loggedInvalidations)) {
1855 uasort($np_loggedInvalidations, "nitropack_queue_sort");
1856 foreach ($np_loggedInvalidations as $requestKey => $data) {
1857 nitropack_sdk_invalidate($data["url"], $data["tag"], $data["reason"]);
1858 }
1859 }
1860 }
1861
1862 function nitropack_execute_warmups() {
1863 if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1864 return;
1865 }
1866
1867 try {
1868 if (!empty(\NitroPack\WordPress\NitroPack::$np_loggedWarmups) && (null !== $nitro = get_nitropack_sdk())) {
1869 $warmupStats = $nitro->getApi()->getWarmupStats();
1870 if (!empty($warmupStats["status"])) {
1871 foreach (array_unique(\NitroPack\WordPress\NitroPack::$np_loggedWarmups) as $url) {
1872 $nitro->getApi()->runWarmup($url);
1873 }
1874 }
1875 }
1876 } catch (\Exception $e) {
1877 }
1878 }
1879
1880 function nitropack_fetch_config() {
1881 if (null !== $nitro = get_nitropack_sdk()) {
1882 try {
1883 $nitro->fetchConfig();
1884 } catch (\Exception $e) {
1885 }
1886 }
1887 }
1888
1889 function nitropack_theme_handler($event = NULL) {
1890 if (!get_option("nitropack-autoCachePurge", 1)) return;
1891
1892 $msg = $event ? $event : 'Theme switched';
1893
1894 try {
1895 nitropack_sdk_purge(NULL, NULL, $msg); // purge entire cache
1896 } catch (\Exception $e) {
1897 }
1898 }
1899
1900 function nitropack_purge_cache() {
1901 nitropack_verify_ajax_nonce($_REQUEST);
1902 try {
1903 if (nitropack_sdk_purge(NULL, NULL, 'Light purge of all caches', \NitroPack\SDK\PurgeType::LIGHT_PURGE)) {
1904 nitropack_json_and_exit(array(
1905 "type" => "success",
1906 "message" => __('Cache has been purged successfully!', 'nitropack')
1907 ));
1908 }
1909 } catch (\Exception $e) {
1910 }
1911
1912 nitropack_json_and_exit(array(
1913 "type" => "error",
1914 "message" => __('Error! There was an error and the cache was not purged!', 'nitropack')
1915 ));
1916 }
1917
1918 function nitropack_invalidate_cache() {
1919 nitropack_verify_ajax_nonce($_REQUEST);
1920 try {
1921 if (nitropack_sdk_invalidate(NULL, NULL, 'Manual invalidation of all pages')) {
1922 nitropack_json_and_exit(array(
1923 "type" => "success",
1924 "message" => __('Cache has been invalidated successfully!', 'nitropack')
1925
1926 ));
1927 }
1928 } catch (\Exception $e) {
1929 }
1930
1931
1932 nitropack_json_and_exit(array(
1933 "type" => "error",
1934 "message" => __('There was an error and the cache was not invalidated!', 'nitropack')
1935 ));
1936 }
1937
1938 function nitropack_clear_residual_cache() {
1939 nitropack_verify_ajax_nonce($_REQUEST);
1940 $gde = !empty($_POST["gde"]) ? $_POST["gde"] : NULL;
1941 if ($gde && array_key_exists($gde, NitroPack\Integration\Plugin\RC::$modules)) {
1942 $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
1943 if (!in_array(false, $result)) {
1944 nitropack_json_and_exit(array(
1945 "type" => "success",
1946 "message" => __('Success! The residual cache has been cleared successfully!', 'nitropack')
1947 ));
1948 }
1949 }
1950 nitropack_json_and_exit(array(
1951 "type" => "error",
1952 "message" => __('Error! There was an error clearing the residual cache!', 'nitropack')
1953 ));
1954 }
1955
1956 function nitropack_json_and_exit($array) {
1957 if (nitropack_is_wp_cli()) {
1958 $type = NULL;
1959 if (array_key_exists("status", $array)) {
1960 $type = $array["status"];
1961 } else if (array_key_exists("type", $array)) {
1962 $type = $array["type"];
1963 }
1964
1965 if ($type && array_key_exists("message", $array)) {
1966 if ($type == "success") {
1967 WP_CLI::success($array["message"]);
1968 } else {
1969 WP_CLI::error($array["message"]);
1970 }
1971 }
1972 } else {
1973 echo json_encode($array);
1974 }
1975 exit;
1976 }
1977 function nitropack_admin_toast_msgs($type) {
1978 if ($type === 'success') {
1979 $msg = esc_html__('Settings updated.', 'nitropack');
1980 } else {
1981 $msg = esc_html__('Something went wrong.', 'nitropack');
1982 }
1983 return $msg;
1984 }
1985 function nitropack_verify_ajax_nonce($request_data) {
1986 // If not an ajax request
1987 if (!defined('DOING_AJAX') || !DOING_AJAX) {
1988 return;
1989 }
1990
1991 // If nonce fails verification
1992 if (empty($request_data['nonce']) || !wp_verify_nonce($request_data['nonce'], NITROPACK_NONCE)) {
1993 wp_die('Unauthorized request');
1994 }
1995 }
1996
1997 function nitropack_has_post_important_change($post) {
1998 $prevPost = nitropack_get_post_pre_update($post);
1999 return $prevPost && ($prevPost->post_title != $post->post_title || $prevPost->post_name != $post->post_name || $prevPost->post_excerpt != $post->post_excerpt);
2000 }
2001
2002 function nitropack_purge_single_cache() {
2003 nitropack_verify_ajax_nonce($_REQUEST);
2004 if (!empty($_POST["postId"]) && is_numeric($_POST["postId"])) {
2005 $postId = $_POST["postId"];
2006 $postUrl = !empty($_POST["postUrl"]) ? $_POST["postUrl"] : NULL;
2007 $reason = sprintf("Manual purge of post %s via the WordPress admin panel", $postId);
2008 $tag = $postId > 0 ? "single:$postId" : NULL;
2009
2010 if ($postUrl) {
2011 if (is_array($postUrl)) {
2012 foreach ($postUrl as &$url) {
2013 $url = nitropack_sanitize_url_input($url);
2014 }
2015 } else {
2016 $postUrl = nitropack_sanitize_url_input($postUrl);
2017 $reason = "Manual purge of " . $postUrl;
2018 }
2019 }
2020
2021 try {
2022 if (nitropack_sdk_purge($postUrl, $tag, $reason)) {
2023 nitropack_json_and_exit(array(
2024 "type" => "success",
2025 "message" => __('Success! Cache has been purged successfully!', 'nitropack')
2026 ));
2027 }
2028 } catch (\Exception $e) {
2029 }
2030 }
2031
2032 nitropack_json_and_exit(array(
2033 "type" => "error",
2034 "message" => __('Error! There was an error and the cache was not purged!', 'nitropack')
2035 ));
2036 }
2037
2038 function nitropack_purge_entire_cache() {
2039 nitropack_verify_ajax_nonce($_REQUEST);
2040 try {
2041 if (nitropack_sdk_purge(null, null, 'Manual purge of all pages')) {
2042 nitropack_json_and_exit(array(
2043 "type" => "success",
2044 "message" => __('Success! Cache has been purged successfully!', 'nitropack')
2045 ));
2046 }
2047 } catch (\Exception $e) {
2048 }
2049
2050 nitropack_json_and_exit(array(
2051 "type" => "error",
2052 "message" => __('Error! There was an error and the cache was not purged!', 'nitropack')
2053 ));
2054 }
2055
2056 function nitropack_invalidate_single_cache() {
2057 nitropack_verify_ajax_nonce($_REQUEST);
2058 if (!empty($_POST["postId"]) && is_numeric($_POST["postId"])) {
2059 $postId = $_POST["postId"];
2060 $postUrl = !empty($_POST["postUrl"]) ? $_POST["postUrl"] : NULL;
2061 $reason = sprintf("Manual invalidation of post %s via the WordPress admin panel", $postId);
2062 $tag = $postId > 0 ? "single:$postId" : NULL;
2063
2064 if ($postUrl) {
2065 if (is_array($postUrl)) {
2066 foreach ($postUrl as &$url) {
2067 $url = nitropack_sanitize_url_input($url);
2068 }
2069 } else {
2070 $postUrl = nitropack_sanitize_url_input($postUrl);
2071 $reason = "Manual invalidation of " . $postUrl;
2072 }
2073 }
2074
2075 try {
2076 if (nitropack_sdk_invalidate($postUrl, $tag, $reason)) {
2077 nitropack_json_and_exit(array(
2078 "type" => "success",
2079 "message" => __('Success! Cache has been invalidated successfully!', 'nitropack')
2080 ));
2081 }
2082 } catch (\Exception $e) {
2083 }
2084 }
2085
2086 nitropack_json_and_exit(array(
2087 "type" => "error",
2088 "message" => __('Error! There was an error and the cache was not invalidated!', 'nitropack')
2089 ));
2090 }
2091
2092 function nitropack_clean_post_cache($post, $taxonomies = NULL, $hasImportantChangeInPost = NULL, $reason = NULL, $usePurge = false) {
2093 try {
2094 $postID = $post->ID;
2095 $postType = isset($post->post_type) ? $post->post_type : "post";
2096 $nicePostTypeLabel = nitropack_get_nice_post_type_label($postType);
2097 $reason = $reason ? $reason : sprintf("Updated %s '%s'", $nicePostTypeLabel, $post->post_title);
2098 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
2099
2100 if (in_array($postType, $cacheableObjectTypes)) {
2101 if ($usePurge) {
2102 // We only purge the single pages because they have to immediately stop serving cache
2103 // These pages no longer exists and if their URL is requested we must not server cache
2104 nitropack_purge(NULL, "single:$postID", $reason);
2105 } else {
2106 nitropack_invalidate(NULL, "single:$postID", $reason);
2107 }
2108
2109 nitropack_invalidate(NULL, "post:$postID", $reason);
2110
2111 if ($hasImportantChangeInPost === NULL) {
2112 $hasImportantChangeInPost = nitropack_has_post_important_change($post);
2113 }
2114 if ($taxonomies === NULL) {
2115 if ($hasImportantChangeInPost) { // This change should be reflected in all taxonomy pages
2116 $taxonomies = array('related' => nitropack_get_taxonomies($post));
2117 } else { // No important change, so only update taxonomy pages which have been added or removed from the post
2118 $taxonomies = nitropack_get_taxonomies_for_update($post);
2119 }
2120 }
2121 if ($taxonomies) {
2122 if (!empty($taxonomies['added'])) { // taxonomies that the post was just added to, must purge all pages for these taxonomies
2123 foreach ($taxonomies['added'] as $term_taxonomy_id) {
2124 nitropack_invalidate(NULL, "tax:$term_taxonomy_id", $reason);
2125 }
2126 }
2127 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:)
2128 foreach ($taxonomies['deleted'] as $term_taxonomy_id) {
2129 nitropack_invalidate(NULL, "taxpost:$term_taxonomy_id:$postID", $reason);
2130 }
2131 }
2132 if (!empty($taxonomies['related'])) { // taxonomy pages that the post is linked to (also accounts for paginations via the taxpost: tag instead of only tax:)
2133 foreach ($taxonomies['related'] as $term_taxonomy_id) {
2134 nitropack_invalidate(NULL, "taxpost:$term_taxonomy_id:$postID", $reason);
2135 }
2136 }
2137 }
2138 } else {
2139 if ($post->public) {
2140 nitropack_invalidate(NULL, "post:$postID", $reason);
2141 }
2142
2143 $posts = get_post_ancestors($postID);
2144 foreach ($posts as $parentID) {
2145 $parent = get_post($parentID);
2146 nitropack_clean_post_cache($parent, false, false, $reason);
2147 }
2148 }
2149 } catch (\Exception $e) {
2150 }
2151 }
2152
2153 function nitropack_get_nice_post_type_label($postType) {
2154 $postTypes = get_post_types(array(
2155 "name" => $postType
2156 ), "objects");
2157
2158 return !empty($postTypes[$postType]) && !empty($postTypes[$postType]->labels) ? $postTypes[$postType]->labels->singular_name : $postType;
2159 }
2160
2161 function nitropack_handle_comment_transition($new, $old, $comment) {
2162 if (!get_option("nitropack-autoCachePurge", 1)) return;
2163
2164 try {
2165 $postID = $comment->comment_post_ID;
2166 $post = get_post($postID);
2167 $postType = isset($post->post_type) ? $post->post_type : "post";
2168 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
2169
2170 if (in_array($postType, $cacheableObjectTypes)) {
2171 nitropack_invalidate(NULL, "single:" . $postID, sprintf("Invalidation of '%s' due to changing related comment status", $post->post_title));
2172 }
2173 } catch (\Exception $e) {
2174 // TODO: Log the error
2175 }
2176 }
2177
2178 function nitropack_handle_comment_post($commentID, $isApproved) {
2179 if (!get_option("nitropack-autoCachePurge", 1) || $isApproved !== 1) return;
2180
2181 try {
2182 $comment = get_comment($commentID);
2183 $postID = $comment->comment_post_ID;
2184 $post = get_post($postID);
2185 nitropack_invalidate(NULL, "single:" . $postID, sprintf("Invalidation of '%s' due to posting a new approved comment", $post->post_title));
2186 } catch (\Exception $e) {
2187 // TODO: Log the error
2188 }
2189 }
2190
2191 function custom_reduce_stock_after_order_placed($order) {
2192
2193 if ((int)get_option('nitropack-stockReduceStatus') !== 1) return;
2194
2195 $items = $order->get_items();
2196
2197 foreach ($items as $item) {
2198 $product_id = $item->get_product_id();
2199 $product_url = get_permalink($product_id);
2200
2201 $stock_quantity = get_post_meta($product_id, '_stock', true);
2202
2203 if ($stock_quantity > 0) {
2204 nitropack_sdk_invalidate($product_url, NULL, 'Invalidated to adjust order quantity');
2205 }
2206 }
2207 }
2208
2209 function nitropack_detect_changes_and_clean_post_cache($post) {
2210
2211 $post_before = nitropack_get_post_pre_update($post);
2212 $ignoredComparisonKeys = array('post_modified', 'post_modified_gmt');
2213 $canCleanPostCache = false;
2214 $postStatesEqual = nitropack_compare_posts((array)$post_before, (array)$post, $ignoredComparisonKeys);
2215
2216 if ($postStatesEqual) {
2217 $taxCurrent = nitropack_get_taxonomies($post);
2218 $taxPreUpdate = nitropack_get_taxonomies_pre_update($post);
2219 $taxAreEqual = nitropack_compare_posts($taxCurrent, $taxPreUpdate);
2220 if ($taxAreEqual) {
2221 $metaCurrent = get_post_meta($post->ID);
2222 $metaPreUpdate = nitropack_get_meta_pre_update($post);
2223 $metaIsEqual = nitropack_compare_posts($metaCurrent, $metaPreUpdate);
2224 if (!$metaIsEqual) {
2225 $canCleanPostCache = true;
2226 }
2227 } else {
2228 $canCleanPostCache = true;
2229 }
2230 } else {
2231 $canCleanPostCache = true;
2232 }
2233
2234 if ($canCleanPostCache) {
2235 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink($post);
2236 nitropack_clean_post_cache($post);
2237 define('NITROPACK_PURGE_CACHE', true);
2238 }
2239 }
2240
2241 function nitropack_handle_post_transition($new, $old, $post) {
2242 if (wp_is_post_revision($post)) return;
2243 if (!empty($post->ID) && in_array($post->ID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs)) return;
2244 if (!get_option("nitropack-autoCachePurge", 1)) return;
2245
2246 try {
2247 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.
2248 return;
2249 }
2250
2251 $ignoredPostTypes = array(
2252 "revision",
2253 "scheduled-action",
2254 "flamingo_contact",
2255 "carts"/*WooCommerce Cart Reports*/
2256 );
2257
2258 $nicePostTypes = array(
2259 "post" => "Post",
2260 "page" => "Page",
2261 "tribe_events" => "Calendar Event",
2262 );
2263 $postType = isset($post->post_type) ? $post->post_type : "post";
2264 $nicePostTypeLabel = nitropack_get_nice_post_type_label($postType);
2265
2266 if (in_array($postType, $ignoredPostTypes)) return;
2267
2268 switch ($postType) {
2269 case "nav_menu_item":
2270 nitropack_invalidate(NULL, NULL, sprintf("Invalidation of all pages due to modifying menu entries"));
2271 break;
2272 case "customize_changeset":
2273 nitropack_invalidate(NULL, NULL, sprintf("Invalidation of all pages due to applying appearance customization"));
2274 break;
2275 case "custom_css":
2276 nitropack_invalidate(NULL, NULL, sprintf("Invalidation of all pages due to modifying custom CSS"));
2277 break;
2278 default:
2279 if ($new == "future") {
2280 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));
2281 } else if ($new === 'publish' && $old === 'trash') {
2282 nitropack_clean_post_cache($post, array('added' => nitropack_get_taxonomies($post)), true, sprintf("Invalidate related pages due to restoring %s '%s'", $nicePostTypeLabel, $post->post_title));
2283 } else if ($new == "publish" && $old != "publish") {
2284 $post->nicePostTypeLabel = $nicePostTypeLabel;
2285 set_transient($post->ID . '_np_first_publish', $post, 120);
2286 } else if ($new == 'publish' && $old != 'trash') {
2287 /* we need to handle the case here for new CPT posts to be optimized initially. No need to reoptimize an untrashed post */
2288 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink($post->ID);
2289 } else if ($new == "trash" && $old == "publish") {
2290 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);
2291 } else if ($new == "private" && $old == "publish") {
2292 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);
2293 } else if ($new == "draft" && $old == "publish") {
2294 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);
2295 } else if ($new != "trash") {
2296 if (get_option('nitropack-legacyPurge', 0) && !defined('NITROPACK_PURGE_CACHE')) {
2297 //Below if will be removed
2298 if ($post->post_author > 0) {
2299 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink($post);
2300 nitropack_clean_post_cache($post);
2301 define('NITROPACK_PURGE_CACHE', true);
2302 }
2303 } elseif (!defined('NITROPACK_PURGE_CACHE')) {
2304 nitropack_detect_changes_and_clean_post_cache($post);
2305 }
2306 }
2307 break;
2308 }
2309 } catch (\Exception $e) {
2310 // TODO: Log the error
2311 }
2312 }
2313
2314 function nitropack_handle_first_publish($post_id) {
2315 $first_publish_post = get_transient($post_id . '_np_first_publish', false);
2316
2317 if (!$first_publish_post) {
2318 return;
2319 }
2320
2321 try {
2322 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));
2323 nitropack_invalidate(NULL, "pageType:blogindex", 'Invalidation of blog page due to changing related post status');
2324 delete_transient($post_id . '_np_first_publish');
2325 } catch (\Exception $e) {
2326 // TODO: Log the error
2327 }
2328 }
2329
2330 function nitropack_postmeta_updated($meta_id, $object_id, $meta_key, $meta_value) {
2331 if ($meta_key !== '_edit_lock') {
2332 if (get_post_type($object_id) === 'product') {
2333 !defined('NITROPACK_PURGE_PRODUCT') && define('NITROPACK_PURGE_PRODUCT', true);
2334 }
2335 }
2336 }
2337
2338 function nitropack_sot($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) {
2339 if (!get_option("nitropack-autoCachePurge", 1)) return;
2340
2341 $post = get_post($object_id);
2342 $post_status = $post->post_status;
2343
2344 if ($post_status === 'auto-draft' || $post_status === 'draft') {
2345 return;
2346 }
2347
2348 if (!defined('NITROPACK_PURGE_CACHE')) {
2349 $purgeCache = !nitropack_compare_posts($tt_ids, $old_tt_ids);
2350 $cleanCache = $purgeCache ? "YES" : "NO";
2351 if ($purgeCache) {
2352 $post = get_post($object_id);
2353 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink($post);
2354 nitropack_clean_post_cache($post);
2355 define('NITROPACK_PURGE_CACHE', true);
2356 }
2357 }
2358 }
2359
2360 function nitropack_handle_product_updates($product, $updated) {
2361 if (!get_option("nitropack-autoCachePurge", 1)) return;
2362
2363 if (!defined('NITROPACK_PURGE_CACHE') && defined('NITROPACK_PURGE_PRODUCT')) {
2364 try {
2365 $post = get_post($product->get_id());
2366 $reasons = 'updated ';
2367 $reasons .= implode(',', $updated);
2368 \NitroPack\WordPress\NitroPack::$np_loggedWarmups[] = get_permalink($post);
2369 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
2370 define('NITROPACK_PURGE_CACHE', true);
2371 } catch (\Exception $e) {
2372 // TODO: Log the error
2373 }
2374 }
2375 }
2376
2377 function nitropack_post_link_listener($permalink, $post, $leavename) {
2378 if (is_object($post)) {
2379 nitropack_handle_the_post($post);
2380 }
2381
2382 return $permalink;
2383 }
2384
2385 function nitropack_handle_the_post($post) {
2386 global $np_customExpirationTimes, $np_queriedObj;
2387 if (defined('POSTEXPIRATOR_VERSION')) {
2388 $postExpiryDate = get_post_meta($post->ID, "_expiration-date", true);
2389 if (!empty($postExpiryDate) && $postExpiryDate > time()) { // We only need to look at future dates
2390 $np_customExpirationTimes[] = $postExpiryDate;
2391 }
2392 }
2393
2394 if (function_exists("sort_portfolio")) { // Portfolio Sorting plugin
2395 $portfolioStartDate = get_post_meta($post->ID, "start_date", true);
2396 $portfolioEndDate = get_post_meta($post->ID, "end_date", true);
2397 if (!empty($portfolioStartDate) && strtotime($portfolioStartDate) > time()) { // We only need to look at future dates
2398 $np_customExpirationTimes[] = strtotime($portfolioStartDate);
2399 } else if (!empty($portfolioEndDate) && strtotime($portfolioEndDate) > time()) { // We only need to look at future dates
2400 $np_customExpirationTimes[] = strtotime($portfolioEndDate);
2401 }
2402 }
2403
2404 $GLOBALS["NitroPack.tags"]["post:" . $post->ID] = 1;
2405 $GLOBALS["NitroPack.tags"]["author:" . $post->post_author] = 1;
2406 if ($np_queriedObj) {
2407 $GLOBALS["NitroPack.tags"]["taxpost:" . $np_queriedObj->term_taxonomy_id . ":" . $post->ID] = 1;
2408 }
2409 }
2410
2411 function nitropack_ignore_post_updates($postID) {
2412 \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs[] = $postID;
2413 }
2414
2415 function nitropack_get_taxonomies($post) {
2416 $term_taxonomy_ids = array();
2417 $taxonomies = get_object_taxonomies($post->post_type);
2418 foreach ($taxonomies as $taxonomy) {
2419 $terms = get_the_terms($post->ID, $taxonomy);
2420 if (!empty($terms)) {
2421 foreach ($terms as $term) {
2422 $term_taxonomy_ids[] = $term->term_taxonomy_id;
2423 }
2424 }
2425 }
2426 return $term_taxonomy_ids;
2427 }
2428
2429 function nitropack_get_taxonomies_for_update($post) {
2430 $prevTaxonomies = nitropack_get_taxonomies_pre_update($post);
2431 $newTaxonomies = nitropack_get_taxonomies($post);
2432 $intersection = array_intersect($newTaxonomies, $prevTaxonomies);
2433 $prevTaxonomies = array_diff($prevTaxonomies, $intersection);
2434 $newTaxonomies = array_diff($newTaxonomies, $intersection);
2435 return array(
2436 "added" => array_diff($newTaxonomies, $prevTaxonomies),
2437 "deleted" => array_diff($prevTaxonomies, $newTaxonomies)
2438 );
2439 }
2440
2441 function nitropack_get_post_pre_update($post) {
2442 return !empty(\NitroPack\WordPress\NitroPack::$preUpdatePosts[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdatePosts[$post->ID] : NULL;
2443 }
2444
2445 function nitropack_get_taxonomies_pre_update($post) {
2446 return !empty(\NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$post->ID] : array();
2447 }
2448
2449 function nitropack_get_meta_pre_update($post) {
2450 return !empty(\NitroPack\WordPress\NitroPack::$preUpdateMeta[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdateMeta[$post->ID] : array();
2451 }
2452
2453 function nitropack_log_post_pre_update($postID) {
2454 if (in_array($postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs)) return;
2455
2456
2457 $post = get_post($postID);
2458 \NitroPack\WordPress\NitroPack::$preUpdatePosts[$postID] = $post;
2459 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$postID] = nitropack_get_taxonomies($post);
2460 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2461 \NitroPack\WordPress\NitroPack::$preUpdateMeta[$postID] = get_post_meta($postID);
2462 }
2463
2464 function nitropack_log_product_pre_api_update($product, $request, $creating) {
2465
2466 if (!$creating) {
2467
2468 $postID = $product->get_id();
2469 if (in_array($postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs)) return;
2470
2471
2472 $post = get_post($postID);
2473 \NitroPack\WordPress\NitroPack::$preUpdatePosts[$postID] = $post;
2474 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$postID] = nitropack_get_taxonomies($post);
2475 //Is post meta updated at this point? Or maybe this block should be moved to a different action?
2476 \NitroPack\WordPress\NitroPack::$preUpdateMeta[$postID] = get_post_meta($postID);
2477 }
2478
2479 return $product;
2480 }
2481
2482 function nitropack_compare_posts(array $p1, array $p2, $ignoredKeys = null) {
2483 $p1keys = array_keys($p1);
2484 $p2keys = array_keys($p2);
2485 if (count($p1keys) !== count($p2keys)) {
2486 return false;
2487 }
2488 if (array_diff($p1keys, $p2keys)) {
2489 return false;
2490 }
2491
2492 $isP1assoc = false;
2493 $expectedKey = 0;
2494 foreach ($p2 as $i => $_) {
2495 if ($i !== $expectedKey) {
2496 $isP1assoc = true;
2497 }
2498 $expectedKey++;
2499 }
2500
2501 $isP2assoc = false;
2502 $expectedKey = 0;
2503 foreach ($p2 as $i => $_) {
2504 if ($i !== $expectedKey) {
2505 $isP2assoc = true;
2506 }
2507 $expectedKey++;
2508 }
2509
2510 if ($isP1assoc !== $isP2assoc) {
2511 return false;
2512 }
2513
2514 if (!$isP1assoc && !$isP2assoc) {
2515 sort($p1);
2516 sort($p2);
2517 }
2518
2519 foreach ($p1 as $poKey => $poVal) {
2520 if ($ignoredKeys && in_array($poKey, $ignoredKeys, true)) {
2521 continue;
2522 }
2523 $checkpoint01 = is_array($poVal);
2524 $checkpoint02 = is_array($p2[$poKey]);
2525 if ($checkpoint01 && $checkpoint02) {
2526 if (!nitropack_compare_posts($poVal, $p2[$poKey], $ignoredKeys, 'Re:')) { //'Re:' left for debug purpose to destinguish between main and recursive call
2527 return false;
2528 }
2529 } elseif (!$checkpoint01 && !$checkpoint02) {
2530 if ($poVal != $p2[$poKey]) {
2531 return false;
2532 }
2533 } else {
2534 return false;
2535 }
2536 }
2537 return true;
2538 }
2539
2540 function nitropack_filter_tag($tag) {
2541 return preg_replace("/[^a-zA-Z0-9:]/", ":", $tag);
2542 }
2543
2544 function nitropack_log_tags() {
2545 if (!empty($GLOBALS["NitroPack.instance"]) && !empty($GLOBALS["NitroPack.tags"])) {
2546 $nitro = $GLOBALS["NitroPack.instance"];
2547 $layout = nitropack_get_layout();
2548 try {
2549 $config = $nitro->getConfig();
2550 $useHeader = !empty($config->TagsViaHeader);
2551
2552 if ($layout == "home") {
2553 if ($useHeader) {
2554 nitropack_header("x-nitro-tags:pageType:home");
2555 } else {
2556 $nitro->getApi()->tagUrl($nitro->getUrl(), "pageType:home");
2557 }
2558 } else if ($layout == "archive") {
2559 if ($useHeader) {
2560 nitropack_header("x-nitro-tags:pageType:archive");
2561 } else {
2562 $nitro->getApi()->tagUrl($nitro->getUrl(), "pageType:archive");
2563 }
2564 } else {
2565 if ($useHeader && count($GLOBALS["NitroPack.tags"]) <= 100) {
2566 nitropack_header("x-nitro-tags:" . implode("|", array_map("nitropack_filter_tag", array_keys($GLOBALS["NitroPack.tags"]))));
2567 } else {
2568 $nitro->getApi()->tagUrl($nitro->getUrl(), array_map("nitropack_filter_tag", array_keys($GLOBALS["NitroPack.tags"])));
2569 }
2570 }
2571 } catch (\Exception $e) {
2572 }
2573 }
2574 }
2575
2576 function nitropack_extend_nonce_life($life) {
2577 // Nonce life should be extended only:
2578 // - if NitroPack is connected for this site
2579 // - if the current value is shorter than the life time of a cache file
2580 // - if no user is logged in
2581 // - for cacheable requests
2582 //
2583 // Reasons why we might need to extend the nonce life time even for requests that are not cacheable:
2584 // - 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)
2585 // - 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.)
2586
2587 if ((null !== $nitro = get_nitropack_sdk())) {
2588 $siteConfig = nitropack_get_site_config();
2589 if ($siteConfig && !empty($siteConfig["isDlmActive"]) && !empty($siteConfig["dlm_downloading_url"]) && !empty($siteConfig["dlm_download_endpoint"])) {
2590 $currentUrl = $nitro->getUrl();
2591 if (strpos($currentUrl, $siteConfig["dlm_downloading_url"]) !== false || strpos($currentUrl, $siteConfig["dlm_download_endpoint"]) !== false) {
2592 // Do not modify the nonce times on pages of Download Monitor
2593 return $life;
2594 }
2595 }
2596 $cacheExpiration = $nitro->getConfig()->PageCache->ExpireTime;
2597 return $cacheExpiration > $life ? $cacheExpiration : $life; // Extend the life of cacheable nonces up to the cache expiration time if needed
2598 }
2599 return $life;
2600 }
2601
2602 function nitropack_reconfigure_webhooks() {
2603 nitropack_verify_ajax_nonce($_REQUEST);
2604 $siteConfig = nitropack_get_site_config();
2605
2606 if ($siteConfig && !empty($siteConfig["siteId"])) {
2607 $siteId = $siteConfig["siteId"];
2608 if (null !== $nitro = get_nitropack_sdk()) {
2609 $token = nitropack_generate_webhook_token($siteId);
2610 try {
2611 nitropack_setup_webhooks($nitro, $token);
2612 update_option("nitropack-webhookToken", $token);
2613 nitropack_json_and_exit(array("status" => "success", 'message' => __('Connection reconfigured successfully', 'nitropack')));
2614 } catch (\NitroPack\SDK\WebhookException $e) {
2615 nitropack_json_and_exit(array("status" => "error", "message" => __('Webhook Error: ', 'nitropack') . $e->getMessage()));
2616 }
2617 } else {
2618 nitropack_json_and_exit(array("status" => "error", "message" => __('Unable to get SDK instance', 'nitropack')));
2619 }
2620 } else {
2621 nitropack_json_and_exit(array("status" => "error", "message" => __('Incomplete site config. Please reinstall the plugin!', 'nitropack')));
2622 }
2623 }
2624
2625 function nitropack_generate_webhook_token($siteId) {
2626 return md5(__FILE__ . ":" . $siteId);
2627 }
2628
2629 function nitropack_verify_connect_ajax() {
2630 nitropack_verify_ajax_nonce($_REQUEST);
2631 $siteId = !empty($_POST["siteId"]) ? $_POST["siteId"] : "";
2632 $siteSecret = !empty($_POST["siteSecret"]) ? $_POST["siteSecret"] : "";
2633 nitropack_verify_connect($siteId, $siteSecret);
2634 }
2635
2636 function nitropack_check_func_availability($func_name) {
2637 if (function_exists('ini_get')) {
2638 $existsResult = stripos(ini_get('disable_functions'), $func_name) === false;
2639 } else {
2640 $existsResult = function_exists($func_name);
2641 }
2642 return $existsResult;
2643 }
2644
2645 function nitropack_prevent_connecting($nitroSDK) {
2646 $remoteUrl = $nitroSDK->getApi()->getWebhook("config");
2647 if (empty($remoteUrl)) {
2648 return false;
2649 }
2650 $siteConfig = nitropack_get_site_config();
2651 $localUrl = new \NitroPack\Url\Url($siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url());
2652 $localHome = strtolower($localUrl->getHost() . $localUrl->getPath());
2653 $storedUrl = new \NitroPack\Url\Url($remoteUrl);
2654 $remoteHome = strtolower($storedUrl->getHost() . $storedUrl->getPath());
2655 if ($localHome === $remoteHome) {
2656 return false;
2657 }
2658 return array('local' => $localHome, 'remote' => $remoteHome);
2659 }
2660
2661 function nitropack_verify_connect($siteId, $siteSecret) {
2662 if (!nitropack_check_func_availability('stream_socket_client')) {
2663 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>"));
2664 }
2665
2666 if (!nitropack_check_func_availability('stream_context_create')) {
2667 // <a href=\"https://support.nitropack.io/hc/en-us/articles/360020898137\" target=\"_blank\" rel=\"noreferrer noopener\">Read more</a>
2668 // ^ Similar article needed on website for stream_context_create function
2669 nitropack_json_and_exit(array("status" => "error", "message" => "stream_context_create function is not allowed by your host."));
2670 }
2671
2672 if (empty($siteId) || empty($siteSecret)) {
2673 nitropack_json_and_exit(array("status" => "error", "message" => __('API Key and API Secret Key cannot be empty', 'nitropack')));
2674 }
2675
2676 //remove tags and whitespaces
2677 $siteId = trim(esc_attr($siteId));
2678 $siteSecret = trim(esc_attr($siteSecret));
2679
2680 if (!nitropack_validate_site_id($siteId) || !nitropack_validate_site_secret($siteSecret)) {
2681 nitropack_json_and_exit(array("status" => "error", "message" => __('Invalid API Key or API Secret Key value', 'nitropack')));
2682 }
2683
2684 try {
2685 $blogId = get_current_blog_id();
2686 if (null !== $nitro = get_nitropack_sdk($siteId, $siteSecret, NULL, true)) {
2687 if (!$nitro->checkHealthStatus()) {
2688 nitropack_json_and_exit(array(
2689 "status" => "error",
2690 "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>."
2691 ));
2692 }
2693
2694 $preventParing = apply_filters('nitropack_prevent_connect', nitropack_prevent_connecting($nitro));
2695 if ($preventParing) {
2696 nitropack_json_and_exit(array(
2697 "status" => "error",
2698 "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/>
2699 <a href='https://support.nitropack.io/hc/en-us/articles/4405254569745' target='_blank' rel='noreferrer noopener'>Read more</a>"
2700 ));
2701 }
2702 $token = nitropack_generate_webhook_token($siteId);
2703 update_option("nitropack-webhookToken", $token);
2704 update_option("nitropack-enableCompression", -1);
2705 update_option("nitropack-autoCachePurge", get_option("nitropack-autoCachePurge", 1));
2706 update_option("nitropack-cacheableObjectTypes", nitropack_get_default_cacheable_object_types());
2707
2708
2709 nitropack_setup_webhooks($nitro, $token);
2710
2711 // _icl_current_language is WPML cookie, it is added here for compatibility with this module
2712 $customVariationCookies = array("np_wc_currency", "np_wc_currency_language", "_icl_current_language");
2713 $variationCookies = $nitro->getApi()->getVariationCookies();
2714 foreach ($variationCookies as $cookie) {
2715 $index = array_search($cookie["name"], $customVariationCookies);
2716 if ($index !== false) {
2717 array_splice($customVariationCookies, $index, 1);
2718 }
2719 }
2720
2721 foreach ($customVariationCookies as $cookieName) {
2722 $nitro->getApi()->setVariationCookie($cookieName);
2723 }
2724
2725 $nitro->fetchConfig(); // Reload the variation cookies
2726
2727 get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId);
2728 nitropack_install_advanced_cache();
2729
2730 try {
2731 do_action('nitropack_integration_purge_all');
2732 } catch (\Exception $e) {
2733 // Exception while signaling our 3rd party integration addons to purge their cache
2734 }
2735
2736 nitropack_event("connect", $nitro);
2737 nitropack_event("enable_extension", $nitro);
2738
2739 // Optimize front page
2740 $siteConfig = nitropack_get_site_config();
2741 if ($siteConfig) {
2742 $nitro->getApi()->runWarmup([$siteConfig['home_url']], true); // force run a warmup on the home page
2743 }
2744
2745
2746 nitropack_json_and_exit(array(
2747 "status" => "success",
2748 "message" => __("Connected", "nitropack")
2749 ));
2750 }
2751 } catch (\NitroPack\SDK\WebhookException $e) {
2752 nitropack_json_and_exit(array("status" => "error", "message" => $e->getMessage()));
2753 } catch (\NitroPack\SDK\StorageException $e) {
2754 nitropack_json_and_exit(array("status" => "error", "message" => __('Permission Error: ', 'nitropack') . $e->getMessage()));
2755 } catch (\NitroPack\SDK\EmptyConfigException $e) {
2756 nitropack_json_and_exit(array("status" => "error", "message" => __('Error while fetching remote config: ', 'nitropack') . $e->getMessage()));
2757 } catch (\NitroPack\HttpClient\Exceptions\SocketOpenException $e) {
2758 nitropack_json_and_exit(array("status" => "error", "message" => __('Can\'t establish connection with NitroPack\'s servers', 'nitropack')));
2759 } catch (\Exception $e) {
2760 nitropack_json_and_exit(array("status" => "error", "message" => __('Incorrect API credentials. Please make sure that you copied them correctly and try again.', 'nitropack')));
2761 }
2762
2763 nitropack_json_and_exit(array("status" => "error"));
2764 }
2765
2766 function nitropack_reset_webhooks($nitroSDK) {
2767 $nitroSDK->getApi()->unsetWebhook("config");
2768 $nitroSDK->getApi()->unsetWebhook("cache_clear");
2769 $nitroSDK->getApi()->unsetWebhook("cache_ready");
2770 }
2771
2772 function nitropack_setup_webhooks($nitro, $token = NULL) {
2773 if (!$nitro || !$token) {
2774 throw new \NitroPack\SDK\WebhookException('Webhook token cannot be empty.');
2775 }
2776
2777 $homeUrl = strtolower(get_home_url());
2778 $configUrl = new \NitroPack\Url\Url($homeUrl . "?nitroWebhook=config&token=$token");
2779 $cacheClearUrl = new \NitroPack\Url\Url($homeUrl . "?nitroWebhook=cache_clear&token=$token");
2780 $cacheReadyUrl = new \NitroPack\Url\Url($homeUrl . "?nitroWebhook=cache_ready&token=$token");
2781
2782 $nitro->getApi()->setWebhook("config", $configUrl);
2783 $nitro->getApi()->setWebhook("cache_clear", $cacheClearUrl);
2784 $nitro->getApi()->setWebhook("cache_ready", $cacheReadyUrl);
2785 }
2786
2787 function nitropack_disconnect() {
2788 nitropack_verify_ajax_nonce($_REQUEST);
2789 nitropack_uninstall_advanced_cache();
2790
2791 try {
2792 nitropack_event("disconnect");
2793 if (null !== $nitro = get_nitropack_sdk()) {
2794 nitropack_reset_webhooks($nitro);
2795 }
2796 } catch (\Exception $e) {
2797 nitropack_json_and_exit(array("status" => "error", "message" => $e->getMessage()));
2798 }
2799
2800 get_nitropack()->unsetCurrentBlogConfig();
2801
2802 $hostingNoticeFile = nitropack_get_hosting_notice_file();
2803 if (file_exists($hostingNoticeFile)) {
2804 if (WP_DEBUG) {
2805 unlink($hostingNoticeFile);
2806 } else {
2807 @unlink($hostingNoticeFile);
2808 }
2809 }
2810
2811 nitropack_json_and_exit(array("status" => "success", "message" => __("Disconnected", "nitropack")));
2812 }
2813
2814 function nitropack_set_compression_ajax() {
2815 nitropack_verify_ajax_nonce($_REQUEST);
2816 $compressionStatus = !empty($_POST["data"]["compressionStatus"]);
2817 $updated = update_option("nitropack-enableCompression", (int)$compressionStatus);
2818 if ($updated) {
2819 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), "hasCompression" => $compressionStatus));
2820 } else {
2821 nitropack_json_and_exit(array(
2822 "type" => "error",
2823 "message" => nitropack_admin_toast_msgs('error')
2824 ));
2825 }
2826 }
2827
2828 function nitropack_set_auto_cache_purge_ajax() {
2829 nitropack_verify_ajax_nonce($_REQUEST);
2830 $autoCachePurgeStatus = !empty($_POST["autoCachePurgeStatus"]);
2831 $updated = update_option("nitropack-autoCachePurge", (int)$autoCachePurgeStatus);
2832 if ($updated) {
2833 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), 'autoCachePurgeStatus' => $autoCachePurgeStatus));
2834 } else {
2835 nitropack_json_and_exit(array(
2836 "type" => "error",
2837 "message" => nitropack_admin_toast_msgs('error')
2838 ));
2839 }
2840 }
2841
2842 function nitropack_set_cart_cache_ajax() {
2843 nitropack_verify_ajax_nonce($_REQUEST);
2844 if (get_nitropack()->isConnected() && nitropack_render_woocommerce_cart_cache_option()) {
2845 $cartCacheStatus = (int) (!empty($_POST["cartCacheStatus"]));
2846
2847 if ($cartCacheStatus == 1) {
2848 nitropack_enable_cart_cache();
2849 } else {
2850 nitropack_disable_cart_cache();
2851 }
2852 }
2853
2854 nitropack_json_and_exit(array(
2855 "type" => "error",
2856 "message" => nitropack_admin_toast_msgs('error')
2857 ));
2858 }
2859
2860 function nitropack_set_stock_reduce_status() {
2861 nitropack_verify_ajax_nonce($_REQUEST);
2862 $stockReduceStatus = !empty($_POST["data"]["stockReduceStatus"]);
2863 $updated = update_option("nitropack-stockReduceStatus", (int)$stockReduceStatus);
2864 if ($updated) {
2865 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), "stockReduceStatus" => $stockReduceStatus));
2866 } else {
2867 nitropack_json_and_exit(array(
2868 "type" => "error",
2869 "message" => nitropack_admin_toast_msgs('error')
2870 ));
2871 }
2872 }
2873
2874 function nitropack_set_bb_cache_purge_sync_ajax() {
2875 nitropack_verify_ajax_nonce($_REQUEST);
2876 $bbCacheSyncPurgeStatus = !empty($_POST["bbCachePurgeSyncStatus"]);
2877 $updated = update_option("nitropack-bbCacheSyncPurge", (int)$bbCacheSyncPurgeStatus);
2878 if ($updated) {
2879 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), 'bbCacheSyncPurgeStatus' => $bbCacheSyncPurgeStatus));
2880 } else {
2881 nitropack_json_and_exit(array(
2882 "type" => "error",
2883 "message" => nitropack_admin_toast_msgs('error')
2884 ));
2885 }
2886 }
2887
2888 function nitropack_set_legacy_purge_ajax() {
2889 nitropack_verify_ajax_nonce($_REQUEST);
2890 $legacyPurgeStatus = !empty($_POST["legacyPurgeStatus"]);
2891 $updated = update_option("nitropack-legacyPurge", (int)$legacyPurgeStatus);
2892 if ($updated) {
2893 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), 'legacyPurgeStatus' => $legacyPurgeStatus));
2894 } else {
2895 nitropack_json_and_exit(array(
2896 "type" => "error",
2897 "message" => nitropack_admin_toast_msgs('error')
2898 ));
2899 }
2900 }
2901
2902 function nitropack_set_cacheable_post_types() {
2903 nitropack_verify_ajax_nonce($_REQUEST);
2904 $currentCacheableObjectTypes = nitropack_get_cacheable_object_types();
2905 $cacheableObjectTypes = !empty($_POST["cacheableObjectTypes"]) ? $_POST["cacheableObjectTypes"] : array();
2906 update_option("nitropack-cacheableObjectTypes", $cacheableObjectTypes);
2907
2908 foreach ($currentCacheableObjectTypes as $objectType) {
2909 if (!in_array($objectType, $cacheableObjectTypes)) {
2910 nitropack_purge(NULL, "pageType:" . $objectType, "Optimizing '$objectType' pages was manually disabled");
2911 }
2912 }
2913
2914 nitropack_json_and_exit(array(
2915 "type" => "success",
2916 "message" => nitropack_admin_toast_msgs('success')
2917 ));
2918 }
2919
2920 function nitropack_test_compression_ajax() {
2921 nitropack_verify_ajax_nonce($_REQUEST);
2922 $hasCompression = true;
2923 try {
2924 if (\NitroPack\Integration\Hosting\Flywheel::detect()) { // Flywheel: Compression is enabled by default
2925 update_option("nitropack-enableCompression", 0);
2926 } else {
2927 require_once plugin_dir_path(__FILE__) . nitropack_trailingslashit('nitropack-sdk') . 'autoload.php';
2928 $http = new NitroPack\HttpClient\HttpClient(get_site_url());
2929 $http->setHeader("X-NitroPack-Request", 1);
2930 $http->timeout = 25;
2931 $http->fetch();
2932 $headers = $http->getHeaders();
2933 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
2934 update_option("nitropack-enableCompression", 0);
2935 $hasCompression = true;
2936 } else { // no compression, we must enable it from NitroPack
2937 update_option("nitropack-enableCompression", 1);
2938 $hasCompression = false;
2939 }
2940 }
2941 update_option("nitropack-checkedCompression", 1);
2942 } catch (\Exception $e) {
2943 nitropack_json_and_exit(array("type" => "error", "message" => nitropack_admin_toast_msgs('error')));
2944 }
2945
2946 nitropack_json_and_exit(array("type" => "success", "message" => nitropack_admin_toast_msgs('success'), "hasCompression" => $hasCompression));
2947 }
2948
2949 function nitropack_render_woocommerce_cart_cache_option() {
2950 return class_exists('WooCommerce');
2951 }
2952
2953 function nitropack_is_cart_cache_active() {
2954 $nitro = get_nitropack()->getSdk();
2955 if ($nitro) {
2956 $config = $nitro->getConfig();
2957 if (!empty($config->StatefulCache->Status) && !empty($config->StatefulCache->CartCache)) {
2958 return nitropack_is_cart_cache_available();
2959 }
2960 }
2961 return false;
2962 }
2963
2964 function nitropack_is_cart_cache_available() {
2965 $nitro = get_nitropack()->getSdk();
2966 if ($nitro) {
2967 $config = $nitro->getConfig();
2968 if (!empty($config->StatefulCache->isCartCacheAvailable)) {
2969 return true;
2970 }
2971 }
2972 return false;
2973 }
2974
2975 function nitropack_handle_compression_toggle($old_value, $new_value) {
2976 nitropack_update_blog_compression($new_value == 1);
2977 }
2978
2979 function nitropack_update_blog_compression($enableCompression = false) {
2980 if (get_nitropack()->isConnected()) {
2981 $siteConfig = nitropack_get_site_config();
2982 $siteId = $siteConfig["siteId"];
2983 $siteSecret = $siteConfig["siteSecret"];
2984 $blogId = get_current_blog_id();
2985 get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId, $enableCompression);
2986 }
2987 }
2988
2989 function nitropack_enable_warmup() {
2990 nitropack_verify_ajax_nonce($_REQUEST);
2991 if (null !== $nitro = get_nitropack_sdk()) {
2992 try {
2993 $nitro->getApi()->enableWarmup();
2994 $nitro->getApi()->setWarmupHomepage(get_home_url());
2995 $nitro->getApi()->runWarmup();
2996 } catch (\Exception $e) {
2997 }
2998
2999 nitropack_json_and_exit(array(
3000 "type" => "success",
3001 "message" => __('Success! Cache warmup has been enabled successfully!', 'nitropack')
3002 ));
3003 }
3004
3005 nitropack_json_and_exit(array(
3006 "type" => "error",
3007 "message" => __('Error! There was an error while enabling the cache warmup!', 'nitropack')
3008 ));
3009 }
3010
3011 function nitropack_disable_warmup() {
3012 nitropack_verify_ajax_nonce($_REQUEST);
3013 if (null !== $nitro = get_nitropack_sdk()) {
3014 try {
3015 $nitro->getApi()->disableWarmup();
3016 $nitro->getApi()->resetWarmup();
3017 delete_option('np_warmup_sitemap');
3018 } catch (\Exception $e) {
3019 }
3020
3021 nitropack_json_and_exit(array(
3022 "type" => "success",
3023 "message" => __('Success! Cache warmup has been disabled successfully!', 'nitropack')
3024 ));
3025 }
3026
3027 nitropack_json_and_exit(array(
3028 "type" => "error",
3029 "message" => __('Error! There was an error while disabling the cache warmup!', 'nitropack')
3030 ));
3031 }
3032
3033 function nitropack_run_warmup() {
3034 nitropack_verify_ajax_nonce($_REQUEST);
3035 if (null !== $nitro = get_nitropack_sdk()) {
3036 try {
3037 $nitro->getApi()->runWarmup();
3038 } catch (\Exception $e) {
3039 }
3040
3041 nitropack_json_and_exit(array(
3042 "type" => "success",
3043 "message" => __('Success! Cache warmup has been started successfully!', 'nitropack')
3044 ));
3045 }
3046
3047 nitropack_json_and_exit(array(
3048 "type" => "error",
3049 "message" => __('Error! There was an error while starting the cache warmup!', 'nitropack')
3050 ));
3051 }
3052
3053 function nitropack_estimate_warmup() {
3054 nitropack_verify_ajax_nonce($_REQUEST);
3055 if (null !== $nitro = get_nitropack_sdk()) {
3056 try {
3057 if (!session_id()) {
3058 session_start();
3059 }
3060 $id = !empty($_POST["estId"]) ? preg_replace("/[^a-fA-F0-9]/", "", (string)$_POST["estId"]) : NULL;
3061 if ($id !== NULL && (!is_string($id) || $id != $_SESSION["nitroEstimateId"])) {
3062 nitropack_json_and_exit(array(
3063 "type" => "error",
3064 "message" => __('Invalid estimation ID!', 'nitropack')
3065 ));
3066 }
3067
3068 $sitemapUrls = nitropack_active_sitemap_plugins() ? nitropack_get_site_maps() : NULL;
3069 $configuredSitemap = false;
3070
3071 if ($sitemapUrls === NULL) {
3072
3073 $defaultSitemap = get_default_sitemap();
3074 if ($defaultSitemap) {
3075 $nitro->getApi()->setWarmupSitemap($defaultSitemap);
3076 $configuredSitemap = true;
3077 }
3078
3079 delete_option('np_warmup_sitemap');
3080 } else {
3081
3082 $warmupSitemap = evaluate_warmup_sitemap($sitemapUrls);
3083 if ($warmupSitemap) {
3084 $nitro->getApi()->setWarmupSitemap($warmupSitemap);
3085 $configuredSitemap = true;
3086 }
3087 }
3088
3089 if (!$configuredSitemap) {
3090 $nitro->getApi()->setWarmupSitemap(NULL);
3091 }
3092
3093 $nitro->getApi()->setWarmupHomepage(get_home_url());
3094
3095 $optimizationsEstimate = $nitro->getApi()->estimateWarmup($id);
3096
3097 if ($id === NULL) {
3098 $_SESSION["nitroEstimateId"] = $optimizationsEstimate; // When id is NULL, $optimizationsEstimate holds the ID for the newly started estimate
3099 }
3100 } catch (\Exception $e) {
3101 }
3102 $json_data = array(
3103 "type" => "success",
3104 "res" => $optimizationsEstimate,
3105 "sitemap_indication" => get_option('np_warmup_sitemap', false),
3106 "message" => __('Warmup estimation failed.', 'nitropack'),
3107 );
3108 if (is_int($optimizationsEstimate) && $optimizationsEstimate > 0) {
3109 $json_data["message"] = __('Cache warmup has been estimated successfully.', 'nitropack');
3110 } else if ($optimizationsEstimate === 0) {
3111 $json_data["message"] = __('We could not find any links for warming up on your home page.', 'nitropack');
3112 } else {
3113 $json_data["message"] = __('Warmup estimation failed. Please try again or contact support if the issue persists', 'nitropack');
3114 }
3115 nitropack_json_and_exit($json_data);
3116 }
3117
3118 nitropack_json_and_exit(array(
3119 "type" => "error",
3120 "message" => __('Warmup estimation failed.', 'nitropack')
3121 ));
3122 }
3123
3124 function nitropack_warmup_stats() {
3125 nitropack_verify_ajax_nonce($_REQUEST);
3126 if (null !== $nitro = get_nitropack_sdk()) {
3127 try {
3128 $stats = $nitro->getApi()->getWarmupStats();
3129 } catch (\Exception $e) {
3130 nitropack_json_and_exit(array(
3131 "type" => "error",
3132 "message" => __('Error! There was an error while fetching warmup stats!', 'nitropack')
3133 ));
3134 }
3135
3136 nitropack_json_and_exit(array(
3137 "type" => "success",
3138 "stats" => $stats
3139 ));
3140 }
3141
3142 nitropack_json_and_exit(array(
3143 "type" => "error",
3144 "message" => __('Error! There was an error while fetching warmup stats!', 'nitropack')
3145 ));
3146 }
3147
3148 function nitropack_enable_safemode() {
3149 nitropack_verify_ajax_nonce($_REQUEST);
3150 if (null !== $nitro = get_nitropack_sdk()) {
3151 try {
3152 $nitro->enableSafeMode();
3153 } catch (\Exception $e) {
3154 }
3155
3156 nitropack_cache_safemode_status(true);
3157 nitropack_json_and_exit(array(
3158 "type" => "success",
3159 "message" => nitropack_admin_toast_msgs('success')
3160
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_disable_safemode() {
3171 nitropack_verify_ajax_nonce($_REQUEST);
3172
3173
3174 if (null !== $nitro = get_nitropack_sdk()) {
3175 try {
3176 $nitro->disableSafeMode();
3177 } catch (\Exception $e) {
3178 }
3179
3180 nitropack_cache_safemode_status(false);
3181 nitropack_json_and_exit(array(
3182 "type" => "success",
3183 "message" => nitropack_admin_toast_msgs('success')
3184 ));
3185 }
3186
3187 nitropack_json_and_exit(array(
3188 "type" => "error",
3189 "message" => nitropack_admin_toast_msgs('error')
3190 ));
3191 }
3192
3193 function nitropack_enable_cart_cache() {
3194 if (null !== $nitro = get_nitropack_sdk()) {
3195 try {
3196 $nitro->enableCartCache();
3197
3198 nitropack_json_and_exit(array(
3199 "type" => "success",
3200 "message" => nitropack_admin_toast_msgs('success')
3201 ));
3202 } catch (\Exception $e) {
3203 }
3204 }
3205
3206 nitropack_json_and_exit(array(
3207 "type" => "error",
3208 "message" => nitropack_admin_toast_msgs('error')
3209 ));
3210 }
3211
3212 function nitropack_disable_cart_cache() {
3213 if (null !== $nitro = get_nitropack_sdk()) {
3214 try {
3215 $nitro->disableCartCache();
3216
3217 nitropack_json_and_exit(array(
3218 "type" => "success",
3219 "message" => nitropack_admin_toast_msgs('success')
3220 ));
3221 } catch (\Exception $e) {
3222 }
3223 }
3224
3225 nitropack_json_and_exit(array(
3226 "type" => "error",
3227 "message" => nitropack_admin_toast_msgs('error')
3228 ));
3229 }
3230
3231 function nitropack_safemode_status($dontExit = false) {
3232 nitropack_verify_ajax_nonce($_REQUEST);
3233 if (null !== $nitro = get_nitropack_sdk()) {
3234 try {
3235 $isEnabled = $nitro->getApi()->isSafeModeEnabled();
3236 } catch (\Exception $e) {
3237 if (!$dontExit) {
3238 nitropack_json_and_exit(array(
3239 "type" => "error",
3240 "message" => nitropack_admin_toast_msgs('success')
3241 ));
3242 }
3243 return NULL;
3244 }
3245
3246 nitropack_cache_safemode_status($isEnabled);
3247 if (!$dontExit) {
3248 nitropack_json_and_exit(array(
3249 "type" => "success",
3250 "isEnabled" => $isEnabled
3251 ));
3252 }
3253 return $isEnabled;
3254 }
3255
3256 nitropack_cache_safemode_status();
3257 if (!$dontExit) {
3258 nitropack_json_and_exit(array(
3259 "type" => "error",
3260 "message" => __('Error! There was an SDK error while fetching status of safe mode!', 'nitropack')
3261 ));
3262 }
3263 return NULL;
3264 }
3265
3266 function nitropack_cache_safemode_status($operation = null) {
3267 $sm = "-1";
3268 if (is_bool($operation)) {
3269 $sm = $operation ? '1' : '0';
3270 }
3271 return update_option('nitropack-safeModeStatus', $sm);
3272 }
3273
3274 function nitropack_get_site_config() {
3275 return get_nitropack()->getSiteConfig();
3276 }
3277
3278 function nitropack_get_current_site_id() {
3279
3280 $site_config = nitropack_get_site_config();
3281
3282 if ($site_config && isset($site_config['siteId'])) {
3283 return $site_config['siteId'];
3284 }
3285 }
3286
3287 function get_nitropack() {
3288 return \NitroPack\WordPress\NitroPack::getInstance();
3289 }
3290
3291 function nitropack_event($event, $nitro = null, $additional_meta_data = null) {
3292 global $wp_version;
3293
3294 try {
3295 $eventUrl = get_nitropack_integration_url("extensionEvent", $nitro);
3296 $domain = !empty($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : "Unknown";
3297
3298
3299 if (class_exists('WooCommerce')) {
3300 $platform = 'WooCommerce';
3301 } else {
3302 $platform = 'WordPress';
3303 }
3304
3305 $query_data = array(
3306 'event' => $event,
3307 'platform' => $platform,
3308 'platform_version' => $wp_version,
3309 'nitropack_extension_version' => NITROPACK_VERSION,
3310 'additional_meta_data' => $additional_meta_data ? json_encode($additional_meta_data) : "{}",
3311 'domain' => $domain
3312 );
3313
3314 $client = new NitroPack\HttpClient\HttpClient($eventUrl . '&' . http_build_query($query_data));
3315 $client->doNotDownload = true;
3316 $client->fetch();
3317 } catch (\Exception $e) {
3318 }
3319 }
3320
3321 function nitropack_get_wpconfig_path() {
3322 $configFilePath = nitropack_trailingslashit(ABSPATH) . "wp-config.php";
3323 if (!file_exists($configFilePath)) {
3324 $configFilePath = nitropack_trailingslashit(dirname(ABSPATH)) . "wp-config.php";
3325 $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.
3326 if (!file_exists($configFilePath) || file_exists($settingsFilePath)) {
3327 return false;
3328 }
3329 }
3330
3331
3332 if (!is_writable($configFilePath)) {
3333 return false;
3334 }
3335
3336 return $configFilePath;
3337 }
3338
3339 function nitropack_get_htaccess_path() {
3340 $configFilePath = nitropack_trailingslashit(ABSPATH) . ".htaccess";
3341 if (!file_exists($configFilePath)) {
3342 return false;
3343 }
3344
3345
3346 if (!is_writable($configFilePath)) {
3347 return false;
3348 }
3349
3350 return $configFilePath;
3351 }
3352
3353 function nitropack_detect_hosting() {
3354 if (\NitroPack\Integration\Hosting\Flywheel::detect()) {
3355 return "flywheel";
3356 } else if (\NitroPack\Integration\Hosting\Cloudways::detect()) {
3357 return "cloudways";
3358 } else if (\NitroPack\Integration\Hosting\WPEngine::detect()) {
3359 return "wpengine";
3360 } else if (\NitroPack\Integration\Hosting\SiteGround::detect()) {
3361 return "siteground";
3362 } else if (\NitroPack\Integration\Hosting\GoDaddyWPaaS::detect()) {
3363 return "godaddy_wpaas";
3364 } else if (\NitroPack\Integration\Hosting\GridPane::detect()) {
3365 return "gridpane";
3366 } else if (\NitroPack\Integration\Hosting\Kinsta::detect()) {
3367 return "kinsta";
3368 } else if (\NitroPack\Integration\Hosting\Closte::detect()) {
3369 return "closte";
3370 } else if (\NitroPack\Integration\Hosting\Pagely::detect()) {
3371 return "pagely";
3372 } else if (\NitroPack\Integration\Hosting\WPX::detect()) {
3373 return "wpx";
3374 } else if (\NitroPack\Integration\Hosting\Vimexx::detect()) {
3375 return "vimexx";
3376 } else if (\NitroPack\Integration\Hosting\Pressable::detect()) {
3377 return "pressable";
3378 } else if (\NitroPack\Integration\Hosting\RocketNet::detect()) {
3379 return "rocketnet";
3380 } else if (\NitroPack\Integration\Hosting\Savvii::detect()) {
3381 return "savvii";
3382 } else if (\NitroPack\Integration\Hosting\DreamHost::detect()) {
3383 return "dreamhost";
3384 } else if (\NitroPack\Integration\Hosting\Raidboxes::detect()) {
3385 return "raidboxes";
3386 } else {
3387 return "unknown";
3388 }
3389 }
3390
3391 function nitropack_removeCacheBustParam($content) {
3392 $content = preg_replace("/(\?|%26|&#0?38;|&#x0?26;|&(amp;)?)ignorenitro(%3D|=)[a-fA-F0-9]{32}(?!%26|&#0?38;|&#x0?26;|&(amp;)?)\/?/mu", "", $content);
3393 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);
3394 }
3395
3396 function nitropack_handle_request($servedFrom = "unknown") {
3397 global $np_integrationSetupEvent;
3398
3399 if (isset($_GET["ignorenitro"])) {
3400 unset($_GET["ignorenitro"]);
3401 }
3402
3403 if (defined("NITROPACK_STRIP_IGNORENITRO") && NITROPACK_STRIP_IGNORENITRO && $_SERVER['REQUEST_URI'] != '') {
3404 $_SERVER['REQUEST_URI'] = nitropack_removeCacheBustParam($_SERVER['REQUEST_URI']);
3405 }
3406
3407 nitropack_header('Cache-Control: no-cache');
3408 do_action("nitropack_early_cache_headers"); // Overrides the Cache-Control header on supported platforms
3409 $isManageWpRequest = !empty($_GET["mwprid"]);
3410 $isWpCli = nitropack_is_wp_cli();
3411
3412 if (file_exists(NITROPACK_CONFIG_FILE) && !empty($_SERVER["HTTP_HOST"]) && !empty($_SERVER["REQUEST_URI"]) && !$isManageWpRequest && !$isWpCli) {
3413 try {
3414 $siteConfig = nitropack_get_site_config();
3415 if ($siteConfig && null !== $nitro = get_nitropack_sdk($siteConfig["siteId"], $siteConfig["siteSecret"])) {
3416 if (is_valid_nitropack_webhook()) {
3417 nitropack_handle_webhook();
3418 } else if (is_valid_nitropack_beacon()) {
3419 nitropack_handle_beacon();
3420 } else if (is_valid_nitropack_heartbeat()) {
3421 nitropack_handle_heartbeat();
3422 } else {
3423 $GLOBALS["NitroPack.instance"] = $nitro;
3424
3425 if (nitropack_passes_cookie_requirements() || (nitropack_is_ajax() && !empty($_COOKIE["nitroCachedPage"]))) {
3426 // Check whether the current URL is cacheable
3427 // 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.
3428 // If we are not checking the referer, the AJAX requests on these pages can fail.
3429 $urlToCheck = nitropack_is_ajax() && !empty($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : $nitro->getUrl();
3430 if ($nitro->isAllowedUrl($urlToCheck)) {
3431 add_filter('nonce_life', 'nitropack_extend_nonce_life');
3432 }
3433 }
3434
3435 if (nitropack_passes_cookie_requirements() && apply_filters("nitropack_can_serve_cache", true)) {
3436 if ($nitro->isCacheAllowed()) {
3437 if (!nitropack_is_ajax()) {
3438 do_action("nitropack_cacheable_cache_headers");
3439 }
3440
3441 if (!empty($siteConfig["compression"])) {
3442 $nitro->enableCompression();
3443 }
3444
3445 if ($nitro->hasLocalCache()) {
3446 // TODO: Make this work so we can provide the reverse proxies with this information $remainingTtl = $nitr->pageCache->getRemainingTtl();
3447 do_action("nitropack_cachehit_cache_headers"); // TODO: Pass the remaining TTL here
3448 $cacheControlOverride = defined("NITROPACK_CACHE_CONTROL_OVERRIDE") ? NITROPACK_CACHE_CONTROL_OVERRIDE : NULL;
3449 if ($cacheControlOverride) {
3450 nitropack_header('Cache-Control: ' . $cacheControlOverride);
3451 }
3452
3453 nitropack_header('X-Nitro-Cache: HIT');
3454 nitropack_header('X-Nitro-Cache-From: ' . $servedFrom);
3455 $cjHandler = new \NitroPack\SDK\Utils\CjHandler($nitro);
3456 $cjHandler->handleQueryParams();
3457 $nitro->pageCache->readfile();
3458 exit;
3459 } else {
3460 // We need the following if..else block to handle bot requests which will not be firing our beacon
3461 if (nitropack_is_warmup_request()) {
3462 if (!empty($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
3463 add_action("init", function () use ($nitro) {
3464 $nitro->hasRemoteCache("default"); // Only ping the API letting our service know that this page must be cached.
3465 exit;
3466 }, 9999);
3467 return; // We need to wait for a language plugin (if present) to redirect
3468 } else {
3469 $nitro->hasRemoteCache("default"); // Only ping the API letting our service know that this page must be cached.
3470 exit; // No need to continue handling this request. The response is not important.
3471 }
3472 } else if (nitropack_is_lighthouse_request() || nitropack_is_gtmetrix_request() || nitropack_is_pingdom_request()) {
3473 $nitro->hasRemoteCache("default"); // Ping the API letting our service know that this page must be cached.
3474 }
3475
3476 $nitro->pageCache->useInvalidated(true);
3477 if ($nitro->hasLocalCache()) {
3478 nitropack_header('X-Nitro-Cache: STALE');
3479 nitropack_header('X-Nitro-Cache-From: ' . $servedFrom);
3480 $cjHandler = new \NitroPack\SDK\Utils\CjHandler($nitro);
3481 $cjHandler->handleQueryParams();
3482 $nitro->pageCache->readfile();
3483 exit;
3484 } else {
3485 $nitro->pageCache->useInvalidated(false);
3486 }
3487 }
3488 }
3489 }
3490 }
3491 }
3492 } catch (\Exception $e) {
3493 // Do nothing, cache serving will be handled by nitropack_init
3494 }
3495 }
3496 }
3497
3498 function nitropack_is_dropin_cache_allowed() {
3499 $siteConfig = nitropack_get_site_config();
3500 return $siteConfig && empty($siteConfig["isEzoicActive"]);
3501 }
3502
3503 function nitropack_is_dismissed_notice($id) {
3504 return isset($_COOKIE["dismissed_notice_" . $id]);
3505 }
3506
3507 function nitropack_admin_bar_menu($wp_admin_bar) {
3508 if (nitropack_is_amp_page()) return;
3509
3510
3511 $nitropackPluginNotices = nitropack_plugin_notices();
3512 $numberOfPluginErrors = 0;
3513 $numberOfPluginWarnings = 0;
3514 foreach (array("warning", "error") as $type) {
3515 foreach ($nitropackPluginNotices[$type] as $notice) {
3516 if (!nitropack_is_dismissed_notice(nitropack_get_notice_id($notice))) {
3517 switch ($type) {
3518 case "error":
3519 $numberOfPluginErrors++;
3520 break;
3521 case "warning":
3522 $numberOfPluginWarnings++;
3523 break;
3524 }
3525 }
3526 }
3527 }
3528 /* Notifications from the app */
3529 $notificationCount = 0;
3530 foreach (get_nitropack()->Notifications->get('system') as $notification) {
3531 if (!nitropack_is_dismissed_notice($notification["id"])) {
3532 $notificationCount++;
3533 }
3534 }
3535
3536 $numberOfPluginIssues = $numberOfPluginErrors + $numberOfPluginWarnings;
3537
3538 if ($numberOfPluginErrors > 0) {
3539 $pluginStatus = 'error';
3540 } else if ($numberOfPluginWarnings > 0) {
3541 $pluginStatus = 'warning';
3542 } else {
3543 $pluginStatus = 'ok';
3544 }
3545
3546
3547 if (!get_nitropack()->isConnected()) {
3548 $node = array(
3549 'id' => 'nitropack-top-menu',
3550 'title' => '&nbsp;&nbsp;<i style="" class="circle nitro nitro-status nitro-status-error" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack is disconnected',
3551 'href' => admin_url('admin.php?page=nitropack'),
3552 'meta' => array(
3553 'class' => 'nitropack-menu'
3554 )
3555 );
3556
3557 $wp_admin_bar->add_node(
3558 array(
3559 'parent' => 'nitropack-top-menu',
3560 'id' => 'optimizations-plugin-status',
3561 'title' => __('Connect NitroPack&nbsp;&nbsp;', 'nitropack'),
3562 'href' => admin_url('admin.php?page=nitropack'),
3563 'meta' => array(
3564 'class' => 'nitropack-plugin-status',
3565 )
3566 )
3567 );
3568 } else {
3569 $title = '&nbsp;&nbsp;<i style="" class="circle nitro nitro-status nitro-status-' . $pluginStatus . '" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack';
3570 if ($pluginStatus != "ok") {
3571 $title .= ' <span class="circle-with-text nitro-color-issues" id="nitro-total-issues-count">' . ($numberOfPluginIssues + $notificationCount) . '</span>';
3572 } else if ($notificationCount > 0) {
3573 $title .= ' <span class="circle-with-text nitro-color-notification" id="nitro-total-issues-count">' . $notificationCount . '</span>';
3574 }
3575 $node = array(
3576 'id' => 'nitropack-top-menu',
3577 'title' => $title,
3578 'href' => admin_url('admin.php?page=nitropack'),
3579 'meta' => array(
3580 'class' => 'nitropack-menu'
3581 )
3582 );
3583
3584 $settings_extra = '';
3585 if ($notificationCount) {
3586 $settings_extra .= ' <span class="circle-with-text nitro-color-notification" id="nitro-notification-issues-count">' . $notificationCount . '</span>';
3587 }
3588 $wp_admin_bar->add_node(array(
3589 'id' => 'nitropack-top-menu-settings',
3590 'parent' => 'nitropack-top-menu',
3591 'title' => __('Settings', 'nitropack') . ' ' . $settings_extra . '',
3592 'href' => admin_url('admin.php?page=nitropack'),
3593 'meta' => array(
3594 'class' => 'nitropack-settings'
3595 )
3596
3597 ));
3598
3599 $wp_admin_bar->add_node(
3600 array(
3601 'id' => 'nitropack-top-menu-purge-entire-cache',
3602 'parent' => 'nitropack-top-menu',
3603 'title' => __('Purge Entire Cache', 'nitropack'),
3604 'href' => '#',
3605 'meta' => array(
3606 'class' => 'nitropack-purge-cache-entire-site',
3607 ),
3608 )
3609 );
3610
3611 if (!is_admin()) { // menu otions available when browsing front-end pages
3612
3613 $wp_admin_bar->add_node(
3614 array(
3615 'parent' => 'nitropack-top-menu',
3616 'id' => 'optimizations-purge-cache',
3617 'title' => __('Purge Current Page', 'nitropack'),
3618 'href' => "#",
3619 'meta' => array(
3620 'class' => 'nitropack-purge-cache',
3621 )
3622 )
3623 );
3624
3625 $wp_admin_bar->add_node(
3626 array(
3627 'parent' => 'nitropack-top-menu',
3628 'id' => 'optimizations-invalidate-cache',
3629 'title' => __('Invalidate Current Page', 'nitropack'),
3630 'href' => "#",
3631 'meta' => array(
3632 'class' => 'nitropack-invalidate-cache',
3633 )
3634 )
3635 );
3636 }
3637
3638 if ($pluginStatus != "ok") {
3639 $wp_admin_bar->add_node(
3640 array(
3641 'parent' => 'nitropack-top-menu',
3642 'id' => 'optimizations-plugin-status',
3643 'title' => 'Issues <span class="circle-with-text nitro-color-issues">' . $numberOfPluginIssues . '</span>',
3644 'href' => admin_url('admin.php?page=nitropack'),
3645 'meta' => array(
3646 'class' => 'nitropack-plugin-status',
3647 )
3648 )
3649 );
3650 }
3651
3652 // $notificationCount = 0;
3653 // foreach (get_nitropack()->Notifications->get('system') as $notification) {
3654 // if (!nitropack_is_dismissed_notice($notification["id"])) {
3655 // $notificationCount++;
3656 // }
3657 // }
3658
3659 // if ($notificationCount) {
3660 // $node['title'] .= ' <span class="circle-with-text nitro-color-notification">' . $notificationCount . '</span>';
3661 // $wp_admin_bar->add_node(
3662 // array(
3663 // 'parent' => 'nitropack-top-menu',
3664 // 'id' => 'nitropack-notifications',
3665 // 'title' => 'Notifications <span class="circle-with-text nitro-color-notification">' . $notificationCount . '</span>',
3666 // 'href' => admin_url('admin.php?page=nitropack'),
3667 // 'meta' => array(
3668 // 'class' => 'nitropack-notifications',
3669 // )
3670 // )
3671 // );
3672 // }
3673 }
3674
3675 $wp_admin_bar->add_node($node);
3676 }
3677
3678 function nitropack_admin_bar_script($hook) {
3679 if (!nitropack_is_amp_page()) {
3680 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);
3681 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__)));
3682 }
3683 }
3684
3685
3686 function enqueue_nitropack_admin_bar_menu_stylesheet() {
3687 if (!nitropack_is_amp_page()) {
3688 wp_enqueue_style('nitropack_admin_bar_menu_stylesheet', plugin_dir_url(__FILE__) . 'view/stylesheet/admin_bar_menu.min.css?np_v=' . NITROPACK_VERSION);
3689 }
3690 }
3691
3692 function nitropack_cookiepath() {
3693 $siteConfig = nitropack_get_site_config();
3694 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
3695 $url = new \NitroPack\Url\Url($homeUrl);
3696 return $url ? $url->getPath() : "/";
3697 }
3698
3699 function nitropack_setcookie($name, $value, $expires = NULL, $options = []) {
3700 if (headers_sent()) return;
3701 $cookie_options = '';
3702 $cookie_path = nitropack_cookiepath();
3703
3704 if ($expires && is_numeric($expires)) {
3705 $options["Expires"] = date("D, d M Y H:i:s", (int)$expires) . ' GMT';
3706 }
3707
3708 if (empty($options["SameSite"])) {
3709 $options["SameSite"] = "Lax";
3710 }
3711
3712 foreach ($options as $optName => $optValue) {
3713 $cookie_options .= "$optName=$optValue; ";
3714 }
3715 nitropack_header("set-cookie: $name=$value; Path=$cookie_path; " . $cookie_options, false);
3716 }
3717
3718 function nitropack_header($header, $replace = true, $response_code = 0) {
3719 if (!nitropack_is_wp_cron() && !nitropack_is_wp_cli()) {
3720 header($header, $replace, $response_code);
3721 }
3722 }
3723
3724
3725 function nitropack_upgrade_handler($entity) {
3726 $np = 'nitropack/main.php';
3727 $trigger = $entity;
3728 if ($entity instanceof Plugin_Upgrader) {
3729 $trigger = $entity->plugin_info();
3730 if (!is_plugin_active($trigger)) {
3731 return;
3732 }
3733 }
3734
3735 if ($entity instanceof Theme_Upgrader) {
3736 if ($entity->theme_info()->Name === wp_get_theme()->Name) {
3737 nitropack_theme_handler('Theme updated');
3738 }
3739 return;
3740 }
3741
3742 if ($trigger !== $np) {
3743 $cookie_expires = date("D, d M Y H:i:s", time() + 600) . ' GMT';
3744 nitropack_setcookie('nitropack_apwarning', "1", time() + 600);
3745 }
3746 }
3747
3748 function nitropack_plugin_notices() {
3749 static $npPluginNotices = NULL;
3750
3751 if ($npPluginNotices !== NULL) {
3752 return $npPluginNotices;
3753 }
3754
3755 $errors = [];
3756 $warnings = [];
3757 $infos = [];
3758
3759 // Add conficting plugins errors
3760 $conflictingPlugins = nitropack_get_conflicting_plugins();
3761 foreach ($conflictingPlugins as $clashingPlugin) {
3762 $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);
3763 }
3764
3765 // Add residual cache notices if found
3766 $residualCachePlugins = \NitroPack\Integration\Plugin\RC::detectThirdPartyCaches();
3767 foreach ($residualCachePlugins as $rcpName) {
3768 $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);
3769 }
3770
3771 // Add plugins state notices
3772 if (isset($_COOKIE['nitropack_apwarning'])) {
3773 $cookie_path = nitropack_cookiepath();
3774 $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>";
3775 }
3776
3777 // Add SM enabled notice
3778 $smStatus = get_option('nitropack-safeModeStatus', "-1");
3779 if ($smStatus === "-1") $smStatus = nitropack_safemode_status(true);
3780 if ($smStatus) {
3781 $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');
3782 if (get_nitropack()->getDistribution() == "oneclick") {
3783 $safeModeMessage = apply_filters("nitropack_oneclick_safemode_message", $safeModeMessage);
3784 }
3785 $warnings[] = '<div id="nitropack-smenabled-notice">' . $safeModeMessage . '</div>';
3786 }
3787
3788 $nitropackIsConnected = get_nitropack()->isConnected();
3789
3790 if ($nitropackIsConnected) {
3791 if (nitropack_is_advanced_cache_allowed()) {
3792 if (!nitropack_has_advanced_cache()) {
3793 $advancedCacheFile = nitropack_trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';
3794 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 :(
3795 if (nitropack_install_advanced_cache()) {
3796 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.
3797 $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');
3798 }
3799 } else {
3800 if (!nitropack_is_conflicting_plugin_active()) {
3801 $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');
3802 }
3803 }
3804 }
3805 } else {
3806 if (!defined("NITROPACK_ADVANCED_CACHE_VERSION") || NITROPACK_VERSION != NITROPACK_ADVANCED_CACHE_VERSION) {
3807 if (!nitropack_install_advanced_cache()) {
3808 if (nitropack_is_conflicting_plugin_active()) {
3809 $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');
3810 } else {
3811 $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');
3812 }
3813 }
3814 }
3815 }
3816 } else {
3817 if (nitropack_has_advanced_cache()) {
3818 nitropack_uninstall_advanced_cache();
3819 }
3820 }
3821
3822 if ((!defined("WP_CACHE") || !WP_CACHE)) {
3823 if (\NitroPack\Integration\Hosting\Flywheel::detect()) { // Flywheel: This is configured throught the FW control panel
3824 $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');
3825 } else if (!nitropack_set_wp_cache_const(true)) {
3826 $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');
3827 }
3828 }
3829
3830 if (apply_filters('nitropack_needs_htaccess_changes', false)) {
3831 if (!nitropack_set_htaccess_rules(true)) {
3832 $warnings[] = __('Unable to configure LiteSpeed specific rules for maximum performance. Please make sure your .htaccess file is writable or contact support.', 'nitropack');
3833 }
3834 }
3835
3836 if (!get_nitropack()->dataDirExists() && !get_nitropack()->initDataDir()) {
3837 $errors[] = __('The NitroPack data directory cannot be created. Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack');
3838 return [
3839 'error' => $errors,
3840 'warning' => $warnings,
3841 'info' => $infos
3842 ];
3843 }
3844
3845 if (!get_nitropack()->pluginDataDirExists() && !get_nitropack()->initPluginDataDir()) {
3846 $errors[] = __('The NitroPack plugin data directory cannot be created. Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack');
3847 return [
3848 'error' => $errors,
3849 'warning' => $warnings,
3850 'info' => $infos
3851 ];
3852 }
3853
3854 $siteConfig = nitropack_get_site_config();
3855 $siteId = $siteConfig ? $siteConfig["siteId"] : NULL;
3856 $siteSecret = $siteConfig ? $siteConfig["siteSecret"] : NULL;
3857 $webhookToken = esc_attr(get_option('nitropack-webhookToken'));
3858 $blogId = get_current_blog_id();
3859 $isConfigOutdated = !nitropack_is_config_up_to_date();
3860
3861 if (!get_nitropack()->Config->exists() && !get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3862 $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');
3863 } else if ($isConfigOutdated) {
3864 if (!get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3865 $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');
3866 } else {
3867 if (!$siteConfig) {
3868 nitropack_event("update");
3869 } else {
3870 $prevVersion = !empty($siteConfig["pluginVersion"]) ? $siteConfig["pluginVersion"] : "1.1.4 or older";
3871 nitropack_event("update", null, array("previous_version" => $prevVersion));
3872
3873 if (empty($siteConfig["pluginVersion"]) || version_compare($siteConfig["pluginVersion"], "1.3", "<")) {
3874 if (!headers_sent()) {
3875 setcookie("nitropack_upgrade_to_1_3_notice", 1, time() + 3600);
3876 }
3877 $_COOKIE["nitropack_upgrade_to_1_3_notice"] = 1;
3878 }
3879 }
3880 }
3881
3882 try {
3883 nitropack_setup_webhooks(get_nitropack_sdk(), $webhookToken);
3884 } catch (\NitroPack\SDK\WebhookException $e) {
3885 $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');
3886 }
3887 } else {
3888 $optionsMistmatch = false;
3889 if (array_key_exists('options_cache', $siteConfig)) {
3890 foreach (\NitroPack\WordPress\NitroPack::$optionsToCache as $opt) {
3891 if (is_array($opt)) {
3892 foreach ($opt as $option => $suboption) {
3893 if (empty($siteConfig['options_cache'][$option][$suboption]) || $siteConfig['options_cache'][$option][$suboption] != get_option($option)[$suboption]) {
3894 $optionsMistmatch = true;
3895 break 2;
3896 }
3897 }
3898 } else {
3899 if (!array_key_exists($opt, $siteConfig['options_cache']) || $siteConfig['options_cache'][$opt] != get_option($opt)) {
3900 $optionsMistmatch = true;
3901 break;
3902 }
3903 }
3904 }
3905 } else {
3906 $optionsMistmatch = true;
3907 }
3908
3909 if (
3910 $optionsMistmatch ||
3911 (!array_key_exists("isEzoicActive", $siteConfig) || $siteConfig["isEzoicActive"] !== \NitroPack\Integration\Plugin\Ezoic::isActive()) ||
3912 (!array_key_exists("isLateIntegrationInitRequired", $siteConfig) || $siteConfig["isLateIntegrationInitRequired"] !== nitropack_is_late_integration_init_required()) ||
3913 (!array_key_exists("isDlmActive", $siteConfig) || $siteConfig["isDlmActive"] !== \NitroPack\Integration\Plugin\DownloadManager::isActive()) ||
3914 (!array_key_exists("isAeliaCurrencySwitcherActive", $siteConfig) || $siteConfig["isAeliaCurrencySwitcherActive"] !== \NitroPack\Integration\Plugin\AeliaCurrencySwitcher::isActive()) ||
3915 (!array_key_exists("isGeoTargetingWPActive", $siteConfig) || $siteConfig["isGeoTargetingWPActive"] !== \NitroPack\Integration\Plugin\GeoTargetingWP::isActive()) ||
3916 (!array_key_exists("isWoocommerceActive", $siteConfig) || $siteConfig["isWoocommerceActive"] !== \NitroPack\Integration\Plugin\Woocommerce::isActive()) ||
3917 (!array_key_exists("isWoocommerceCacheHandlerActive", $siteConfig) || $siteConfig["isWoocommerceCacheHandlerActive"] !== \NitroPack\Integration\Plugin\WoocommerceCacheHandler::isActive())
3918 ) {
3919 if (!get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3920 $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');
3921 }
3922 }
3923
3924 if (empty($_COOKIE["nitropack_webhook_sync"])) {
3925 if (null !== $nitro = get_nitropack_sdk()) {
3926 try {
3927 if (!headers_sent()) {
3928 nitropack_setcookie("nitropack_webhook_sync", "1", time() + 300); // Do these checks in 5 minute intervals.
3929 }
3930 $configWebhook = $nitro->getApi()->getWebhook("config");
3931 if (!empty($configWebhook)) {
3932 $query = parse_url($configWebhook, PHP_URL_QUERY);
3933 if ($query) {
3934 parse_str($query, $webhookParams);
3935 if (empty($webhookParams["token"]) || $webhookParams["token"] != $webhookToken) {
3936 $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>";
3937 }
3938 }
3939 }
3940 } catch (\Exception $e) {
3941 //Do nothing
3942 }
3943 }
3944 }
3945
3946 if (apply_filters('nitropack_should_modify_htaccess', false) && (empty($_SERVER["NitroPackHtaccessVersion"]) || NITROPACK_VERSION != $_SERVER["NitroPackHtaccessVersion"])) {
3947 if (!nitropack_set_htaccess_rules(true)) {
3948 $errors[] = "The .htaccess file cannot be modified. Please make sure that it is writable and refresh this page.";
3949 }
3950 }
3951 }
3952
3953 if (!empty($_COOKIE["nitropack_upgrade_to_1_3_notice"])) {
3954 $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>";
3955 }
3956
3957 if (\NitroPack\Integration\Plugin\Cloudflare::isApoActive() && !\NitroPack\Integration\Plugin\Cloudflare::isApoCacheByDeviceTypeEnabled()) {
3958 $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.";
3959 }
3960 }
3961
3962 $npPluginNotices = [
3963 'error' => $errors,
3964 'warning' => $warnings,
3965 'info' => $infos
3966 ];
3967
3968
3969 return $npPluginNotices;
3970 }
3971
3972 /**
3973 * Caches some options in the config so that we can access them before get_option() is defined
3974 * which is in advanced_cache.php, functions.php and Integrations
3975 */
3976 function nitropack_updated_option($option, $oldValue, $value) {
3977 $neededOptions = \NitroPack\WordPress\NitroPack::$optionsToCache;
3978 if (!in_array($option, $neededOptions)) return;
3979
3980 $np = get_nitropack();
3981 $siteConfig = $np->Config->get();
3982
3983 if (function_exists('get_home_url')) {
3984 $configKey = \NitroPack\WordPress\NitroPack::getConfigKey();
3985 $siteConfig[$configKey]['options_cache'][$option] = $value;
3986 $np->Config->set($siteConfig);
3987 }
3988 }
3989
3990 function nitropack_is_late_integration_init_required() {
3991 return \NitroPack\Integration\Plugin\NginxHelper::isActive() || \NitroPack\Integration\Plugin\Cloudflare::isApoActive();
3992 }
3993
3994 function nitropack_get_notice_id($message) {
3995 return md5($message);
3996 }
3997
3998 function nitropack_display_admin_notices() {
3999 $noticesArray = nitropack_plugin_notices();
4000 foreach ($noticesArray as $type => $notices) {
4001 foreach ($notices as $notice) {
4002 nitropack_print_notice($type, $notice, false);
4003 }
4004 }
4005 }
4006
4007 function nitropack_offer_safemode() {
4008 global $pagenow;
4009 if ($pagenow == 'plugins.php') {
4010 $smStatus = get_option('nitropack-safeModeStatus', "-1");
4011 if ($smStatus === "0") {
4012 add_action('admin_enqueue_scripts', function () {
4013 wp_enqueue_script('np_safemode', plugin_dir_url(__FILE__) . 'view/javascript/np_safemode.js', array('jquery'));
4014 wp_enqueue_style('np_safemode', plugin_dir_url(__FILE__) . 'view/stylesheet/safemode.min.css');
4015 });
4016 add_action('admin_footer', function () {
4017 require_once NITROPACK_PLUGIN_DIR . 'view/safemode.php';
4018 });
4019 }
4020 }
4021 }
4022
4023 function nitropack_active_sitemap_plugins() {
4024 return
4025 NitroPack\Integration\Plugin\YoastSEO::isActive() ||
4026 NitroPack\Integration\Plugin\JetPackNP::isActive() ||
4027 NitroPack\Integration\Plugin\SquirrlySEO::isActive() ||
4028 NitroPack\Integration\Plugin\RankMathNP::isActive();
4029 }
4030
4031 function nitropack_get_site_maps() {
4032 $sitemapUrls['YoastSEO'] = NitroPack\Integration\Plugin\YoastSEO::getSitemapURL();
4033 $sitemapUrls['JetPack'] = NitroPack\Integration\Plugin\JetPackNP::getSitemapURL();
4034 $sitemapUrls['SquirrlySEO'] = NitroPack\Integration\Plugin\SquirrlySEO::getSitemapURL();
4035 $sitemapUrls['RankMath'] = NitroPack\Integration\Plugin\RankMathNP::getSitemapURL();
4036
4037 return $sitemapUrls;
4038 }
4039
4040 function get_default_sitemap() {
4041
4042 $defaultSiteMap = NitroPack\Integration\Plugin\WPCacheHelper::getSitemapURL();
4043 if ($defaultSiteMap) {
4044 set_sitemap_indication_msg('WordPress', $defaultSiteMap);
4045 return $defaultSiteMap;
4046 }
4047
4048 return false;
4049 }
4050
4051 function evaluate_warmup_sitemap($sitemapUrls) {
4052
4053 $sitemapProviders = array(
4054 'YoastSEO' => 'Yoast!',
4055 'SquirrlySEO' => 'Squirrly SEO',
4056 'RankMath' => 'Rank Math',
4057 'JetPack' => 'Jetpack',
4058 );
4059
4060 foreach ($sitemapProviders as $provider => $name) {
4061 if (isset($sitemapUrls[$provider]) && $sitemapUrls[$provider]) {
4062 set_sitemap_indication_msg($name, $sitemapUrls[$provider]);
4063 return $sitemapUrls[$provider];
4064 }
4065 }
4066
4067 return get_default_sitemap();
4068 }
4069
4070 function set_sitemap_indication_msg($pluginName, $sitemapURL) {
4071 $sitemapURI = explode("/", parse_url($sitemapURL, PHP_URL_PATH));
4072 $msg = $sitemapURI[1] . ' used by ' . $pluginName;
4073 update_option('np_warmup_sitemap', $msg);
4074 }
4075
4076 function nitropack_rml_notification() {
4077
4078 if (!isset($_POST)) {
4079 return;
4080 }
4081
4082 nitropack_verify_ajax_nonce($_REQUEST);
4083
4084 $notification_id = $_POST['notification_id'];
4085 $notification_end = $_POST['notification_end'];
4086 $midpoint = get_date_midpoint($notification_end);
4087 $notification_end = strtotime($notification_end) - time();
4088 $transient_status = set_transient($notification_id, $midpoint, $notification_end);
4089
4090 nitropack_json_and_exit(array(
4091 "transient_status" => $transient_status,
4092 ));
4093 }
4094
4095 function get_date_midpoint($endDate) {
4096 return (time() + strtotime($endDate)) / 2;
4097 }
4098
4099 function nitropack_ignore_dismissed_notifications($notifications, $type) {
4100 foreach ($notifications as $key => $notification) {
4101 $display_time = get_transient($notification['id']);
4102 if ($display_time && time() < $display_time) {
4103 unset($notifications[$key]);
4104 }
4105 }
4106
4107 return $notifications;
4108 }
4109
4110 function initVariationCookies($customVariationCookies) {
4111 $api = get_nitropack_sdk()->getApi();
4112 try {
4113 $variationCookies = $api->getVariationCookies();
4114 foreach ($variationCookies as $cookie) {
4115 $index = array_search($cookie["name"], $customVariationCookies);
4116 if ($index !== false) {
4117 array_splice($customVariationCookies, $index, 1);
4118 }
4119 }
4120
4121 foreach ($customVariationCookies as $cookieName) {
4122 $api->setVariationCookie($cookieName);
4123 }
4124 } catch (\Exception $e) {
4125 // what to do here? possible reason for exception is the API not responding
4126 return false;
4127 }
4128 }
4129
4130 function removeVariationCookies($cookiesToRemove) {
4131 $api = get_nitropack_sdk()->getApi();
4132 try {
4133 $variationCookies = $api->getVariationCookies();
4134 foreach ($variationCookies as $cookie) {
4135 if (in_array($cookie["name"], $cookiesToRemove)) {
4136 $api->unsetVariationCookie($cookie["name"]);
4137 }
4138 }
4139 } catch (\Exception $e) {
4140 // what to do here? possible reason for exception is the API not responding
4141 return false;
4142 }
4143 }
4144
4145 function getNewCookie($name) {
4146 $cookies = getNewCookies();
4147 return !empty($cookies[$name]) ? $cookies[$name] : null;
4148 }
4149
4150 /**
4151 * Returns an array of newly set cookies (not in $_COOKIE), that will be sent along with the headers of the current response.
4152 */
4153 function getNewCookies() {
4154 $cookies = [];
4155 $headers = headers_list();
4156 foreach ($headers as $header) {
4157 if (strpos($header, 'Set-Cookie: ') === 0) {
4158 $value = str_replace('&', urlencode('&'), substr($header, 12));
4159 parse_str(current(explode(';', $value)), $pair);
4160 $cookies = array_merge_recursive($cookies, $pair);
4161 }
4162 }
4163
4164 return array_filter(array_map(function ($val) {
4165 if (is_array($val)) {
4166 $lastEl = end($val);
4167 if (is_array($lastEl)) {
4168 return NULL;
4169 }
4170 return $lastEl;
4171 }
4172
4173 return $val;
4174 }, $cookies));
4175 }
4176
4177 /**
4178 * Purge entire cache when permalink structure is changed.
4179 *
4180 * @param string $old_permalink_structure The previous permalink structure.
4181 * @param string $permalink_structure The new permalink structure.
4182 *
4183 * @return void
4184 */
4185 function nitropack_permalink_structure_changed_handler($old_permalink_structure, $permalink_structure) {
4186
4187 if ($old_permalink_structure != $permalink_structure && get_option("nitropack-autoCachePurge", 1)) {
4188 $msg = 'The permalink structure is changed. Purging the cache for the home page.';
4189 $url = get_home_url();
4190
4191 try {
4192 nitropack_sdk_purge($url, NULL, $msg); // purge cache for the home page
4193 } catch (\Exception $e) {
4194 }
4195
4196 // run warmup
4197 if (null !== $nitro = get_nitropack_sdk()) {
4198 try {
4199 $nitro->getApi()->runWarmup();
4200 } catch (\Exception $e) {
4201 }
4202 }
4203 }
4204 }
4205
4206 add_action('permalink_structure_changed', 'nitropack_permalink_structure_changed_handler', 10, 2);
4207
4208 /**
4209 * Purge entire cache when front page is changed.
4210 *
4211 * @param array $old_value An array of previous settings values.
4212 * @param array $value An array of submitted settings values.
4213 *
4214 * @return void
4215 */
4216 function nitropack_frontpage_changed_handler($old_value, $value) {
4217
4218 if ($old_value !== $value) {
4219 $msg = 'The front page is changed';
4220 $url = get_home_url();
4221
4222 try {
4223 nitropack_sdk_purge($url, NULL, $msg); // purge entire cache
4224 } catch (\Exception $e) {
4225 }
4226 }
4227 }
4228
4229 add_action('update_option_show_on_front', 'nitropack_frontpage_changed_handler', 10, 2);
4230 add_action('update_option_page_on_front', 'nitropack_frontpage_changed_handler', 10, 2);
4231 add_action('update_option_page_for_posts', 'nitropack_frontpage_changed_handler', 10, 2);
4232
4233 // Init integration action handlers
4234 $modHandler = NitroPack\ModuleHandler::getInstance();
4235 $modHandler->init();
4236