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