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