PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.5.15
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.5.15
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
3198 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 do_action('nitropack_integration_purge_url', $homeUrl);
1245
1246 if ($tag) {
1247 do_action('nitropack_integration_purge_all');
1248 } else if ($url) {
1249 do_action('nitropack_integration_purge_url', $url);
1250 } else {
1251 do_action('nitropack_integration_purge_all');
1252 }
1253 } catch (\Exception $e) {
1254 // Exception while signaling 3rd party integration addons to purge their cache
1255 }
1256 } catch (\Exception $e) {
1257 return false;
1258 }
1259
1260 return true;
1261 }
1262
1263 return false;
1264 }
1265
1266 /* Start Heartbeat Related Functions */
1267 function nitropack_is_heartbeat_needed() {
1268 return !nitropack_is_optimizer_request() &&
1269 !nitropack_is_amp_page() &&
1270 !nitropack_is_heartbeat_running() &&
1271 (!nitropack_is_heartbeat_completed() || time() - nitropack_last_heartbeat() > NITROPACK_HEARTBEAT_INTERVAL);
1272 }
1273
1274 function nitropack_print_heartbeat_script() {
1275 if (nitropack_is_heartbeat_needed()) {
1276 if (defined("NITROPACK_HEARTBEAT_PRINTED")) return;
1277 define("NITROPACK_HEARTBEAT_PRINTED", true);
1278 echo apply_filters("nitro_script_output", nitropack_get_heartbeat_script());
1279 }
1280 }
1281
1282 function nitropack_get_heartbeat_script() {
1283 $siteConfig = nitropack_get_site_config();
1284 if ($siteConfig && !empty($siteConfig["siteId"]) && !empty($siteConfig["siteSecret"])) {
1285 if (null !== $nitro = get_nitropack_sdk($siteConfig["siteId"], $siteConfig["siteSecret"]) ) {
1286 if (is_admin()) {
1287 $credentials = "same-origin";
1288 } else {
1289 $credentials = "omit";
1290 }
1291
1292 return "
1293 <script nitro-exclude>
1294 var heartbeatData = new FormData(); heartbeatData.append('nitroHeartbeat', '1');
1295 fetch(location.href, {method: 'POST', body: heartbeatData, credentials: '$credentials'});
1296 </script>";
1297 }
1298 }
1299 }
1300
1301 function is_valid_nitropack_heartbeat() {
1302 return !empty($_POST['nitroHeartbeat']);
1303 }
1304
1305 function nitropack_get_heartbeat_file() {
1306 if (null !== $nitro = get_nitropack_sdk()) {
1307 return nitropack_trailingslashit($nitro->getCacheDir()) . "heartbeat";
1308 } else {
1309 return nitropack_trailingslashit(NITROPACK_DATA_DIR) . "heartbeat";
1310 }
1311 }
1312
1313 function nitropack_last_heartbeat() {
1314 if (null !== $nitro = get_nitropack_sdk()) {
1315 try {
1316 return \NitroPack\SDK\Filesystem::fileMTime(nitropack_get_heartbeat_file());
1317 } catch (\Exception $e) {
1318 return 0;
1319 }
1320 }
1321 }
1322
1323 function nitropack_is_heartbeat_running() {
1324 if (null !== $nitro = get_nitropack_sdk()) {
1325 try {
1326 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents(nitropack_get_heartbeat_file());
1327 if ($heartbeatContent == "1") {
1328 return time() - nitropack_last_heartbeat() < NITROPACK_HEARTBEAT_INTERVAL;
1329 }
1330 } catch (\Exception $e) {
1331 return false;
1332 }
1333 }
1334 }
1335
1336 function nitropack_is_heartbeat_completed() {
1337 if (null !== $nitro = get_nitropack_sdk()) {
1338 try {
1339 $heartbeatContent = \NitroPack\SDK\Filesystem::fileGetContents(nitropack_get_heartbeat_file());
1340 return $heartbeatContent == "0"; // 0 - Job Done, 1 - Job Running, 2 - Job Needs Repeat
1341 } catch (\Exception $e) {
1342 return true;
1343 }
1344 }
1345 }
1346
1347 function nitropack_handle_heartbeat() {
1348 // TODO: Lock the file before checking this
1349 if (nitropack_is_heartbeat_running()) return;
1350
1351 session_write_close();
1352 if (null !== $nitro = get_nitropack_sdk()) {
1353 try {
1354 $success = true;
1355 \NitroPack\SDK\Filesystem::filePutContents(nitropack_get_heartbeat_file(), 1);
1356 if (nitropack_healthcheck()) {
1357 $success &= nitropack_flush_backlog();
1358 }
1359 $success &= nitropack_cache_cleanup();
1360
1361 if ($success) {
1362 \NitroPack\SDK\Filesystem::filePutContents(nitropack_get_heartbeat_file(), 0);
1363 } else {
1364 \NitroPack\SDK\Filesystem::filePutContents(nitropack_get_heartbeat_file(), 2);
1365 }
1366 } catch (\Exception $e) {
1367 return false;
1368 }
1369 }
1370 exit;
1371 }
1372
1373 function nitropack_healthcheck() {
1374 if (null !== $nitro = get_nitropack_sdk()) {
1375 return $nitro->getHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY || $nitro->checkHealthStatus() == \NitroPack\SDK\HealthStatus::HEALTHY;
1376 }
1377 return true;
1378 }
1379
1380 function nitropack_flush_backlog() {
1381 if (null !== $nitro = get_nitropack_sdk()) {
1382 try {
1383 if ($nitro->backlog->exists()) {
1384 return $nitro->backlog->replay(30);
1385 }
1386 } catch (\NitroPack\SDK\BacklogReplayTimeoutException $e) {
1387 $nitro->backlog->delete();
1388 return nitropack_sdk_purge(NULL, NULL, "Full purge after backlog timeout");
1389 } catch (\Exception $e) {
1390 return false;
1391 }
1392 }
1393 return true;
1394 }
1395
1396 function nitropack_cache_cleanup() {
1397 if (null !== $nitro = get_nitropack_sdk()) {
1398 $cacheDirParent = dirname($nitro->getCacheDir());
1399 $entries = scandir($cacheDirParent);
1400 foreach ($entries as $entry) {
1401 if (strpos($entry, ".stale.") !== false) {
1402 $cacheDir = nitropack_trailingslashit($cacheDirParent) . $entry;
1403 try {
1404 \NitroPack\SDK\Filesystem::deleteDir($cacheDir);
1405 } catch (\Exception $e) {
1406 // TODO: Log this
1407 return false;
1408 }
1409 }
1410 }
1411 }
1412 return true;
1413 }
1414 /* End Heartbeat Related Functions */
1415
1416 function nitropack_sdk_purge($url = NULL, $tag = NULL, $reason = NULL, $type = \NitroPack\SDK\PurgeType::COMPLETE) {
1417 if (null !== $nitro = get_nitropack_sdk()) {
1418 try {
1419 $siteConfig = nitropack_get_site_config();
1420 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
1421
1422 if ($tag) {
1423 if (is_array($tag)) {
1424 $tag = array_map('nitropack_filter_tag', $tag);
1425 } else {
1426 $tag = nitropack_filter_tag($tag);
1427 }
1428 }
1429
1430 if (!$url && !$tag) {
1431 $nitro->purgeLocalCache(true);
1432 }
1433
1434 $nitro->purgeCache($url, $tag, $type, $reason);
1435
1436 try {
1437 do_action('nitropack_integration_purge_url', $homeUrl);
1438
1439 if ($tag) {
1440 do_action('nitropack_integration_purge_all');
1441 } else if ($url) {
1442 do_action('nitropack_integration_purge_url', $url);
1443 } else {
1444 do_action('nitropack_integration_purge_all');
1445 }
1446 } catch (\Exception $e) {
1447 // Exception while signaling 3rd party integration addons to purge their cache
1448 }
1449 } catch (\Exception $e) {
1450 return false;
1451 }
1452
1453 return true;
1454 }
1455
1456 return false;
1457 }
1458
1459 function nitropack_sdk_purge_local($url = NULL) {
1460 if (null !== $nitro = get_nitropack_sdk()) {
1461 try {
1462 if ($url) {
1463 $nitro->purgeLocalUrlCache($url);
1464 do_action('nitropack_integration_purge_url', $url);
1465 } else {
1466 $nitro->purgeLocalCache(true);
1467
1468 try {
1469 do_action('nitropack_integration_purge_all');
1470 } catch (\Exception $e) {
1471 // Exception while signaling our 3rd party integration addons to purge their cache
1472 }
1473 }
1474 } catch (\Exception $e) {
1475 return false;
1476 }
1477
1478 return true;
1479 }
1480
1481 return false;
1482 }
1483
1484 function nitropack_sdk_delete_backlog() {
1485 if (null !== $nitro = get_nitropack_sdk()) {
1486 try {
1487 if ($nitro->backlog->exists()) {
1488 $nitro->backlog->delete();
1489 }
1490 } catch (\Exception $e) {
1491 return false;
1492 }
1493
1494 return true;
1495 }
1496
1497 return false;
1498 }
1499
1500 function nitropack_purge($url = NULL, $tag = NULL, $reason = NULL) {
1501 if ($tag != "pageType:home") {
1502 $siteConfig = nitropack_get_site_config();
1503 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
1504 nitropack_log_invalidate($homeUrl, "pageType:home", $reason);
1505 }
1506
1507 if ($tag != "pageType:archive") {
1508 nitropack_log_invalidate(NULL, "pageType:archive", $reason);
1509 }
1510
1511 nitropack_log_purge($url, $tag, $reason);
1512 }
1513
1514 function nitropack_log_purge($url = NULL, $tag = NULL, $reason = NULL) {
1515 global $np_loggedPurges;
1516 if ($tag && is_array($tag)) {
1517 foreach ($tag as $tagSingle) {
1518 nitropack_log_purge($url, $tagSingle, $reason);
1519 }
1520 return;
1521 }
1522
1523 $keyBase = "";
1524 if ($url) {
1525 $keyBase .= $url;
1526 }
1527
1528 if ($tag) {
1529 $tag = nitropack_filter_tag($tag);
1530 $keyBase .= $tag;
1531 }
1532
1533 $purgeRequestKey = md5($keyBase);
1534 if (is_array($np_loggedPurges) && array_key_exists($purgeRequestKey, $np_loggedPurges)) {
1535 $np_loggedPurges[$purgeRequestKey]["reason"] = $reason;
1536 $np_loggedPurges[$purgeRequestKey]["priority"]++;
1537 } else {
1538 $np_loggedPurges[$purgeRequestKey] = array(
1539 "url" => $url,
1540 "tag" => $tag,
1541 "reason" => $reason,
1542 "priority" => 1
1543 );
1544 }
1545 }
1546
1547 function nitropack_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
1548 if ($tag != "pageType:home") {
1549 $siteConfig = nitropack_get_site_config();
1550 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
1551 nitropack_log_invalidate($homeUrl, "pageType:home", $reason);
1552 }
1553
1554 if ($tag != "pageType:archive") {
1555 nitropack_log_invalidate(NULL, "pageType:archive", $reason);
1556 }
1557
1558 nitropack_log_invalidate($url, $tag, $reason);
1559 }
1560
1561 function nitropack_log_invalidate($url = NULL, $tag = NULL, $reason = NULL) {
1562 global $np_loggedInvalidations;
1563 if ($tag && is_array($tag)) {
1564 foreach ($tag as $tagSingle) {
1565 nitropack_log_invalidate($url, $tagSingle, $reason);
1566 }
1567 return;
1568 }
1569
1570 $keyBase = "";
1571 if ($url) {
1572 $keyBase .= $url;
1573 }
1574
1575 if ($tag) {
1576 $tag = nitropack_filter_tag($tag);
1577 $keyBase .= $tag;
1578 }
1579
1580 $invalidateRequestKey = md5($keyBase);
1581 if (is_array($np_loggedInvalidations) && array_key_exists($invalidateRequestKey, $np_loggedInvalidations)) {
1582 $np_loggedInvalidations[$invalidateRequestKey]["reason"] = $reason;
1583 $np_loggedInvalidations[$invalidateRequestKey]["priority"]++;
1584 } else {
1585 $np_loggedInvalidations[$invalidateRequestKey] = array(
1586 "url" => $url,
1587 "tag" => $tag,
1588 "reason" => $reason,
1589 "priority" => 1
1590 );
1591 }
1592 }
1593
1594 function nitropack_queue_sort($a, $b) {
1595 if ($a["priority"] == $b["priority"]) {
1596 return 0;
1597 }
1598 return ($a["priority"] < $b["priority"]) ? -1 : 1;
1599 }
1600
1601 function nitropack_execute_purges() {
1602 global $np_loggedPurges;
1603 if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1604 return;
1605 }
1606 if (!empty($np_loggedPurges)) {
1607 uasort($np_loggedPurges, "nitropack_queue_sort");
1608 foreach ($np_loggedPurges as $requestKey => $data) {
1609 nitropack_sdk_purge($data["url"], $data["tag"], $data["reason"]);
1610 }
1611 }
1612 }
1613
1614 function nitropack_execute_invalidations() {
1615 global $np_loggedInvalidations;
1616 if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1617 return;
1618 }
1619 if (!empty($np_loggedInvalidations)) {
1620 uasort($np_loggedInvalidations, "nitropack_queue_sort");
1621 foreach ($np_loggedInvalidations as $requestKey => $data) {
1622 nitropack_sdk_invalidate($data["url"], $data["tag"], $data["reason"]);
1623 }
1624 }
1625 }
1626
1627 function nitropack_execute_warmups() {
1628 global $np_loggedWarmups;
1629 if (!empty($_GET["action"]) && ($_GET["action"] === "edit") && !empty($_GET["meta-box-loader"])) {
1630 return;
1631 }
1632 try {
1633 if (!empty($np_loggedWarmups) && (null !== $nitro = get_nitropack_sdk())) {
1634 $warmupStats = $nitro->getApi()->getWarmupStats();
1635 if (!empty($warmupStats["status"])) {
1636 foreach (array_unique($np_loggedWarmups) as $url) {
1637 $nitro->getApi()->runWarmup($url);
1638 }
1639 }
1640 }
1641 } catch (\Exception $e) {}
1642 }
1643
1644 function nitropack_fetch_config() {
1645 if (null !== $nitro = get_nitropack_sdk()) {
1646 try {
1647 $nitro->fetchConfig();
1648 } catch (\Exception $e) {}
1649 }
1650 }
1651
1652 function nitropack_theme_handler($event = NULL) {
1653 if (!get_option("nitropack-autoCachePurge", 1)) return;
1654
1655 $msg = $event ? $event : 'Theme switched';
1656
1657 try {
1658 nitropack_sdk_purge(NULL, NULL, $msg); // purge entire cache
1659 } catch (\Exception $e) {}
1660 }
1661
1662 function nitropack_purge_cache() {
1663 try {
1664 if (nitropack_sdk_purge(NULL, NULL, 'Manual purge of all pages')) {
1665 nitropack_json_and_exit(array(
1666 "type" => "success",
1667 "message" => "Success! Cache has been purged successfully!"
1668 ));
1669 }
1670 } catch (\Exception $e) {}
1671
1672 nitropack_json_and_exit(array(
1673 "type" => "error",
1674 "message" => "Error! There was an error and the cache was not purged!"
1675 ));
1676 }
1677
1678 function nitropack_invalidate_cache() {
1679 try {
1680 if (nitropack_sdk_invalidate(NULL, NULL, 'Manual invalidation of all pages')) {
1681 nitropack_json_and_exit(array(
1682 "type" => "success",
1683 "message" => "Success! Cache has been invalidated successfully!"
1684 ));
1685 }
1686 } catch (\Exception $e) {}
1687
1688 nitropack_json_and_exit(array(
1689 "type" => "error",
1690 "message" => "Error! There was an error and the cache was not invalidated!"
1691 ));
1692 }
1693
1694 function nitropack_clear_residual_cache() {
1695 $gde = !empty($_POST["gde"]) ? $_POST["gde"] : NULL;
1696 if ($gde && array_key_exists($gde, NitroPack\Integration\Plugin\RC::$modules)) {
1697 $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
1698 if (!in_array(false, $result)) {
1699 nitropack_json_and_exit(array(
1700 "type" => "success",
1701 "message" => "Success! The residual cache has been cleared successfully!"
1702 ));
1703 }
1704 }
1705 nitropack_json_and_exit(array(
1706 "type" => "error",
1707 "message" => "Error! There was an error clearing the residual cache!"
1708 ));
1709 }
1710
1711 function nitropack_json_and_exit($array) {
1712 if (nitropack_is_wp_cli()) {
1713 $type = NULL;
1714 if (array_key_exists("status", $array)) {
1715 $type = $array["status"];
1716 } else if (array_key_exists("type", $array)) {
1717 $type = $array["type"];
1718 }
1719
1720 if ($type && array_key_exists("message", $array)) {
1721 if ($type == "success") {
1722 WP_CLI::success($array["message"]);
1723 } else {
1724 WP_CLI::error($array["message"]);
1725 }
1726 }
1727 } else {
1728 echo json_encode($array);
1729 }
1730 exit;
1731 }
1732
1733 function nitropack_has_post_important_change($post) {
1734 $prevPost = nitropack_get_post_pre_update($post);
1735 return $prevPost && ($prevPost->post_title != $post->post_title || $prevPost->post_name != $post->post_name || $prevPost->post_excerpt != $post->post_excerpt);
1736 }
1737
1738 function nitropack_purge_single_cache() {
1739 if (!empty($_POST["postId"]) && is_numeric($_POST["postId"])) {
1740 $postId = $_POST["postId"];
1741 $postUrl = !empty($_POST["postUrl"]) ? $_POST["postUrl"] : NULL;
1742 $reason = sprintf("Manual purge of post %s via the WordPress admin panel", $postId);
1743 $tag = $postId > 0 ? "single:$postId" : NULL;
1744
1745 if ($postUrl) {
1746 if (is_array($postUrl)) {
1747 foreach ($postUrl as &$url) {
1748 $url = nitropack_sanitize_url_input($url);
1749 }
1750 } else {
1751 $postUrl = nitropack_sanitize_url_input($postUrl);
1752 $reason = "Manual purge of " . $postUrl;
1753 }
1754 }
1755
1756 try {
1757 if (nitropack_sdk_purge($postUrl, $tag, $reason)) {
1758 nitropack_json_and_exit(array(
1759 "type" => "success",
1760 "message" => "Success! Cache has been purged successfully!"
1761 ));
1762 }
1763 } catch (\Exception $e) {}
1764 }
1765
1766 nitropack_json_and_exit(array(
1767 "type" => "error",
1768 "message" => "Error! There was an error and the cache was not purged!"
1769 ));
1770 }
1771
1772 function nitropack_invalidate_single_cache() {
1773 if (!empty($_POST["postId"]) && is_numeric($_POST["postId"])) {
1774 $postId = $_POST["postId"];
1775 $postUrl = !empty($_POST["postUrl"]) ? $_POST["postUrl"] : NULL;
1776 $reason = sprintf("Manual invalidation of post %s via the WordPress admin panel", $postId);
1777 $tag = $postId > 0 ? "single:$postId" : NULL;
1778
1779 if ($postUrl) {
1780 if (is_array($postUrl)) {
1781 foreach ($postUrl as &$url) {
1782 $url = nitropack_sanitize_url_input($url);
1783 }
1784 } else {
1785 $postUrl = nitropack_sanitize_url_input($postUrl);
1786 $reason = "Manual invalidation of " . $postUrl;
1787 }
1788 }
1789
1790 try {
1791 if (nitropack_sdk_invalidate($postUrl, $tag, $reason)) {
1792 nitropack_json_and_exit(array(
1793 "type" => "success",
1794 "message" => "Success! Cache has been invalidated successfully!"
1795 ));
1796 }
1797 } catch (\Exception $e) {}
1798 }
1799
1800 nitropack_json_and_exit(array(
1801 "type" => "error",
1802 "message" => "Error! There was an error and the cache was not invalidated!"
1803 ));
1804 }
1805
1806 function nitropack_clean_post_cache($post, $taxonomies = NULL, $hasImportantChangeInPost = NULL, $reason = NULL, $usePurge = false) {
1807 try {
1808 $postID = $post->ID;
1809 $postType = isset($post->post_type) ? $post->post_type : "post";
1810 $nicePostTypeLabel = nitropack_get_nice_post_type_label($postType);
1811 $reason = $reason ? $reason : sprintf("Updated %s '%s'", $nicePostTypeLabel, $post->post_title);
1812 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
1813
1814 if (in_array($postType, $cacheableObjectTypes)) {
1815 if ($usePurge) {
1816 // We only purge the single pages because they have to immediately stop serving cache
1817 // These pages no longer exists and if their URL is requested we must not server cache
1818 nitropack_purge(NULL, "single:$postID", $reason);
1819 } else {
1820 nitropack_invalidate(NULL, "single:$postID", $reason);
1821 }
1822
1823 nitropack_invalidate(NULL, "post:$postID", $reason);
1824
1825 if ($hasImportantChangeInPost === NULL) {
1826 $hasImportantChangeInPost = nitropack_has_post_important_change($post);
1827 }
1828 if ($taxonomies === NULL) {
1829 if ($hasImportantChangeInPost) { // This change should be reflected in all taxonomy pages
1830 $taxonomies = array('related' => nitropack_get_taxonomies($post));
1831 } else { // No important change, so only update taxonomy pages which have been added or removed from the post
1832 $taxonomies = nitropack_get_taxonomies_for_update($post);
1833 }
1834 }
1835 if ($taxonomies) {
1836 if (!empty($taxonomies['added'])) { // taxonomies that the post was just added to, must purge all pages for these taxonomies
1837 foreach ($taxonomies['added'] as $term_taxonomy_id) {
1838 nitropack_invalidate(NULL, "tax:$term_taxonomy_id", $reason);
1839 }
1840 }
1841 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:)
1842 foreach ($taxonomies['deleted'] as $term_taxonomy_id) {
1843 nitropack_invalidate(NULL, "taxpost:$term_taxonomy_id:$postID", $reason);
1844 }
1845 }
1846 if (!empty($taxonomies['related'])) { // taxonomy pages that the post is linked to (also accounts for paginations via the taxpost: tag instead of only tax:)
1847 foreach ($taxonomies['related'] as $term_taxonomy_id) {
1848 nitropack_invalidate(NULL, "taxpost:$term_taxonomy_id:$postID", $reason);
1849 }
1850 }
1851 }
1852 } else {
1853 if ($post->public) {
1854 nitropack_invalidate(NULL, "post:$postID", $reason);
1855 }
1856
1857 $posts = get_post_ancestors($postID);
1858 foreach ($posts as $parentID) {
1859 $parent = get_post($parentID);
1860 nitropack_clean_post_cache($parent, false, false, $reason);
1861 }
1862 }
1863 } catch (\Exception $e) {}
1864 }
1865
1866 function nitropack_get_nice_post_type_label($postType) {
1867 $postTypes = get_post_types(array(
1868 "name" => $postType
1869 ), "objects");
1870
1871 return !empty($postTypes[$postType]) && !empty($postTypes[$postType]->labels) ? $postTypes[$postType]->labels->singular_name : $postType;
1872 }
1873
1874 function nitropack_handle_comment_transition($new, $old, $comment) {
1875 if (!get_option("nitropack-autoCachePurge", 1)) return;
1876
1877 try {
1878 $postID = $comment->comment_post_ID;
1879 $post = get_post($postID);
1880 $postType = isset($post->post_type) ? $post->post_type : "post";
1881 $cacheableObjectTypes = nitropack_get_cacheable_object_types();
1882
1883 if (in_array($postType, $cacheableObjectTypes)) {
1884 nitropack_invalidate(NULL, "single:" . $postID, sprintf("Invalidation of '%s' due to changing related comment status", $post->post_title));
1885 }
1886 } catch (\Exception $e) {
1887 // TODO: Log the error
1888 }
1889 }
1890
1891 function nitropack_handle_comment_post($commentID, $isApproved) {
1892 if (!get_option("nitropack-autoCachePurge", 1) || $isApproved !== 1) return;
1893
1894 try {
1895 $comment = get_comment($commentID);
1896 $postID = $comment->comment_post_ID;
1897 $post = get_post($postID);
1898 nitropack_invalidate(NULL, "single:" . $postID, sprintf("Invalidation of '%s' due to posting a new approved comment", $post->post_title));
1899 } catch (\Exception $e) {
1900 // TODO: Log the error
1901 }
1902 }
1903
1904 function nitropack_handle_post_transition($new, $old, $post) {
1905 global $np_loggedWarmups;
1906 if (!empty($post->ID) && in_array($post->ID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs)) return;
1907 if (!get_option("nitropack-autoCachePurge", 1)) return;
1908
1909 try {
1910 if ($new === "auto-draft" || ($new === "draft" && $old != "publish") || $new === "inherit") { // Creating a new post or draft, don't do anything for now.
1911 return;
1912 }
1913
1914 $ignoredPostTypes = array(
1915 "revision",
1916 "scheduled-action",
1917 "flamingo_contact",
1918 "carts"/*WooCommerce Cart Reports*/
1919 );
1920
1921 $nicePostTypes = array(
1922 "post" => "Post",
1923 "page" => "Page",
1924 "tribe_events" => "Calendar Event",
1925 );
1926 $postType = isset($post->post_type) ? $post->post_type : "post";
1927 $nicePostTypeLabel = nitropack_get_nice_post_type_label($postType);
1928
1929 if (in_array($postType, $ignoredPostTypes)) return;
1930
1931 switch ($postType) {
1932 case "nav_menu_item":
1933 nitropack_invalidate(NULL, NULL, sprintf("Invalidation of all pages due to modifying menu entries"));
1934 break;
1935 case "customize_changeset":
1936 nitropack_invalidate(NULL, NULL, sprintf("Invalidation of all pages due to applying appearance customization"));
1937 break;
1938 case "custom_css":
1939 nitropack_invalidate(NULL, NULL, sprintf("Invalidation of all pages due to modifying custom CSS"));
1940 break;
1941 default:
1942 if ($new == "future") {
1943 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));
1944 } else if ($new == "publish" && $old != "publish") {
1945 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));
1946 $np_loggedWarmups[] = get_permalink($post);
1947 } else if ($new == "trash" && $old == "publish") {
1948 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);
1949 } else if ($new == "private" && $old == "publish") {
1950 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);
1951 } else if ($new == "draft" && $old == "publish") {
1952 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);
1953 } else if ($new != "trash") {
1954 nitropack_clean_post_cache($post);
1955 $np_loggedWarmups[] = get_permalink($post);
1956 }
1957 break;
1958 }
1959 } catch (\Exception $e) {
1960 // TODO: Log the error
1961 }
1962 }
1963
1964 function nitropack_handle_product_updates($product, $updated) {
1965 if (!get_option("nitropack-autoCachePurge", 1)) return;
1966
1967 try {
1968 $post = get_post($product->get_id());
1969 $reasons = 'updated ';
1970 $reasons .= implode(',', $updated);
1971 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
1972 } catch (\Exception $e) {
1973 // TODO: Log the error
1974 }
1975 }
1976
1977 function nitropack_post_link_listener($permalink, $post, $leavename) {
1978 if (is_object($post)) {
1979 nitropack_handle_the_post($post);
1980 }
1981
1982 return $permalink;
1983 }
1984
1985 function nitropack_handle_the_post($post) {
1986 global $np_customExpirationTimes, $np_queriedObj;
1987 if (defined('POSTEXPIRATOR_VERSION')) {
1988 $postExpiryDate = get_post_meta($post->ID, "_expiration-date", true);
1989 if (!empty($postExpiryDate) && $postExpiryDate > time()) { // We only need to look at future dates
1990 $np_customExpirationTimes[] = $postExpiryDate;
1991 }
1992 }
1993
1994 if (function_exists("sort_portfolio")) { // Portfolio Sorting plugin
1995 $portfolioStartDate = get_post_meta($post->ID, "start_date", true);
1996 $portfolioEndDate = get_post_meta($post->ID, "end_date", true);
1997 if (!empty($portfolioStartDate) && strtotime($portfolioStartDate) > time()) { // We only need to look at future dates
1998 $np_customExpirationTimes[] = strtotime($portfolioStartDate);
1999 } else if (!empty($portfolioEndDate) && strtotime($portfolioEndDate) > time()) { // We only need to look at future dates
2000 $np_customExpirationTimes[] = strtotime($portfolioEndDate);
2001 }
2002 }
2003
2004 $GLOBALS["NitroPack.tags"]["post:" . $post->ID] = 1;
2005 $GLOBALS["NitroPack.tags"]["author:" . $post->post_author] = 1;
2006 if ($np_queriedObj) {
2007 $GLOBALS["NitroPack.tags"]["taxpost:" . $np_queriedObj->term_taxonomy_id . ":" . $post->ID] = 1;
2008 }
2009 }
2010
2011 function nitropack_ignore_post_updates($postID) {
2012 \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs[] = $postID;
2013 }
2014
2015 function nitropack_get_taxonomies($post) {
2016 $term_taxonomy_ids = array();
2017 $taxonomies = get_object_taxonomies($post->post_type);
2018 foreach ($taxonomies as $taxonomy) {
2019 $terms = get_the_terms( $post->ID, $taxonomy );
2020 if (!empty($terms)) {
2021 foreach ($terms as $term) {
2022 $term_taxonomy_ids[] = $term->term_taxonomy_id;
2023 }
2024 }
2025 }
2026 return $term_taxonomy_ids;
2027 }
2028
2029 function nitropack_get_taxonomies_for_update($post) {
2030 $prevTaxonomies = nitropack_get_taxonomies_pre_update($post);
2031 $newTaxonomies = nitropack_get_taxonomies($post);
2032 $intersection = array_intersect($newTaxonomies, $prevTaxonomies);
2033 $prevTaxonomies = array_diff($prevTaxonomies, $intersection);
2034 $newTaxonomies = array_diff($newTaxonomies, $intersection);
2035 return array(
2036 "added" => array_diff($newTaxonomies, $prevTaxonomies),
2037 "deleted" => array_diff($prevTaxonomies, $newTaxonomies)
2038 );
2039 }
2040
2041 function nitropack_get_post_pre_update($post) {
2042 return !empty(\NitroPack\WordPress\NitroPack::$preUpdatePosts[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdatePosts[$post->ID] : NULL;
2043 }
2044
2045 function nitropack_get_taxonomies_pre_update($post) {
2046 return !empty(\NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$post->ID]) ? \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$post->ID] : array();
2047 }
2048
2049 function nitropack_log_post_pre_update($postID) {
2050 if (in_array($postID, \NitroPack\WordPress\NitroPack::$ignoreUpdatePostIDs)) return;
2051
2052 $post = get_post($postID);
2053 \NitroPack\WordPress\NitroPack::$preUpdatePosts[$postID] = $post;
2054 \NitroPack\WordPress\NitroPack::$preUpdateTaxonomies[$postID] = nitropack_get_taxonomies($post);
2055 }
2056
2057 function nitropack_filter_tag($tag) {
2058 return preg_replace("/[^a-zA-Z0-9:]/", ":", $tag);
2059 }
2060
2061 function nitropack_log_tags() {
2062 if (!empty($GLOBALS["NitroPack.instance"]) && !empty($GLOBALS["NitroPack.tags"])) {
2063 $nitro = $GLOBALS["NitroPack.instance"];
2064 $layout = nitropack_get_layout();
2065 try {
2066 if ($layout == "home") {
2067 $nitro->getApi()->tagUrl($nitro->getUrl(), "pageType:home");
2068 } else if ($layout == "archive") {
2069 $nitro->getApi()->tagUrl($nitro->getUrl(), "pageType:archive");
2070 } else {
2071 $nitro->getApi()->tagUrl($nitro->getUrl(), array_map("nitropack_filter_tag", array_keys($GLOBALS["NitroPack.tags"])));
2072 }
2073 } catch (\Exception $e) {}
2074 }
2075 }
2076
2077 function nitropack_extend_nonce_life($life) {
2078 // Nonce life should be extended only:
2079 // - if NitroPack is connected for this site
2080 // - if the current value is shorter than the life time of a cache file
2081 // - if no user is logged in
2082 // - for cacheable requests
2083 //
2084 // Reasons why we might need to extend the nonce life time even for requests that are not cacheable:
2085 // - 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)
2086 // - 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.)
2087
2088 if ((null !== $nitro = get_nitropack_sdk())) {
2089 $siteConfig = nitropack_get_site_config();
2090 if ($siteConfig && !empty($siteConfig["isDlmActive"]) && !empty($siteConfig["dlm_downloading_url"]) && !empty($siteConfig["dlm_download_endpoint"])) {
2091 $currentUrl = $nitro->getUrl();
2092 if (strpos($currentUrl, $siteConfig["dlm_downloading_url"]) !== false || strpos($currentUrl, $siteConfig["dlm_download_endpoint"]) !== false) {
2093 // Do not modify the nonce times on pages of Download Monitor
2094 return $life;
2095 }
2096 }
2097 $cacheExpiration = $nitro->getConfig()->PageCache->ExpireTime;
2098 return $cacheExpiration > $life ? $cacheExpiration : $life; // Extend the life of cacheable nonces up to the cache expiration time if needed
2099 }
2100 return $life;
2101 }
2102
2103 function nitropack_reconfigure_webhooks() {
2104 $siteConfig = nitropack_get_site_config();
2105
2106 if ($siteConfig && !empty($siteConfig["siteId"])) {
2107 $siteId = $siteConfig["siteId"];
2108 if (null !== $nitro = get_nitropack_sdk()) {
2109 $token = nitropack_generate_webhook_token($siteId);
2110 try {
2111 nitropack_setup_webhooks($nitro, $token);
2112 update_option("nitropack-webhookToken", $token);
2113 nitropack_json_and_exit(array("status" => "success"));
2114 } catch (\NitroPack\SDK\WebhookException $e) {
2115 nitropack_json_and_exit(array("status" => "error", "message" => "Webhook Error: " . $e->getMessage()));
2116 }
2117 } else {
2118 nitropack_json_and_exit(array("status" => "error", "message" => "Unable to get SDK instance"));
2119 }
2120 } else {
2121 nitropack_json_and_exit(array("status" => "error", "message" => "Incomplete site config. Please reinstall the plugin!"));
2122 }
2123 }
2124
2125 function nitropack_generate_webhook_token($siteId) {
2126 return md5(__FILE__ . ":" . $siteId);
2127 }
2128
2129 function nitropack_verify_connect_ajax() {
2130 $siteId = !empty($_POST["siteId"]) ? $_POST["siteId"] : "";
2131 $siteSecret = !empty($_POST["siteSecret"]) ? $_POST["siteSecret"] : "";
2132 nitropack_verify_connect($siteId, $siteSecret);
2133 }
2134
2135 function nitropack_check_func_availability($func_name) {
2136 if (function_exists('ini_get')) {
2137 $existsResult = stripos(ini_get('disable_functions'), $func_name) === false;
2138 } else {
2139 $existsResult = function_exists($func_name);
2140 }
2141 return $existsResult;
2142 }
2143
2144 function nitropack_prevent_connecting($nitroSDK) {
2145 $remoteUrl = $nitroSDK->getApi()->getWebhook("config");
2146 if (empty($remoteUrl)) {
2147 return false;
2148 }
2149 $siteConfig = nitropack_get_site_config();
2150 $localUrl = new \NitroPack\Url($siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url());
2151 $localHome = strtolower($localUrl->getHost() . $localUrl->getPath());
2152 $storedUrl = new \NitroPack\Url($remoteUrl);
2153 $remoteHome = strtolower($storedUrl->getHost() . $storedUrl->getPath());
2154 if ($localHome === $remoteHome) {
2155 return false;
2156 }
2157 return array('local' => $localHome, 'remote' => $remoteHome);
2158 }
2159
2160 function nitropack_verify_connect($siteId, $siteSecret) {
2161 if (!nitropack_check_func_availability('stream_socket_client')) {
2162 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>"));
2163 }
2164
2165 if (empty($siteId) || empty($siteSecret)) {
2166 nitropack_json_and_exit(array("status" => "error", "message" => "Site ID and Site Secret cannot be empty"));
2167 }
2168
2169 //remove tags and whitespaces
2170 $siteId = trim(esc_attr($siteId));
2171 $siteSecret = trim(esc_attr($siteSecret));
2172
2173 if (!nitropack_validate_site_id($siteId) || !nitropack_validate_site_secret($siteSecret)) {
2174 nitropack_json_and_exit(array("status" => "error", "message" => "Invalid Site ID or Site Secret value"));
2175 }
2176
2177 try {
2178 $blogId = get_current_blog_id();
2179 if (null !== $nitro = get_nitropack_sdk($siteId, $siteSecret, NULL, true)) {
2180 if (!$nitro->checkHealthStatus()) {
2181 nitropack_json_and_exit(array(
2182 "status" => "error",
2183 "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>."
2184 ));
2185 }
2186
2187 $preventParing = apply_filters('nitropack_prevent_connect', nitropack_prevent_connecting($nitro));
2188 if ($preventParing) {
2189 nitropack_json_and_exit(array(
2190 "status" => "error",
2191 "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/>
2192 <a href='https://support.nitropack.io/hc/en-us/articles/4405254569745' target='_blank' rel='noreferrer noopener'>Read more</a>"
2193 ));
2194 }
2195 $token = nitropack_generate_webhook_token($siteId);
2196 update_option("nitropack-webhookToken", $token);
2197 update_option("nitropack-enableCompression", -1);
2198 update_option("nitropack-autoCachePurge", get_option("nitropack-autoCachePurge", 1));
2199 update_option("nitropack-cacheableObjectTypes", nitropack_get_default_cacheable_object_types());
2200
2201 nitropack_setup_webhooks($nitro, $token);
2202
2203 // _icl_current_language is WPML cookie, it is added here for compatibility with this module
2204 $customVariationCookies = array("np_wc_currency", "np_wc_currency_language", "_icl_current_language");
2205 $variationCookies = $nitro->getApi()->getVariationCookies();
2206 foreach ($variationCookies as $cookie) {
2207 $index = array_search($cookie["name"], $customVariationCookies);
2208 if ($index !== false) {
2209 array_splice($customVariationCookies, $index, 1);
2210 }
2211 }
2212
2213 foreach ($customVariationCookies as $cookieName) {
2214 $nitro->getApi()->setVariationCookie($cookieName);
2215 }
2216
2217 $nitro->fetchConfig(); // Reload the variation cookies
2218
2219 get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId);
2220 nitropack_install_advanced_cache();
2221 update_option("nitropack-siteId", $siteId);
2222 update_option("nitropack-siteSecret", $siteSecret);
2223
2224 try {
2225 do_action('nitropack_integration_purge_all');
2226 } catch (\Exception $e) {
2227 // Exception while signaling our 3rd party integration addons to purge their cache
2228 }
2229
2230 nitropack_event("connect", $nitro);
2231 nitropack_event("enable_extension", $nitro);
2232
2233 // Optimize front page
2234 $siteConfig = nitropack_get_site_config();
2235 if ($siteConfig) {
2236 $nitro->getApi()->runWarmup([$siteConfig['home_url']], true); // force run a warmup on the home page
2237 }
2238
2239 nitropack_json_and_exit(array("status" => "success"));
2240 }
2241 } catch (\NitroPack\SDK\WebhookException $e) {
2242 nitropack_json_and_exit(array("status" => "error", "message" => $e->getMessage()));
2243 } catch (\NitroPack\SDK\StorageException $e) {
2244 nitropack_json_and_exit(array("status" => "error", "message" => "Permission Error: " . $e->getMessage()));
2245 } catch (\NitroPack\SDK\EmptyConfigException $e) {
2246 nitropack_json_and_exit(array("status" => "error", "message" => "Error while fetching remote config: " . $e->getMessage()));
2247 } catch (\NitroPack\SocketOpenException $e) {
2248 nitropack_json_and_exit(array("status" => "error", "message" => "Can't establish connection with NitroPack's servers"));
2249 } catch (\Exception $e) {
2250 nitropack_json_and_exit(array("status" => "error", "message" => "Incorrect API credentials. Please make sure that you copied them correctly and try again."));
2251 }
2252
2253 nitropack_json_and_exit(array("status" => "error"));
2254 }
2255
2256 function nitropack_reset_webhooks($nitroSDK) {
2257 $nitroSDK->getApi()->unsetWebhook("config");
2258 $nitroSDK->getApi()->unsetWebhook("cache_clear");
2259 $nitroSDK->getApi()->unsetWebhook("cache_ready");
2260 }
2261
2262 function nitropack_setup_webhooks($nitro, $token = NULL) {
2263 if (!$nitro || !$token) {
2264 throw new \NitroPack\SDK\WebhookException('Webhook token cannot be empty.');
2265 }
2266
2267 $homeUrl = strtolower(get_home_url());
2268 $configUrl = new \NitroPack\Url($homeUrl . "?nitroWebhook=config&token=$token");
2269 $cacheClearUrl = new \NitroPack\Url($homeUrl . "?nitroWebhook=cache_clear&token=$token");
2270 $cacheReadyUrl = new \NitroPack\Url($homeUrl . "?nitroWebhook=cache_ready&token=$token");
2271
2272 $nitro->getApi()->setWebhook("config", $configUrl);
2273 $nitro->getApi()->setWebhook("cache_clear", $cacheClearUrl);
2274 $nitro->getApi()->setWebhook("cache_ready", $cacheReadyUrl);
2275 }
2276
2277 function nitropack_disconnect() {
2278 nitropack_uninstall_advanced_cache();
2279
2280 try {
2281 nitropack_event("disconnect");
2282 if (null !== $nitro = get_nitropack_sdk()) {
2283 nitropack_reset_webhooks($nitro);
2284 }
2285 } catch (\Exception $e) {
2286 }
2287
2288 get_nitropack()->unsetCurrentBlogConfig();
2289 delete_option("nitropack-siteId");
2290 delete_option("nitropack-siteSecret");
2291
2292 $hostingNoticeFile = nitropack_get_hosting_notice_file();
2293 if (file_exists($hostingNoticeFile)) {
2294 if (WP_DEBUG) {
2295 unlink($hostingNoticeFile);
2296 } else {
2297 @unlink($hostingNoticeFile);
2298 }
2299 }
2300 }
2301
2302 function nitropack_set_compression_ajax() {
2303 $compressionStatus = !empty($_POST["data"]["compressionStatus"]);
2304 update_option("nitropack-enableCompression", (int)$compressionStatus);
2305 nitropack_json_and_exit(array("status" => "success", "hasCompression" => $compressionStatus));
2306 }
2307
2308 function nitropack_set_auto_cache_purge_ajax() {
2309 $autoCachePurgeStatus = !empty($_POST["autoCachePurgeStatus"]);
2310 update_option("nitropack-autoCachePurge", (int)$autoCachePurgeStatus);
2311 }
2312
2313 function nitropack_set_bb_cache_purge_sync_ajax() {
2314 $bbCacheSyncPurgeStatus = !empty($_POST["bbCachePurgeSyncStatus"]);
2315 update_option("nitropack-bbCacheSyncPurge", (int)$bbCacheSyncPurgeStatus);
2316 }
2317
2318 function nitropack_set_cacheable_post_types() {
2319 $currentCacheableObjectTypes = nitropack_get_cacheable_object_types();
2320 $cacheableObjectTypes = !empty($_POST["cacheableObjectTypes"]) ? $_POST["cacheableObjectTypes"] : array();
2321 update_option("nitropack-cacheableObjectTypes", $cacheableObjectTypes);
2322
2323 foreach ($currentCacheableObjectTypes as $objectType) {
2324 if (!in_array($objectType, $cacheableObjectTypes)) {
2325 nitropack_purge(NULL, "pageType:" . $objectType, "Optimizing '$objectType' pages was manually disabled");
2326 }
2327 }
2328
2329 nitropack_json_and_exit(array(
2330 "type" => "success",
2331 "message" => "Success! Cacheable post types have been updated!"
2332 ));
2333 }
2334
2335 function nitropack_test_compression_ajax() {
2336 $hasCompression = true;
2337 try {
2338 if (\NitroPack\Integration\Hosting\Flywheel::detect()) { // Flywheel: Compression is enabled by default
2339 update_option("nitropack-enableCompression", 0);
2340 } else {
2341 require_once plugin_dir_path(__FILE__) . nitropack_trailingslashit('nitropack-sdk') . 'autoload.php';
2342 $http = new NitroPack\HttpClient(get_site_url());
2343 $http->setHeader("X-NitroPack-Request", 1);
2344 $http->timeout = 25;
2345 $http->fetch();
2346 $headers = $http->getHeaders();
2347 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
2348 update_option("nitropack-enableCompression", 0);
2349 $hasCompression = true;
2350 } else { // no compression, we must enable it from NitroPack
2351 update_option("nitropack-enableCompression", 1);
2352 $hasCompression = false;
2353 }
2354 }
2355 update_option("nitropack-checkedCompression", 1);
2356 } catch (\Exception $e) {
2357 nitropack_json_and_exit(array("status" => "error"));
2358 }
2359
2360 nitropack_json_and_exit(array("status" => "success", "hasCompression" => $hasCompression));
2361 }
2362
2363 function nitropack_handle_compression_toggle($old_value, $new_value) {
2364 nitropack_update_blog_compression($new_value == 1);
2365 }
2366
2367 function nitropack_update_blog_compression($enableCompression = false) {
2368 if (get_nitropack()->isConnected()) {
2369 $siteId = esc_attr( get_option('nitropack-siteId') );
2370 $siteSecret = esc_attr( get_option('nitropack-siteSecret') );
2371 $blogId = get_current_blog_id();
2372 get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId, $enableCompression);
2373 }
2374 }
2375
2376 function nitropack_enable_warmup() {
2377 if (null !== $nitro = get_nitropack_sdk()) {
2378 try {
2379 $nitro->getApi()->enableWarmup();
2380 $nitro->getApi()->setWarmupHomepage(get_home_url());
2381 $nitro->getApi()->runWarmup();
2382 } catch (\Exception $e) {
2383 }
2384
2385 nitropack_json_and_exit(array(
2386 "type" => "success",
2387 "message" => "Success! Cache warmup has been enabled successfully!"
2388 ));
2389 }
2390
2391 nitropack_json_and_exit(array(
2392 "type" => "error",
2393 "message" => "Error! There was an error while enabling the cache warmup!"
2394 ));
2395 }
2396
2397 function nitropack_disable_warmup() {
2398 if (null !== $nitro = get_nitropack_sdk()) {
2399 try {
2400 $nitro->getApi()->disableWarmup();
2401 $nitro->getApi()->resetWarmup();
2402 } catch (\Exception $e) {
2403 }
2404
2405 nitropack_json_and_exit(array(
2406 "type" => "success",
2407 "message" => "Success! Cache warmup has been disabled successfully!"
2408 ));
2409 }
2410
2411 nitropack_json_and_exit(array(
2412 "type" => "error",
2413 "message" => "Error! There was an error while disabling the cache warmup!"
2414 ));
2415 }
2416
2417 function nitropack_run_warmup() {
2418 if (null !== $nitro = get_nitropack_sdk()) {
2419 try {
2420 $nitro->getApi()->runWarmup();
2421 } catch (\Exception $e) {
2422 }
2423
2424 nitropack_json_and_exit(array(
2425 "type" => "success",
2426 "message" => "Success! Cache warmup has been started successfully!"
2427 ));
2428 }
2429
2430 nitropack_json_and_exit(array(
2431 "type" => "error",
2432 "message" => "Error! There was an error while starting the cache warmup!"
2433 ));
2434 }
2435
2436 function nitropack_estimate_warmup() {
2437 if (null !== $nitro = get_nitropack_sdk()) {
2438 try {
2439 if (!session_id()) {
2440 session_start();
2441 }
2442 $id = !empty($_POST["estId"]) ? preg_replace("/[^a-fA-F0-9]/", "", (string)$_POST["estId"]) : NULL;
2443 if ($id !== NULL && (!is_string($id) || $id != $_SESSION["nitroEstimateId"])) {
2444 nitropack_json_and_exit(array(
2445 "type" => "error",
2446 "message" => "Error! Invalid estimation ID!"
2447 ));
2448 }
2449
2450 $nitro->getApi()->setWarmupHomepage(get_home_url());
2451 $optimizationsEstimate = $nitro->getApi()->estimateWarmup($id);
2452
2453 if ($id === NULL) {
2454 $_SESSION["nitroEstimateId"] = $optimizationsEstimate; // When id is NULL, $optimizationsEstimate holds the ID for the newly started estimate
2455 }
2456 } catch (\Exception $e) {
2457 }
2458
2459 nitropack_json_and_exit(array(
2460 "type" => "success",
2461 "res" => $optimizationsEstimate
2462 ));
2463 }
2464
2465 nitropack_json_and_exit(array(
2466 "type" => "error",
2467 "message" => "Error! There was an error while estimating the cache warmup!"
2468 ));
2469 }
2470
2471 function nitropack_warmup_stats() {
2472 if (null !== $nitro = get_nitropack_sdk()) {
2473 try {
2474 $stats = $nitro->getApi()->getWarmupStats();
2475 } catch (\Exception $e) {
2476 nitropack_json_and_exit(array(
2477 "type" => "error",
2478 "message" => "Error! There was an error while fetching warmup stats!"
2479 ));
2480 }
2481
2482 nitropack_json_and_exit(array(
2483 "type" => "success",
2484 "stats" => $stats
2485 ));
2486 }
2487
2488 nitropack_json_and_exit(array(
2489 "type" => "error",
2490 "message" => "Error! There was an error while fetching warmup stats!"
2491 ));
2492 }
2493
2494 function nitropack_enable_safemode() {
2495 if (null !== $nitro = get_nitropack_sdk()) {
2496 try {
2497 $nitro->enableSafeMode();
2498 } catch (\Exception $e) {
2499 }
2500
2501 nitropack_cache_safemode_status(true);
2502 nitropack_json_and_exit(array(
2503 "type" => "success",
2504 "message" => "Success! Safe mode has been enabled successfully!"
2505 ));
2506 }
2507
2508 nitropack_json_and_exit(array(
2509 "type" => "error",
2510 "message" => "Error! There was an error while enabling safe mode!"
2511 ));
2512 }
2513
2514 function nitropack_disable_safemode() {
2515 if (null !== $nitro = get_nitropack_sdk()) {
2516 try {
2517 $nitro->disableSafeMode();
2518 } catch (\Exception $e) {
2519 }
2520
2521 nitropack_cache_safemode_status(false);
2522 nitropack_json_and_exit(array(
2523 "type" => "success",
2524 "message" => "Success! Safe mode has been disabled successfully!"
2525 ));
2526 }
2527
2528 nitropack_json_and_exit(array(
2529 "type" => "error",
2530 "message" => "Error! There was an error while disabling safe mode!"
2531 ));
2532 }
2533
2534 function nitropack_safemode_status() {
2535 if (null !== $nitro = get_nitropack_sdk()) {
2536 try {
2537 $isEnabled = $nitro->getApi()->isSafeModeEnabled();
2538 } catch (\Exception $e) {
2539 nitropack_cache_safemode_status();
2540 nitropack_json_and_exit(array(
2541 "type" => "error",
2542 "message" => "Error! There was an error while fetching the status of safe mode!"
2543 ));
2544 }
2545
2546 nitropack_cache_safemode_status($isEnabled);
2547 nitropack_json_and_exit(array(
2548 "type" => "success",
2549 "isEnabled" => $isEnabled
2550 ));
2551 }
2552
2553 nitropack_cache_safemode_status();
2554 nitropack_json_and_exit(array(
2555 "type" => "error",
2556 "message" => "Error! There was an error while fetching status of safe mode!"
2557 ));
2558 }
2559
2560 function nitropack_cache_safemode_status($operation = null) {
2561 $sm = "-1";
2562 if (is_bool($operation)) {
2563 $sm = $operation ? '1' : '0';
2564 }
2565 return update_option('nitropack-safeModeStatus', $sm);
2566 }
2567
2568 function nitropack_get_site_config() {
2569 return get_nitropack()->getSiteConfig();
2570 }
2571
2572 function get_nitropack() {
2573 return \NitroPack\WordPress\NitroPack::getInstance();
2574 }
2575
2576 function nitropack_event($event, $nitro = null, $additional_meta_data = null) {
2577 global $wp_version;
2578
2579 try {
2580 $eventUrl = get_nitropack_integration_url("extensionEvent", $nitro);
2581 $domain = !empty($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : "Unknown";
2582
2583 $query_data = array(
2584 'event' => $event,
2585 'platform' => 'WordPress',
2586 'platform_version' => $wp_version,
2587 'nitropack_extension_version' => NITROPACK_VERSION,
2588 'additional_meta_data' => $additional_meta_data ? json_encode($additional_meta_data) : "{}",
2589 'domain' => $domain
2590 );
2591
2592 $client = new NitroPack\HttpClient($eventUrl . '&' . http_build_query($query_data));
2593 $client->doNotDownload = true;
2594 $client->fetch();
2595 } catch (\Exception $e) {}
2596 }
2597
2598 function nitropack_get_wpconfig_path() {
2599 $configFilePath = nitropack_trailingslashit(ABSPATH) . "wp-config.php";
2600 if (!file_exists($configFilePath)) {
2601 $configFilePath = nitropack_trailingslashit(dirname(ABSPATH)) . "wp-config.php";
2602 $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.
2603 if (!file_exists($configFilePath) || file_exists($settingsFilePath)) {
2604 return false;
2605 }
2606 }
2607
2608 if (!is_writable($configFilePath)) {
2609 return false;
2610 }
2611
2612 return $configFilePath;
2613 }
2614
2615 function nitropack_get_htaccess_path() {
2616 $configFilePath = nitropack_trailingslashit(ABSPATH) . ".htaccess";
2617 if (!file_exists($configFilePath)) {
2618 return false;
2619 }
2620
2621 if (!is_writable($configFilePath)) {
2622 return false;
2623 }
2624
2625 return $configFilePath;
2626 }
2627
2628 function nitropack_detect_hosting() {
2629 if (\NitroPack\Integration\Hosting\Flywheel::detect()) {
2630 return "flywheel";
2631 } else if (\NitroPack\Integration\Hosting\Cloudways::detect()) {
2632 return "cloudways";
2633 } else if (\NitroPack\Integration\Hosting\WPEngine::detect()) {
2634 return "wpengine";
2635 } else if (\NitroPack\Integration\Hosting\SiteGround::detect()) {
2636 return "siteground";
2637 } else if (\NitroPack\Integration\Hosting\GoDaddyWPaaS::detect()) {
2638 return "godaddy_wpaas";
2639 } else if (\NitroPack\Integration\Hosting\GridPane::detect()) {
2640 return "gridpane";
2641 } else if (\NitroPack\Integration\Hosting\Kinsta::detect()) {
2642 return "kinsta";
2643 } else if (\NitroPack\Integration\Hosting\Closte::detect()) {
2644 return "closte";
2645 } else if (\NitroPack\Integration\Hosting\Pagely::detect()) {
2646 return "pagely";
2647 } else if (\NitroPack\Integration\Hosting\WPX::detect()) {
2648 return "wpx";
2649 } else if (\NitroPack\Integration\Hosting\Vimexx::detect()) {
2650 return "vimexx";
2651 } else if (\NitroPack\Integration\Hosting\Pressable::detect()) {
2652 return "pressable";
2653 } else if (\NitroPack\Integration\Hosting\RocketNet::detect()) {
2654 return "rocketnet";
2655 } else if (\NitroPack\Integration\Hosting\Savvii::detect()) {
2656 return "savvii";
2657 } else if (\NitroPack\Integration\Hosting\DreamHost::detect()) {
2658 return "dreamhost";
2659 } else {
2660 return "unknown";
2661 }
2662 }
2663
2664 function nitropack_removeCacheBustParam($content) {
2665 $content = preg_replace("/(\?|%26|&#0?38;|&#x0?26;|&(amp;)?)ignorenitro(%3D|=)[a-fA-F0-9]{32}(?!%26|&#0?38;|&#x0?26;|&(amp;)?)\/?/mu", "", $content);
2666 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);
2667 }
2668
2669 function nitropack_handle_request($servedFrom = "unknown") {
2670 global $np_integrationSetupEvent;
2671
2672 if (isset($_GET["ignorenitro"])) {
2673 unset($_GET["ignorenitro"]);
2674 }
2675
2676 if (defined("NITROPACK_STRIP_IGNORENITRO") && NITROPACK_STRIP_IGNORENITRO && $_SERVER['REQUEST_URI'] != '') {
2677 $_SERVER['REQUEST_URI'] = nitropack_removeCacheBustParam($_SERVER['REQUEST_URI']);
2678 }
2679
2680 nitropack_header('Cache-Control: no-cache');
2681 do_action("nitropack_early_cache_headers"); // Overrides the Cache-Control header on supported platforms
2682 $isManageWpRequest = !empty($_GET["mwprid"]);
2683 $isWpCli = nitropack_is_wp_cli();
2684
2685 if ( file_exists(NITROPACK_CONFIG_FILE) && !empty($_SERVER["HTTP_HOST"]) && !empty($_SERVER["REQUEST_URI"]) && !$isManageWpRequest && !$isWpCli ) {
2686 try {
2687 $siteConfig = nitropack_get_site_config();
2688 if ( $siteConfig && null !== $nitro = get_nitropack_sdk($siteConfig["siteId"], $siteConfig["siteSecret"]) ) {
2689 if (is_valid_nitropack_webhook()) {
2690 nitropack_handle_webhook();
2691 } else if (is_valid_nitropack_beacon()) {
2692 nitropack_handle_beacon();
2693 } else if (is_valid_nitropack_heartbeat()) {
2694 nitropack_handle_heartbeat();
2695 } else {
2696 $GLOBALS["NitroPack.instance"] = $nitro;
2697
2698 if (nitropack_passes_cookie_requirements() || (nitropack_is_ajax() && !empty($_COOKIE["nitroCachedPage"])) ) {
2699 // Check whether the current URL is cacheable
2700 // 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.
2701 // If we are not checking the referer, the AJAX requests on these pages can fail.
2702 $urlToCheck = nitropack_is_ajax() && !empty($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : $nitro->getUrl();
2703 if ($nitro->isAllowedUrl($urlToCheck)) {
2704 add_filter( 'nonce_life', 'nitropack_extend_nonce_life' );
2705 }
2706 }
2707
2708 if (nitropack_passes_cookie_requirements() && apply_filters("nitropack_can_serve_cache", true)) {
2709 if ($nitro->isCacheAllowed()) {
2710 if (!nitropack_is_ajax()) {
2711 do_action("nitropack_cacheable_cache_headers");
2712 }
2713
2714 if (!empty($siteConfig["compression"])) {
2715 $nitro->enableCompression();
2716 }
2717
2718 if ($nitro->hasLocalCache()) {
2719 // TODO: Make this work so we can provide the reverse proxies with this information $remainingTtl = $nitr->pageCache->getRemainingTtl();
2720 do_action("nitropack_cachehit_cache_headers"); // TODO: Pass the remaining TTL here
2721 $cacheControlOverride = defined("NITROPACK_CACHE_CONTROL_OVERRIDE") ? NITROPACK_CACHE_CONTROL_OVERRIDE : NULL;
2722 if ($cacheControlOverride) {
2723 nitropack_header('Cache-Control: ' . $cacheControlOverride);
2724 }
2725
2726 nitropack_header('X-Nitro-Cache: HIT');
2727 nitropack_header('X-Nitro-Cache-From: ' . $servedFrom);
2728 $nitro->pageCache->readfile();
2729 exit;
2730 } else {
2731 // We need the following if..else block to handle bot requests which will not be firing our beacon
2732 if (nitropack_is_warmup_request()) {
2733 $nitro->hasRemoteCache("default"); // Only ping the API letting our service know that this page must be cached.
2734 exit; // No need to continue handling this request. The response is not important.
2735 } else if (nitropack_is_lighthouse_request() || nitropack_is_gtmetrix_request() || nitropack_is_pingdom_request()) {
2736 $nitro->hasRemoteCache("default"); // Ping the API letting our service know that this page must be cached.
2737 }
2738
2739 $nitro->pageCache->useInvalidated(true);
2740 if ($nitro->hasLocalCache()) {
2741 nitropack_header('X-Nitro-Cache: STALE');
2742 nitropack_header('X-Nitro-Cache-From: ' . $servedFrom);
2743 $nitro->pageCache->readfile();
2744 exit;
2745 } else {
2746 $nitro->pageCache->useInvalidated(false);
2747 }
2748 }
2749 }
2750 }
2751 }
2752 }
2753 } catch (\Exception $e) {
2754 // Do nothing, cache serving will be handled by nitropack_init
2755 }
2756 }
2757 }
2758
2759 function nitropack_is_dropin_cache_allowed() {
2760 $siteConfig = nitropack_get_site_config();
2761 return $siteConfig && empty($siteConfig["isEzoicActive"]);
2762 }
2763
2764 function nitropack_admin_bar_menu($wp_admin_bar){
2765 if (nitropack_is_amp_page()) return;
2766
2767
2768 $nitropackPluginNotices = nitropack_plugin_notices();
2769
2770 if($nitropackPluginNotices['error']){
2771 $pluginStatus = 'error';
2772 } else if ($nitropackPluginNotices['warning']){
2773 $pluginStatus = 'warning';
2774 } else {
2775 $pluginStatus = 'ok';
2776 }
2777
2778 if (!get_nitropack()->isConnected()) {
2779 $node = array(
2780 'id' => 'nitropack-top-menu',
2781 'title' => '&nbsp;&nbsp;<i style="" class="fa fa-circle nitro nitro-status nitro-status-error" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack is disconnected',
2782 'href' => admin_url( 'options-general.php?page=nitropack' ),
2783 'meta' => array(
2784 'class' => 'custom-node-class'
2785 )
2786 );
2787
2788 $wp_admin_bar->add_node(
2789 array(
2790 'parent' => 'nitropack-top-menu',
2791 'id' => 'optimizations-plugin-status',
2792 'title' => 'Connect NitroPack&nbsp;&nbsp;',
2793 'href' => admin_url( 'options-general.php?page=nitropack' ),
2794 'meta' => array(
2795 'class' => 'nitropack-plugin-status',
2796 )
2797 )
2798 );
2799 } else {
2800 $node = array(
2801 'id' => 'nitropack-top-menu',
2802 'title' => '&nbsp;&nbsp;<i style="" class="fa fa-circle nitro nitro-status nitro-status-'.$pluginStatus.'" aria-hidden="true"></i>&nbsp;&nbsp;NitroPack',
2803 'href' => admin_url( 'options-general.php?page=nitropack' ),
2804 'meta' => array(
2805 'class' => 'custom-node-class'
2806 )
2807 );
2808
2809 if(!is_admin()) { // menu otions available when browsing front-end pages
2810 $wp_admin_bar->add_node(
2811 array(
2812 'parent' => 'nitropack-top-menu',
2813 'id' => 'optimizations-invalidate-cache',
2814 'title' => 'Invalidate Cache for this page&nbsp;&nbsp;',
2815 'href' => "#",
2816 'meta' => array(
2817 'class' => 'nitropack-invalidate-cache',
2818 )
2819 )
2820 );
2821
2822 $wp_admin_bar->add_node(
2823 array(
2824 'parent' => 'nitropack-top-menu',
2825 'id' => 'optimizations-purge-cache',
2826 'title' => 'Purge Cache for this page&nbsp;&nbsp;',
2827 'href' => "#",
2828 'meta' => array(
2829 'class' => 'nitropack-purge-cache',
2830 )
2831 )
2832 );
2833 }
2834
2835 if ($pluginStatus != "ok") {
2836 $numberOfIssues = count($nitropackPluginNotices['error']) + count($nitropackPluginNotices['warning']);
2837 $wp_admin_bar->add_node(
2838 array(
2839 'parent' => 'nitropack-top-menu',
2840 'id' => 'optimizations-plugin-status',
2841 'title' => 'Issues&nbsp;&nbsp;<span style="color:#fff;background-color:#ca4a1f;border-radius:11px;padding: 2px 7px">' . $numberOfIssues . '</span>',
2842 'href' => admin_url( 'options-general.php?page=nitropack' ),
2843 'meta' => array(
2844 'class' => 'nitropack-plugin-status',
2845 )
2846 )
2847 );
2848 }
2849
2850 $notificationCount = count(get_nitropack()->Notifications->get('system'));
2851 if ($notificationCount) {
2852 $node['title'] .= '&nbsp;&nbsp;<span style="color:#fff;background-color:#72aee6;border-radius:11px;padding: 2px 7px">' . $notificationCount . '</span>';
2853 $wp_admin_bar->add_node(
2854 array(
2855 'parent' => 'nitropack-top-menu',
2856 'id' => 'nitropack-notifications',
2857 'title' => 'Notifications&nbsp;&nbsp;<span style="color:#fff;background-color:#72aee6;border-radius:11px;padding: 2px 7px">' . $notificationCount . '</span>',
2858 'href' => admin_url( 'options-general.php?page=nitropack' ),
2859 'meta' => array(
2860 'class' => 'nitropack-notifications',
2861 )
2862 )
2863 );
2864 }
2865 }
2866
2867 $wp_admin_bar->add_node($node);
2868 }
2869
2870 function nitropack_admin_bar_script($hook) {
2871 if (!nitropack_is_amp_page()) {
2872 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);
2873 wp_localize_script( 'nitropack_admin_bar_menu_script', 'frontendajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' )));
2874 }
2875 }
2876
2877 function nitropack_enqueue_load_fa() {
2878 if (!nitropack_is_amp_page()) {
2879 wp_enqueue_style( 'load-fa', plugin_dir_url(__FILE__) . 'view/stylesheet/fontawesome/font-awesome.min.css?np_v=' . NITROPACK_VERSION);
2880 }
2881 }
2882
2883 function enqueue_nitropack_admin_bar_menu_stylesheet() {
2884 if (!nitropack_is_amp_page()) {
2885 wp_enqueue_style( 'nitropack_admin_bar_menu_stylesheet', plugin_dir_url(__FILE__) . 'view/stylesheet/admin_bar_menu.css?np_v=' . NITROPACK_VERSION);
2886 }
2887 }
2888
2889 function nitropack_cookiepath() {
2890 $siteConfig = nitropack_get_site_config();
2891 $homeUrl = $siteConfig && !empty($siteConfig["home_url"]) ? $siteConfig["home_url"] : get_home_url();
2892 $url = new \NitroPack\Url($homeUrl);
2893 return $url ? $url->getPath() : "/";
2894 }
2895
2896 function nitropack_setcookie($name, $value, $expires = NULL, $options = []) {
2897 if (headers_sent()) return;
2898 $cookie_options = '';
2899 $cookie_path = nitropack_cookiepath();
2900
2901 if ($expires && is_numeric($expires)) {
2902 $options["Expires"] = date("D, d M Y H:i:s", (int)$expires) . ' GMT';
2903 }
2904
2905 if (empty($options["SameSite"])) {
2906 $options["SameSite"] = "Lax";
2907 }
2908
2909 foreach ($options as $optName => $optValue) {
2910 $cookie_options .= "$optName=$optValue; ";
2911 }
2912 nitropack_header("set-cookie: $name=$value; Path=$cookie_path; " . $cookie_options, false);
2913 }
2914
2915 function nitropack_header($header, $replace = true, $response_code = 0) {
2916 if (!nitropack_is_wp_cron() && !nitropack_is_wp_cli()) {
2917 header($header, $replace, $response_code);
2918 }
2919 }
2920
2921
2922 function nitropack_upgrade_handler($entity) {
2923 $np = 'nitropack/main.php';
2924 $trigger = $entity;
2925 if ($entity instanceof Plugin_Upgrader) {
2926 $trigger = $entity->plugin_info();
2927 if (!is_plugin_active($trigger)) {
2928 return;
2929 }
2930 }
2931
2932 if ($entity instanceof Theme_Upgrader) {
2933 if ($entity->theme_info()->Name === wp_get_theme()->Name) {
2934 nitropack_theme_handler('Theme updated');
2935 }
2936 return;
2937 }
2938
2939 if ($trigger !== $np) {
2940 $cookie_expires = date("D, d M Y H:i:s",time() + 600) . ' GMT';
2941 nitropack_setcookie('nitropack_apwarning', "1", time() + 600);
2942 }
2943 }
2944
2945 function nitropack_plugin_notices() {
2946 static $npPluginNotices = NULL;
2947
2948 if ($npPluginNotices !== NULL) {
2949 return $npPluginNotices;
2950 }
2951
2952 $errors = [];
2953 $warnings = [];
2954 $infos = [];
2955
2956 // Add conficting plugins errors
2957 $conflictingPlugins = nitropack_get_conflicting_plugins();
2958 foreach ($conflictingPlugins as $clashingPlugin) {
2959 $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);
2960 }
2961
2962 // Add residual cache notices if found
2963 $residualCachePlugins = \NitroPack\Integration\Plugin\RC::detectThirdPartyCaches();
2964 foreach ($residualCachePlugins as $rcpName) {
2965 $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);
2966 }
2967
2968 // Add plugins state notices
2969 if (isset($_COOKIE['nitropack_apwarning'])) {
2970 $cookie_path = nitropack_cookiepath();
2971 $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>";
2972 }
2973
2974 $nitropackIsConnected = get_nitropack()->isConnected();
2975
2976 if ($nitropackIsConnected) {
2977 if (nitropack_is_advanced_cache_allowed()) {
2978 if (!nitropack_has_advanced_cache()) {
2979 $advancedCacheFile = nitropack_trailingslashit(WP_CONTENT_DIR) . 'advanced-cache.php';
2980 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 :(
2981 if (nitropack_install_advanced_cache()) {
2982 $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.";
2983 } else {
2984 if (!nitropack_is_conflicting_plugin_active()) {
2985 $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.";
2986 }
2987 }
2988 }
2989 } else {
2990 if (!defined("NITROPACK_ADVANCED_CACHE_VERSION") || NITROPACK_VERSION != NITROPACK_ADVANCED_CACHE_VERSION) {
2991 if (!nitropack_install_advanced_cache()) {
2992 if (nitropack_is_conflicting_plugin_active()) {
2993 $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.";
2994 } else {
2995 $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.";
2996 }
2997 }
2998 }
2999 }
3000 } else {
3001 if (nitropack_has_advanced_cache()) {
3002 nitropack_uninstall_advanced_cache();
3003 }
3004 }
3005
3006 if ( (!defined("WP_CACHE") || !WP_CACHE) ) {
3007 if (\NitroPack\Integration\Hosting\Flywheel::detect()) { // Flywheel: This is configured throught the FW control panel
3008 $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>.";
3009 } else if (!nitropack_set_wp_cache_const(true)) {
3010 $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.";
3011 }
3012 }
3013
3014 if ( apply_filters('nitropack_needs_htaccess_changes', false) ) {
3015 if (!nitropack_set_htaccess_rules(true)) {
3016 $warnings[] = "Unable to configure LiteSpeed specific rules for maximum performance. Please make sure your .htaccess file is writable or contact support.";
3017 }
3018 }
3019
3020 if ( !get_nitropack()->dataDirExists() && !get_nitropack()->initDataDir()) {
3021 $errors[] = "The NitroPack data directory cannot be created. Please make sure that the /wp-content/ directory is writable and refresh this page.";
3022 return [
3023 'error' => $errors,
3024 'warning' => $warnings,
3025 'info' => $infos
3026 ];
3027 }
3028
3029 $siteId = esc_attr( get_option('nitropack-siteId') );
3030 $siteSecret = esc_attr( get_option('nitropack-siteSecret') );
3031 $webhookToken = esc_attr( get_option('nitropack-webhookToken') );
3032 $blogId = get_current_blog_id();
3033 $isConfigOutdated = !nitropack_is_config_up_to_date();
3034 $siteConfig = nitropack_get_site_config();
3035
3036 if ( !get_nitropack()->Config->exists() && !get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3037 $errors[] = "The NitroPack static config file cannot be created. Please make sure that the /wp-content/nitropack/ directory is writable and refresh this page.";
3038 } else if ( $isConfigOutdated ) {
3039 if (!get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3040 $errors[] = "The NitroPack static config file cannot be updated. Please make sure that the /wp-content/nitropack/ directory is writable and refresh this page.";
3041 } else {
3042 if (!$siteConfig) {
3043 nitropack_event("update");
3044 } else {
3045 $prevVersion = !empty($siteConfig["pluginVersion"]) ? $siteConfig["pluginVersion"] : "1.1.4 or older";
3046 nitropack_event("update", null, array("previous_version" => $prevVersion));
3047
3048 if (empty($siteConfig["pluginVersion"]) || version_compare($siteConfig["pluginVersion"], "1.3", "<")) {
3049 if (!headers_sent()) {
3050 setcookie("nitropack_upgrade_to_1_3_notice", 1, time() + 3600);
3051 }
3052 $_COOKIE["nitropack_upgrade_to_1_3_notice"] = 1;
3053 }
3054 }
3055 }
3056
3057 try {
3058 nitropack_setup_webhooks(get_nitropack_sdk(), $webhookToken);
3059 } catch (\NitroPack\SDK\WebhookException $e) {
3060 $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.";
3061 }
3062 } else {
3063 $optionsMistmatch = false;
3064 if (array_key_exists('options_cache', $siteConfig)) {
3065 foreach (\NitroPack\WordPress\NitroPack::$optionsToCache as $opt) {
3066 if (is_array($opt)) {
3067 foreach ($opt as $option => $suboption) {
3068 if (empty($siteConfig['options_cache'][$option][$suboption]) || $siteConfig['options_cache'][$option][$suboption] != get_option($option)[$suboption]) {
3069 $optionsMistmatch = true;
3070 break 2;
3071 }
3072 }
3073 } else {
3074 if (!array_key_exists($opt, $siteConfig['options_cache']) || $siteConfig['options_cache'][$opt] != get_option($opt)) {
3075 $optionsMistmatch = true;
3076 break;
3077 }
3078 }
3079 }
3080 } else {
3081 $optionsMistmatch = true;
3082 }
3083
3084 if (
3085 $optionsMistmatch ||
3086 (!array_key_exists("isEzoicActive", $siteConfig) || $siteConfig["isEzoicActive"] !== \NitroPack\Integration\Plugin\Ezoic::isActive()) ||
3087 (!array_key_exists("isLateIntegrationInitRequired", $siteConfig) || $siteConfig["isLateIntegrationInitRequired"] !== nitropack_is_late_integration_init_required()) ||
3088 (!array_key_exists("isDlmActive", $siteConfig) || $siteConfig["isDlmActive"] !== \NitroPack\Integration\Plugin\DownloadManager::isActive()) ||
3089 (!array_key_exists("isAeliaCurrencySwitcherActive", $siteConfig) || $siteConfig["isAeliaCurrencySwitcherActive"] !== \NitroPack\Integration\Plugin\AeliaCurrencySwitcher::isActive()) ||
3090 (!array_key_exists("isWoocommerceActive", $siteConfig) || $siteConfig["isWoocommerceActive"] !== \NitroPack\Integration\Plugin\Woocommerce::isActive()) ||
3091 (!array_key_exists("isWoocommerceCacheHandlerActive", $siteConfig) || $siteConfig["isWoocommerceCacheHandlerActive"] !== \NitroPack\Integration\Plugin\WoocommerceCacheHandler::isActive())
3092 ) {
3093 if (!get_nitropack()->updateCurrentBlogConfig($siteId, $siteSecret, $blogId)) {
3094 $errors[] = "The NitroPack static config file cannot be updated. Please make sure that the /wp-content/nitropack/ directory is writable and refresh this page.";
3095 }
3096 }
3097
3098 if (empty($_COOKIE["nitropack_webhook_sync"])) {
3099 if (null !== $nitro = get_nitropack_sdk() ) {
3100 try {
3101 if (!headers_sent()) {
3102 nitropack_setcookie("nitropack_webhook_sync", "1", time() + 300); // Do these checks in 5 minute intervals.
3103 }
3104 $configWebhook = $nitro->getApi()->getWebhook("config");
3105 if (!empty($configWebhook)) {
3106 $query = parse_url($configWebhook, PHP_URL_QUERY);
3107 if ($query) {
3108 parse_str($query, $webhookParams);
3109 if (empty($webhookParams["token"]) || $webhookParams["token"] != $webhookToken) {
3110 $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>";
3111 }
3112 }
3113 }
3114 } catch (\Exception $e) {
3115 //Do nothing
3116 }
3117 }
3118 }
3119 }
3120
3121 if (!empty($_COOKIE["nitropack_upgrade_to_1_3_notice"])) {
3122 $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>";
3123 }
3124 }
3125
3126 $npPluginNotices = [
3127 'error' => $errors,
3128 'warning' => $warnings,
3129 'info' => $infos
3130 ];
3131
3132 return $npPluginNotices;
3133 }
3134
3135 /**
3136 * Caches some options in the config so that we can access them before get_option() is defined
3137 * which is in advanced_cache.php, functions.php and Integrations
3138 */
3139 function nitropack_updated_option($option, $oldValue, $value) {
3140 $neededOptions = \NitroPack\WordPress\NitroPack::$optionsToCache;
3141 if (!in_array($option, $neededOptions)) return;
3142
3143 $np = get_nitropack();
3144 $siteConfig = $np->Config->get();
3145
3146 if (function_exists('get_home_url')) {
3147 $configKey = \NitroPack\WordPress\NitroPack::getConfigKey();
3148 $siteConfig[$configKey]['options_cache'][$option] = $value;
3149 $np->Config->set($siteConfig);
3150 }
3151 }
3152
3153 function nitropack_is_late_integration_init_required() {
3154 return \NitroPack\Integration\Plugin\NginxHelper::isActive() || \NitroPack\Integration\Plugin\Cloudflare::isApoActive();
3155 }
3156
3157 function nitropack_display_admin_notices() {
3158 $noticesArray = nitropack_plugin_notices();
3159 foreach($noticesArray as $type => $notices){
3160 switch($type) {
3161 case "error":
3162 $alertType = "danger";
3163 break;
3164 case "warning":
3165 $alertType = "warning";
3166 break;
3167 case "info":
3168 $alertType = "info";
3169 break;
3170 }
3171 foreach($notices as $notice){
3172 ?>
3173 <div class="alert alert-<?php echo $alertType; ?>">
3174 <?php echo _e($notice); ?>
3175 </div>
3176 <?php
3177 }
3178 }
3179 }
3180
3181 function nitropack_offer_safemode() {
3182 global $pagenow;
3183 if ($pagenow == 'plugins.php') {
3184 $smStatus = get_option('nitropack-safeModeStatus', "-1");
3185 if ($smStatus === "0") {
3186 add_action('admin_enqueue_scripts', function() {
3187 wp_enqueue_script( 'np_safemode', plugin_dir_url( __FILE__ ). 'view/javascript/np_safemode.js', array('jquery'));
3188 wp_enqueue_style('np_safemode', plugin_dir_url( __FILE__ ) . 'view/stylesheet/np_safemode.css');
3189 });
3190 add_action('admin_footer', function(){require_once NITROPACK_PLUGIN_DIR . 'view/safemode.tpl';});
3191 }
3192 }
3193 }
3194
3195 // Init integration action handlers
3196 $integration = NitroPack\Integration::getInstance();
3197 $integration->init();
3198