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