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