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