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