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