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