PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.19.0
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.19.0
1.19.8 1.19.7 1.19.6 1.19.5 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.11.0 1.12.0 1.13.0 1.14.0 1.15.0 1.15.1 1.15.2 1.15.3 1.16.0 1.16.1 1.16.2 1.16.3 1.16.4 1.16.5 1.16.6 1.16.7 1.16.8 1.17.0 1.17.6 1.17.7 1.17.8 1.17.9 1.18.0 1.18.1 1.18.2 1.18.3 1.18.4 1.18.5 1.18.6 1.18.7 1.18.8 1.18.9 1.19.0 1.19.1 1.19.2 1.19.3 1.19.4 1.3.19 1.3.20 1.4.0 1.4.1 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.14 1.5.15 1.5.16 1.5.17 1.5.18 1.5.19 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.8.0 1.8.1 1.8.3 1.9.0 1.9.1 1.9.2
nitropack / classes / WordPress / Notifications / Notifications.php
nitropack / classes / WordPress / Notifications Last commit date
AppNotifications.php 1 year ago Notifications.php 4 months ago
Notifications.php
754 lines
1 <?php
2 namespace NitroPack\WordPress\Notifications;
3
4 use NitroPack\WordPress\Settings\TestMode;
5 /*
6 * Class Notifications
7 *
8 * This class handles the notifications for the NitroPack plugin in WordPress.
9 *
10 * @package NitroPack\WordPress\Notifications
11 */
12 class Notifications {
13 private static $instance = NULL;
14 public function __construct() {
15
16 add_action( 'admin_init', [ $this, 'move_existing_notices' ] );
17 add_action( 'admin_notices', [ $this, 'nitropack_admin_notices' ] );
18 /* Using 'init' because it fixes issue when get_home_url() in updateCurrentBlogConfig() is not found in multisites */
19 add_action( 'init', function () {
20 add_action( 'plugins_loaded', [ $this, 'nitropack_plugin_notices' ] );
21 } );
22 //ajax
23 add_action( 'wp_ajax_nitropack_safemode_notification', [ $this, 'nitropack_safemode_notification' ] );
24 add_action( 'wp_ajax_nitropack_dismiss_permanently_notification', [ $this, 'nitropack_dismiss_permanently_notification' ] );
25 add_action( 'wp_ajax_nitropack_dismiss_notification_by_transient', [ $this, 'nitropack_dismiss_notification_by_transient' ] );
26 add_action( 'wp_ajax_nitropack_conflict_plugin_deactivate', [ $this, 'nitropack_conflict_plugin_deactivate' ] );
27
28 }
29 public static function getInstance() {
30 if ( ! self::$instance ) {
31 self::$instance = new Notifications();
32 }
33
34 return self::$instance;
35 }
36
37 /**
38 * Displays general admin notices for the NitroPack plugin in WordPress dashboard.
39 *
40 * @return void
41 */
42 public function nitropack_admin_notices() {
43 $components = new \NitroPack\WordPress\Settings\Components;
44 if ( defined( 'NITROPACK_DATA_DIR_WARNING' ) ) {
45 $components->render_notification( NITROPACK_DATA_DIR_WARNING, 'warning', 'Unable to initialize cache dir' );
46 }
47
48 if ( defined( 'NITROPACK_PLUGIN_DATA_DIR_WARNING' ) ) {
49 $components->render_notification( NITROPACK_PLUGIN_DATA_DIR_WARNING, 'warning', 'Unable to initialize plugin data dir' );
50 }
51
52 if ( ! empty( $_COOKIE["nitropack_after_activate_notice"] ) && !get_nitropack()->isConnected() ) {
53 $components->render_notification( "Please complete the setup process to activate optimizations.",
54 'promo',
55 esc_html__( 'Connect your website to enable NitroPack\'s optimizations', 'nitropack' ),
56 '<a href="' . admin_url( 'admin.php?page=nitropack' ) . '" class="btn btn-primary">' . esc_html__( 'Connect your website', 'nitropack' ) . '</a>' );
57 }
58
59 $this->render_app_notifications();
60 $this->nitropack_print_hosting_notice();
61 $this->nitropack_print_woocommerce_notice();
62 }
63 /**
64 * Display NitroPack plugin notices in the WordPress admin area.
65 *
66 * This function is responsible for showing various notifications related to the NitroPack plugin.
67 *
68 * @return null|array
69 */
70 public function nitropack_plugin_notices() {
71 if ( ! $this->pass_notification_capabilities() )
72 return;
73
74 static $npPluginNotices = NULL;
75
76 if ( $npPluginNotices !== NULL ) {
77 return $npPluginNotices;
78 }
79
80 $errors = [];
81 $warnings = [];
82 $infos = [];
83
84 /* Sets a warning if there are any conflicting plugins - mostly caching plugins. */
85 $conflictingPlugins = \NitroPack\WordPress\ConflictingPlugins::getInstance();
86 $conflictingPlugins_list = $conflictingPlugins->nitropack_get_conflicting_plugins();
87
88 if ( $conflictingPlugins_list ) {
89
90 foreach ( $conflictingPlugins_list as $clashingPlugin ) {
91 $warnings[] = array(
92 'title' => sprintf( "%s is active and may conflict with NitroPack", $clashingPlugin['name'] ),
93 'msg' => esc_html__( "Some of its features overlap with NitroPack's optimizations which could lead to issues. We recommend disabling it to avoid potential conflicts.", 'nitropack' ),
94 'actions' => '<a class="btn btn-secondary modal-plugin-deactivate" data-plugin-path="'.$clashingPlugin['plugin'].'" data-plugin-name="'.$clashingPlugin['name'].'" title="Disable ' . $clashingPlugin['name'] . ' ">' . sprintf( "Deactivate %s", $clashingPlugin['name'] ) . '</a>',
95 'classes' => [ 'conflicting-plugins plugin-' . sanitize_title( $clashingPlugin['name'] ) ],
96 );
97 }
98
99 }
100 /* Add residual cache notices if found */
101 $residualCachePlugins = \NitroPack\Integration\Plugin\RC::detectThirdPartyCaches();
102 foreach ( $residualCachePlugins as $rcpName ) {
103 $warnings[] = array(
104 'title' => esc_html__( "Residual cache files", 'nitropack' ),
105 /* translators: %s: Name of the plugin that left residual cache files */
106 'msg' => sprintf( esc_html__( 'We found residual cache files from %s. These files can interfere with the caching process and must be deleted.', 'nitropack' ), $rcpName, $rcpName ),
107 'actions' => '<a class="btn btn-warning" nitropack-rc-data="' . $rcpName . '">' . esc_html__( 'Delete now', 'nitropack' ) . '</a>',
108 );
109 }
110 /* Sets a warning if there is any activity in the plugins such as new activations, updates, or deletions. */
111 if ( isset( $_COOKIE['nitropack_apwarning'] ) ) {
112 $cookie_path = nitropack_cookiepath();
113 $warnings[] = array(
114 'title' => esc_html__( "Plugins activity", 'nitropack' ),
115 'msg' => esc_html__( 'It seems plugins have been activated, deactivated or updated. It is recommended that you purge the cache to reflect the latest changes.', 'nitropack' ),
116 'actions' => "<a class=\"btn btn-secondary\" href=\"javascript:void(0);\" id=\"np-onstate-cache-purge\" onclick=\"document.cookie = 'nitropack_apwarning=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=$cookie_path';window.location.reload();\">" . esc_html__( 'Dismiss', 'nitropack' ) . "</a>",
117 'classes' => [ 'plugins-state' ],
118 );
119 }
120
121 /* Sets a warning if the Test Mode is enabled. */
122 if ( TestMode::getInstance()->is_test_mode_enabled() ) {
123 $safeModeMessage = __( 'Visitors are accessing your unoptimized pages. Make sure to disable it once you are done testing.', 'nitropack' );
124 if ( get_nitropack()->getDistribution() == "oneclick" ) {
125 $safeModeMessage = apply_filters( "nitropack_oneclick_safemode_message", $safeModeMessage );
126 }
127
128 $warnings[] = array(
129 'title' => esc_html__( "Test Mode Enabled", 'nitropack' ),
130 'msg' => $safeModeMessage,
131 'classes' => [ 'test-mode' ],
132 );
133 }
134
135 $nitropackIsConnected = get_nitropack()->isConnected();
136
137 if ( $nitropackIsConnected ) {
138 if ( nitropack_is_advanced_cache_allowed() ) {
139 $notification_title = esc_html__( "File advanced-cache.php cannot be created", 'nitropack' );
140 $notification_class = [ 'advanced-cache' ];
141
142 if ( ! nitropack_has_advanced_cache() ) {
143
144 $advancedCacheFile = nitropack_trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php';
145 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 :(
146
147 if ( nitropack_install_advanced_cache() ) {
148 if ( ! \NitroPack\Integration\Hosting\WPEngine::detect() ) { // The advanced-cache.php file in WP Engine is reset fairly often and we don't want to show the notice every time. This is an info we can skip in this case.
149
150 /* Sets an info notifications if the advanced-cache.php file was re-installed. */
151 $infos[] = array(
152 'title' => esc_html__( 'File advanced-cache.php re-installed', 'nitropack' ),
153 'msg' => esc_html__( '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.', 'nitropack' ),
154 'actions' => '<a href="' . admin_url() . 'plugins.php" target="_blank" class="btn btn-secondary">' . esc_html__( 'Plugins page', 'nitropack' ) . '</a>',
155 'classes' => $notification_class,
156 );
157 }
158 } else {
159 if ( ! $conflictingPlugins->nitropack_is_conflicting_plugin_active() ) {
160
161 /* Sets an error notifications for not being able to create the advanced-cache.php file due to conflicting caching plugins */
162
163 $errors[] = array(
164 'title' => $notification_title,
165 'msg' => __( 'Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack' ),
166 'classes' => $notification_class,
167 );
168 }
169 }
170 }
171 } else {
172 if ( ! defined( "NITROPACK_ADVANCED_CACHE_VERSION" ) || NITROPACK_VERSION != NITROPACK_ADVANCED_CACHE_VERSION ) {
173 if ( ! nitropack_install_advanced_cache() ) {
174 if ( $conflictingPlugins->nitropack_is_conflicting_plugin_active() ) {
175 $errors[] = array(
176 'title' => $notification_title,
177 'msg' => esc_html__( 'The file /wp-content/advanced-cache.php cannot be created because a conflicting plugin is active. Please make sure to disable all conflicting plugins.', 'nitropack' ),
178 'actions' => '<a href="' . admin_url() . 'plugins.php" target="_blank" class="btn btn-primary">Plugins page</a>',
179 'classes' => $notification_class,
180 );
181 } else {
182 $errors[] = array(
183 'title' => $notification_title,
184 'msg' => esc_html__( 'The file /wp-content/advanced-cache.php cannot be created. Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack' ),
185 'classes' => $notification_class,
186 );
187 }
188 }
189 }
190 }
191 } else {
192 if ( nitropack_has_advanced_cache() ) {
193 nitropack_uninstall_advanced_cache();
194 }
195 }
196
197 if ( ( ! defined( "WP_CACHE" ) || ! WP_CACHE ) ) {
198 $notification_class = [ 'wp-cache' ];
199 if ( \NitroPack\Integration\Hosting\Flywheel::detect() ) { // Flywheel: This is configured throught the FW control panel
200 $warnings[] = array(
201 'title' => esc_html__( "WP_CACHE not enabled", 'nitropack' ),
202 'msg' => esc_html__( "Please go to your FlyWheel control panel and enable this setting.", 'nitropack' ),
203 'actions' => '<a href="https://getflywheel.com/wordpress-support/how-to-enable-wp_cache/" target="_blank" class="btn btn-primary">View more</a>',
204 'classes' => $notification_class,
205 );
206 } else if ( ! nitropack_set_wp_cache_const( true ) ) {
207 $errors[] = array(
208 'title' => esc_html__( 'Constant WP_CACHE cannot be set', 'nitropack' ),
209 'msg' => esc_html__( 'This can lead to slower cache delivery. Please make sure that the /wp-config.php file is writable and refresh this page.', 'nitropack' ),
210 'classes' => $notification_class,
211 );
212 }
213 }
214
215 if ( apply_filters( 'nitropack_needs_htaccess_changes', false ) ) {
216 if ( ! nitropack_set_htaccess_rules( true ) ) {
217 $warnings[] = array(
218 'title' => esc_html__( "File .htaccess is not writable", 'nitropack' ),
219 'msg' => esc_html__( 'Unable to configure LiteSpeed specific rules for maximum performance. Please make sure your .htaccess file is writable or contact support.', 'nitropack' ),
220 'classes' => [ 'htaccess' ],
221 );
222 }
223 }
224
225 if ( ! get_nitropack()->dataDirExists() && ! get_nitropack()->initDataDir() ) {
226 $errors[] = array(
227 'title' => esc_html__( 'NitroPack data directory cannot be created', 'nitropack' ),
228 'msg' => esc_html__( 'Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack' ),
229 'classes' => [ 'np-data-dir' ],
230 );
231 return [
232 'error' => $errors,
233 'warning' => $warnings,
234 'info' => $infos
235 ];
236 }
237
238 if ( ! get_nitropack()->pluginDataDirExists() && ! get_nitropack()->initPluginDataDir() ) {
239 $errors[] = array(
240 'title' => esc_html__( 'NitroPack plugin data directory cannot be created', 'nitropack' ),
241 'msg' => esc_html__( 'Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack' ),
242
243 'classes' => [ 'np-data-dir' ],
244 );
245 return [
246 'error' => $errors,
247 'warning' => $warnings,
248 'info' => $infos
249 ];
250 }
251
252 $siteConfig = nitropack_get_site_config();
253 $siteId = $siteConfig ? $siteConfig["siteId"] : NULL;
254 $siteSecret = $siteConfig ? $siteConfig["siteSecret"] : NULL;
255 $webhookToken = esc_attr( get_option( 'nitropack-webhookToken' ) );
256 $blogId = get_current_blog_id();
257 $isConfigOutdated = ! nitropack_is_config_up_to_date();
258 if ( ! get_nitropack()->Config->exists() && ! get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId ) ) {
259 $errors[] = array(
260 'title' => esc_html__( "NitroPack static config file cannot be created", 'nitropack' ),
261 'msg' => esc_html__( 'Please make sure that the /wp-content/config-nitropack/ directory is writable and refresh this page.', 'nitropack' ),
262 );
263 } else if ( $isConfigOutdated ) {
264 if ( ! get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId ) ) {
265 $errors[] = array(
266 'title' => esc_html__( "NitroPack static config file cannot be updated", 'nitropack' ),
267 'msg' => esc_html__( 'Please make sure that the /wp-content/config-nitropack/ directory is writable and refresh this page.', 'nitropack' ),
268 );
269 } else {
270
271 if ( ! $siteConfig ) {
272 nitropack_event( "update" );
273 } else {
274 $prevVersion = ! empty( $siteConfig["pluginVersion"] ) ? $siteConfig["pluginVersion"] : "1.1.4 or older";
275 nitropack_event( "update", null, array( "previous_version" => $prevVersion ) );
276 if ( empty( $siteConfig["pluginVersion"] ) || version_compare( $siteConfig["pluginVersion"], "1.4", "<" ) ) {
277 $nitropack_v1_3_notice_id = 'nitropack_upgrade_to_1_3';
278 }
279 }
280 }
281
282 try {
283 nitropack_setup_webhooks( get_nitropack_sdk(), $webhookToken );
284 } catch (\NitroPack\SDK\WebhookException $e) {
285 $warnings[] = array(
286 'title' => esc_html__( "Unable to configure webhooks", 'nitropack' ),
287 'msg' => esc_html__( 'This can impact the stability of the plugin. Please disconnect and connect again in order to retry configuring the webhooks.', 'nitropack' ),
288 );
289 }
290 } else {
291 $optionsMismatch = false;
292 if ( array_key_exists( 'options_cache', $siteConfig ) ) {
293 foreach ( \NitroPack\WordPress\NitroPack::$optionsToCache as $opt ) {
294 if ( is_array( $opt ) ) {
295 foreach ( $opt as $option => $suboption ) {
296 // Handle both nested and flat structures
297 if ( is_array( $suboption ) ) {
298 // Nested structure
299 if ( ! isset( $siteConfig['options_cache'][ $option ] ) || ! is_array( $siteConfig['options_cache'][ $option ] ) ) {
300 $optionsMismatch = true;
301 break 2;
302 }
303 foreach ( $suboption as $subkey => $subvalue ) {
304 if (
305 ! isset( $siteConfig['options_cache'][ $option ][ $subkey ] ) ||
306 $siteConfig['options_cache'][ $option ][ $subkey ] !== get_option( $option )[ $subkey ]
307 ) {
308 $optionsMismatch = true;
309 break 3;
310 }
311 }
312 } else {
313 // Flat structure within the nested loop
314 if (
315 ! isset( $siteConfig['options_cache'][ $option ] ) ||
316 $siteConfig['options_cache'][ $option ] !== get_option( $option )
317 ) {
318 $optionsMismatch = true;
319 break 2;
320 }
321 }
322 }
323 } else {
324 // Flat structure outside the nested loop
325 if (
326 ! isset( $siteConfig['options_cache'][ $opt ] ) ||
327 is_bool( $siteConfig['options_cache'][ $opt ] ) ||
328 $siteConfig['options_cache'][ $opt ] !== get_option( $opt )
329 ) {
330 $optionsMismatch = true;
331 break;
332 }
333 }
334 }
335 } else {
336 $optionsMismatch = true;
337 }
338
339 if (
340 $optionsMismatch ||
341 ( ! array_key_exists( "isEzoicActive", $siteConfig ) || $siteConfig["isEzoicActive"] !== \NitroPack\Integration\Plugin\Ezoic::isActive() ) ||
342 ( ! array_key_exists( "isLateIntegrationInitRequired", $siteConfig ) || $siteConfig["isLateIntegrationInitRequired"] !== nitropack_is_late_integration_init_required() ) ||
343 ( ! array_key_exists( "isDlmActive", $siteConfig ) || $siteConfig["isDlmActive"] !== \NitroPack\Integration\Plugin\DownloadManager::isActive() ) ||
344 ( ! array_key_exists( "isAeliaCurrencySwitcherActive", $siteConfig ) || $siteConfig["isAeliaCurrencySwitcherActive"] !== \NitroPack\Integration\Plugin\AeliaCurrencySwitcher::isActive() ) ||
345 ( ! array_key_exists( "isGeoTargetingWPActive", $siteConfig ) || $siteConfig["isGeoTargetingWPActive"] !== \NitroPack\Integration\Plugin\GeoTargetingWP::isActive() ) ||
346 ( ! array_key_exists( "isWoocommerceActive", $siteConfig ) || $siteConfig["isWoocommerceActive"] !== \NitroPack\Integration\Plugin\WooCommerce::isActive() ) ||
347 ( ! array_key_exists( "isWoocommerceCacheHandlerActive", $siteConfig ) || $siteConfig["isWoocommerceCacheHandlerActive"] !== \NitroPack\Integration\Plugin\WoocommerceCacheHandler::isActive() )
348 ) {
349 if ( ! get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId ) ) {
350 $errors[] = array(
351 'title' => esc_html__( "NitroPack static config file cannot be updated", 'nitropack' ),
352 'msg' => esc_html__( 'Please make sure that the /wp-content/config-nitropack/ directory is writable and refresh this page.', 'nitropack' ),
353 );
354 }
355 }
356
357 if ( empty( $_COOKIE["nitropack_webhook_sync"] ) || ! $siteConfig["webhookToken"] ) {
358 if ( null !== $nitro = get_nitropack_sdk() ) {
359 try {
360 if ( ! headers_sent() ) {
361 nitropack_setcookie( "nitropack_webhook_sync", "1", time() + 300 ); // Do these checks in 5 minute intervals.
362 }
363 $configWebhook = $nitro->getApi()->getWebhook( "config" );
364 if ( ! empty( $configWebhook ) ) {
365 $query = parse_url( $configWebhook, PHP_URL_QUERY );
366 if ( $query ) {
367 parse_str( $query, $webhookParams );
368 if ( empty( $webhookParams["token"] ) || $webhookParams["token"] != $webhookToken ) {
369 $warnings[] = array(
370 'title' => esc_html__( "Connection problems detected", 'nitropack' ),
371 'msg' => esc_html__( 'Most likely you have used the same API credentials to connect another website (e.g. dev or staging). Click to restore the connection to this site.', 'nitropack' ),
372 'actions' => '<a id="nitro-restore-connection-btn" class="btn btn-warning">Restore connection</a>',
373 );
374 }
375 }
376 }
377 } catch (\Exception $e) {
378 //Do nothing
379 }
380 }
381 }
382
383 if ( apply_filters( 'nitropack_should_modify_htaccess', false ) && ( empty( $_SERVER["NitroPackHtaccessVersion"] ) || NITROPACK_VERSION != $_SERVER["NitroPackHtaccessVersion"] ) ) {
384 if ( ! nitropack_set_htaccess_rules( true ) ) {
385 $errors[] = array(
386 'title' => esc_html__( "The .htaccess file cannot be modified", 'nitropack' ),
387 'msg' => esc_html__( 'Please make sure that it is writable and refresh this page.', 'nitropack' ),
388 );
389 }
390 }
391 }
392 if ( isset( $nitropack_v1_3_notice_id ) ) {
393 $warnings[] = array(
394 'title' => esc_html__( "NitroPack upgraded to 1.3", 'nitropack' ),
395 'msg' => esc_html__( '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.', 'nitropack' ),
396 'dismissibleId' => $nitropack_v1_3_notice_id,
397 'dismissBy' => 'option',
398 );
399 }
400
401 if ( \NitroPack\Integration\Plugin\Cloudflare::isApoActive() && ! \NitroPack\Integration\Plugin\Cloudflare::isApoCacheByDeviceTypeEnabled() ) {
402 $warnings[] = array(
403 'title' => esc_html__( "Cache By Device Type is not activate", 'nitropack' ),
404 'msg' => esc_html__( 'It seems Cache By Device Type is not activate with the Cloudflare APO. It is recommended that you enable it for a more optimized experience.', 'nitropack' ),
405 );
406 }
407 }
408
409 $npPluginNotices = [
410 'error' => $errors,
411 'warning' => $warnings,
412 'info' => $infos
413 ];
414
415 return $npPluginNotices;
416 }
417
418 /**
419 * Display admin notices in the NitroPack -> Dashboard plugin page.
420 *
421 * This function checks if the current user has the necessary capabilities to view the notices.
422 * It renders specific notifications related to hosting information, system, compatibilities and notifications coming from the NitroPack app
423 *
424 * @return void
425 */
426 public function nitropack_display_admin_notices() {
427 if ( ! $this->pass_notification_capabilities() )
428 return;
429
430 $noticesArray = $this->nitropack_plugin_notices();
431 $components = new \NitroPack\WordPress\Settings\Components;
432 foreach ( $noticesArray as $type => $notices ) {
433 foreach ( $notices as $notice ) {
434 $components->render_notification( $notice['msg'], $type, $notice['title'], isset( $notice['actions'] ) ? $notice['actions'] : null, isset( $notice['classes'] ) ? $notice['classes'] : null, isset( $notice['dismissibleId'] ) ? $notice['dismissibleId'] : null, isset( $notice['dismissBy'] ) ? $notice['dismissBy'] : null );
435 }
436 }
437 //render app notifications
438 $this->render_app_notifications();
439 }
440
441 /**
442 * Render notifications coming from notifications.json file such as ones from the NitroPack app.
443 *
444 * @return void
445 */
446 public function render_app_notifications() {
447 $components = new \NitroPack\WordPress\Settings\Components();
448 $app_notifications = AppNotifications::getInstance();
449 foreach ( $app_notifications->get( 'system' ) as $notification ) {
450 $msg = $notification['message'];
451 $type = 'info';
452 $title = '';
453
454 if ( ! empty( $notification['type'] ) ) {
455 $type = $notification['type'];
456 }
457 if ( ! empty( $notification['message_details']['title'] ) ) {
458 $title = $notification['message_details']['title'];
459 }
460 if ( ! empty( $notification['message_details']['message'] ) ) {
461 $msg = $notification['message_details']['message'];
462 }
463
464 $components->render_notification( $msg, $type, $title, '', [ 'app-notification' ], $notification['id'], 'transient', $notification );
465 }
466 }
467 /**
468 * Prints a hosting notice for NitroPack.
469 *
470 * @return void
471 */
472 private function nitropack_print_hosting_notice() {
473
474 $hostingNoticeFile = nitropack_get_hosting_notice_file();
475 if ( ! get_nitropack()->isConnected() || file_exists( $hostingNoticeFile ) )
476 return;
477
478 $documentedHostingSetups = array(
479 "flywheel" => array(
480 "name" => "Flywheel",
481 "helpUrl" => "https://getflywheel.com/wordpress-support/how-to-enable-wp_cache/"
482 ),
483 "cloudways" => array(
484 "name" => "Cloudways",
485 "helpUrl" => "https://support.nitropack.io/hc/en-us/articles/360060916674-Cloudways-Hosting-Configuration-for-NitroPack"
486 )
487 );
488
489 $siteConfig = nitropack_get_site_config();
490
491 if ( $siteConfig && ! empty( $siteConfig["hosting"] ) && array_key_exists( $siteConfig["hosting"], $documentedHostingSetups ) ) {
492
493 $hostingInfo = $documentedHostingSetups[ $siteConfig["hosting"] ];
494 $showNotice = true;
495 if ( $siteConfig["hosting"] == "flywheel" && defined( "WP_CACHE" ) && WP_CACHE ) {
496 $showNotice = false;
497 }
498
499 if ( $showNotice ) {
500 $components = new \NitroPack\WordPress\Settings\Components;
501 $components->render_notification( esc_html__( "Please follow the instructions in order to make sure that everything works correctly.", 'nitropack' ), 'info',
502 /* translators: %s: Name of the hosting provider */
503 sprintf( esc_html__( 'It looks like you are hosted on %s', 'nitropack' ), $hostingInfo['name'] ),
504 '<a href="' . $hostingInfo["helpUrl"] . '" target="_blank" class="btn btn-info btn-ghost">' . esc_html__( 'Read Instructions', 'nitropack' ) . '</a>',
505 [ 'hosting-notice' ], 'hosting-' . $siteConfig["hosting"], 'option' );
506 }
507 }
508 }
509 /**
510 * Prints a WooCommerce notice for NitroPack across WordPress admin
511 * @return void
512 */
513 private function nitropack_print_woocommerce_notice() {
514 if ( get_nitropack()->isConnected() ) {
515 if ( class_exists( 'WooCommerce' ) ) {
516 $np_notices = get_option( 'nitropack-dismissed-notices', [] );
517 $woocommerce_notice = in_array( 'WooCommerce', $np_notices, true ) ? true : false;
518
519 if ( ! $woocommerce_notice ) {
520 $components = new \NitroPack\WordPress\Settings\Components;
521 $components->render_notification( __( 'Your <strong>account</strong>, <strong>cart</strong>, and <strong>checkout</strong> pages are automatically excluded from optimization.', 'nitropack' ),
522 'success',
523 esc_html__( 'WooCommerce detected', 'nitropack' ),
524 '<a class="btn btn-secondary" href="' . admin_url( 'admin.php?page=nitropack' ) . '">' . esc_html__( 'Settings', 'nitropack' ) . '</a>',
525 [ 'woocommerce-notice' ],
526 'WooCommerce', 'option' );
527 }
528 }
529 }
530 }
531
532 public function admin_bar_notices_counter() {
533 if ( ! $this->pass_notification_capabilities() )
534 return;
535
536 $notices = $this->nitropack_plugin_notices();
537
538 $numberOfPluginErrors = 0;
539 $numberOfPluginWarnings = 0;
540 $notificationCount = 0;
541 foreach ( array( "warning", "error", "info" ) as $type ) {
542
543 foreach ( $notices[ $type ] as $notice ) {
544
545
546 switch ( $type ) {
547 case "error":
548 $numberOfPluginErrors++;
549 break;
550 case "warning":
551 $numberOfPluginWarnings++;
552 break;
553 case "info":
554 $notificationCount++;
555 break;
556 }
557
558
559 }
560 }
561
562 /* Notifications from the app */
563 $app_notifications = AppNotifications::getInstance();
564 foreach ( $app_notifications->get( 'system' ) as $notification ) {
565
566 if ( ! empty( $notification['id'] ) ) {
567
568 /* Don't count if dismissed by transient and the time has passed */
569 $notice = get_transient( $notification['id'] );
570 if ( ! empty( $notice ) && ( $notice && time() < $notice ) ) {
571 continue;
572 }
573
574 if ( ! empty( $notification['type'] ) ) {
575 switch ( $notification['type'] ) {
576 case 'error':
577 $numberOfPluginErrors++;
578 break;
579 case 'warning':
580 $numberOfPluginWarnings++;
581 break;
582 case 'info':
583 $notificationCount++;
584 break;
585 }
586 } else {
587 $notificationCount++;
588 }
589 }
590 }
591
592 $numberOfPluginIssues = $numberOfPluginErrors + $numberOfPluginWarnings;
593
594 if ( $numberOfPluginErrors > 0 ) {
595 $pluginStatus = 'error';
596 } else if ( $numberOfPluginWarnings > 0 ) {
597 $pluginStatus = 'warning';
598 } else {
599 $pluginStatus = 'ok';
600 }
601 $data = [ 'issues' => $numberOfPluginIssues, 'status' => $pluginStatus, 'errors' => $numberOfPluginErrors, 'warnings' => $numberOfPluginWarnings, 'notifications' => $notificationCount ];
602
603 return $data;
604 }
605 /**
606 * Checks if the user has capabilities to manage options - administrators typically have this capability.
607 * @return void|bool
608 */
609 private function pass_notification_capabilities() {
610 if ( ! current_user_can( 'manage_options' ) )
611 return;
612 else {
613 return true;
614 }
615 }
616
617 public function test_mode_notification_html() {
618 $components = new \NitroPack\WordPress\Settings\Components;
619 $components->render_notification( 'Visitors are accessing your unoptimized pages. Make sure to disable it once you are done testing.', 'warning', 'Test Mode Enabled', false, [ 'test-mode' ] );
620 }
621 public function nitropack_safemode_notification() {
622 nitropack_verify_ajax_nonce( $_REQUEST );
623 $this->test_mode_notification_html();
624 wp_die();
625 }
626
627 /* Dismiss notification by using set_transient -> temporary dismissal with auto-expiry */
628 public function nitropack_dismiss_notification_by_transient() {
629 if ( ! $this->pass_notification_capabilities() ) {
630 wp_die( __( 'You do not have sufficient permissions.', 'nitropack' ) );
631 }
632
633 if ( empty( $_POST['notification_id'] ) ) {
634 wp_send_json_error( [ 'message' => __( 'Missing notification ID.', 'nitropack' ) ] );
635 }
636
637 nitropack_verify_ajax_nonce( $_REQUEST );
638
639 $notification_id = $_POST['notification_id'];
640 $notification_end = $_POST['notification_end'];
641 $midpoint = get_date_midpoint( $notification_end );
642 $notification_end = strtotime( $notification_end ) - time();
643 $transient_status = set_transient( $notification_id, $midpoint, $notification_end );
644
645 nitropack_json_and_exit( array(
646 "transient_status" => $transient_status,
647 ) );
648 }
649
650 /**
651 * Handles the dismissal of a notification permanently by updating nitropack-dismissed-notices option in the database.
652 *
653 * @return void Outputs a JSON response and terminates the script execution.
654 */
655
656 public function nitropack_dismiss_permanently_notification() {
657 if ( ! $this->pass_notification_capabilities() ) {
658 wp_send_json_error( [ 'message' => __( 'You do not have sufficient permissions.', 'nitropack' ) ] );
659 }
660
661 if ( empty( $_POST['notification_id'] ) ) {
662 wp_send_json_error( [ 'message' => __( 'Missing notification ID.', 'nitropack' ) ] );
663 }
664
665 nitropack_verify_ajax_nonce( $_REQUEST );
666
667 $notification_id = sanitize_text_field( wp_unslash( $_POST['notification_id'] ) );
668 $notices = get_option( 'nitropack-dismissed-notices', [] );
669
670 if ( ! in_array( $notification_id, $notices, true ) ) {
671 $notices[] = $notification_id;
672 update_option( 'nitropack-dismissed-notices', $notices );
673 }
674
675 wp_send_json_success();
676 }
677
678 /**
679 * Moves existing dismissed notices to the new dismissed option as an array.
680 *
681 * Notices being migrated:
682 * - `nitropack-wcNotice` (mapped to `WooCommerce`)
683 * - `nitropack-noticeOptimizeCPT` (mapped to `OptimizeCPT`)
684 *
685 * @return void
686 */
687
688 public function move_existing_notices() {
689 $existing_notices = [ 'nitropack-wcNotice' => 'WooCommerce', 'nitropack-noticeOptimizeCPT' => 'OptimizeCPT' ];
690 foreach ( $existing_notices as $notice => $new_notice ) {
691 if ( get_option( $notice ) ) {
692 $notices = get_option( 'nitropack-dismissed-notices', [] );
693 if ( ! in_array( $notice, $notices, true ) ) {
694 $notices[] = $new_notice;
695 update_option( 'nitropack-dismissed-notices', $notices );
696 }
697 delete_option( $notice );
698 }
699 }
700 }
701 /**
702 * Deactivates a conflicting plugin from NitroPack.
703 *
704 * It verifies the nonce for security and checks if the specified plugin is in the list of conflicting plugins
705 * and finally deactivates it if it is active.
706 *
707 * @return void Outputs a JSON response indicating success or failure.
708 */
709 public function nitropack_conflict_plugin_deactivate() {
710 if ( ! $this->pass_notification_capabilities() ) {
711 wp_send_json_error( [ 'message' => __( 'You do not have sufficient permissions.', 'nitropack' ) ] );
712 }
713
714 if ( empty( $_POST['plugin'] ) ) {
715 wp_send_json_error( [ 'message' => __( 'Missing plugin.', 'nitropack' ) ] );
716 }
717 $plugin = sanitize_text_field( wp_unslash( $_POST['plugin'] ) );
718
719 if ( empty( $_POST['plugin_name'] ) ) {
720 wp_send_json_error( [ 'message' => __( 'Missing plugin name.', 'nitropack' ) ] );
721 }
722 $plugin_name = sanitize_text_field( wp_unslash( $_POST['plugin_name'] ) );
723
724 nitropack_verify_ajax_nonce( $_REQUEST );
725
726 // Check if the plugin is in the list of conflicting plugins for extra security measures.
727 $conflictingPlugins = \NitroPack\WordPress\ConflictingPlugins::getInstance();
728 $conflictingPlugins_list = $conflictingPlugins->nitropack_get_conflicting_plugins();
729 $plugin_found = false;
730 foreach ( $conflictingPlugins_list as $conflict_plugin ) {
731 if ( $conflict_plugin['plugin'] === $plugin ) {
732 $plugin_found = true;
733 break;
734 }
735 }
736 if ( ! $plugin_found ) {
737 wp_send_json_error( [ 'message' => __( 'Plugin not found in the list of conflicting plugins.', 'nitropack' ) ] );
738 }
739
740 if ( is_plugin_active( $plugin ) ) {
741 deactivate_plugins( $plugin );
742 if ( ! is_plugin_active( $plugin ) ) {
743 /* translators: %s: Name of the plugin that was deactivated */
744 wp_send_json_success( [ 'message' => sprintf( esc_html__( '%s deactivated successfully.', 'nitropack' ), $plugin_name ) ] );
745 } else {
746 wp_send_json_error( [ 'message' => __( 'Failed to deactivate the plugin.', 'nitropack' ) ] );
747 }
748 } else {
749 /* translators: %s: Name of the plugin */
750 wp_send_json_error( [ 'message' => sprintf( esc_html__( '%s is not active.', 'nitropack' ), $plugin_name ) ] );
751 }
752 }
753 }
754