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