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