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