PluginProbe ʕ •ᴥ•ʔ
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization / 1.18.5
NitroPack – Performance, Page Speed & Cache Plugin for Core Web Vitals, CDN & Image Optimization v1.18.5
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 10 months ago
Notifications.php
750 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"] ) ) {
53 $components->render_notification( "<script>document.cookie = 'nitropack_after_activate_notice=1; expires=Thu, 01 Jan 1970 00:00:01 GMT;';</script> Go to its' settings to connect it in order to start optimizing your site.",
54 'info',
55 esc_html__( 'NitroPack activated but not connected', 'nitropack' ),
56 '<a href="' . admin_url( 'admin.php?page=nitropack' ) . '">' . esc_html__( 'NitroPack Settings', '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 '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 ),
106 'actions' => '<a class="btn btn-warning" nitropack-rc-data="' . $rcpName . '">' . esc_html__( 'Delete now', 'nitropack' ) . '</a>',
107 );
108 }
109 /* Sets a warning if there is any activity in the plugins such as new activations, updates, or deletions. */
110 if ( isset( $_COOKIE['nitropack_apwarning'] ) ) {
111 $cookie_path = nitropack_cookiepath();
112 $warnings[] = array(
113 'title' => esc_html__( "Plugins activity", 'nitropack' ),
114 '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' ),
115 '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>",
116 'classes' => [ 'plugins-state' ],
117 );
118 }
119
120 /* Sets a warning if the Test Mode is enabled. */
121 if ( TestMode::getInstance()->is_test_mode_enabled() ) {
122 $safeModeMessage = __( 'Visitors are accessing your unoptimized pages. Make sure to disable it once you are done testing.', 'nitropack' );
123 if ( get_nitropack()->getDistribution() == "oneclick" ) {
124 $safeModeMessage = apply_filters( "nitropack_oneclick_safemode_message", $safeModeMessage );
125 }
126
127 $warnings[] = array(
128 'title' => esc_html__( "Test Mode Enabled", 'nitropack' ),
129 'msg' => $safeModeMessage,
130 'classes' => [ 'test-mode' ],
131 );
132 }
133
134 $nitropackIsConnected = get_nitropack()->isConnected();
135
136 if ( $nitropackIsConnected ) {
137 if ( nitropack_is_advanced_cache_allowed() ) {
138 $notification_title = esc_html__( "File advanced-cache.php cannot be created", 'nitropack' );
139 $notification_class = [ 'advanced-cache' ];
140
141 if ( ! nitropack_has_advanced_cache() ) {
142
143 $advancedCacheFile = nitropack_trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php';
144 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 :(
145
146 if ( nitropack_install_advanced_cache() ) {
147 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.
148
149 /* Sets an info notifications if the advanced-cache.php file was re-installed. */
150 $infos[] = array(
151 'title' => esc_html__( 'File advanced-cache.php re-installed', 'nitropack' ),
152 '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' ),
153 'actions' => '<a href="' . admin_url() . 'plugins.php" target="_blank" class="btn btn-secondary">' . esc_html__( 'Plugins page' ) . '</a>',
154 'classes' => $notification_class,
155 );
156 }
157 } else {
158 if ( ! $conflictingPlugins->nitropack_is_conflicting_plugin_active() ) {
159
160 /* Sets an error notifications for not being able to create the advanced-cache.php file due to conflicting caching plugins */
161
162 $errors[] = array(
163 'title' => $notification_title,
164 'msg' => __( 'Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack' ),
165 'classes' => $notification_class,
166 );
167 }
168 }
169 }
170 } else {
171 if ( ! defined( "NITROPACK_ADVANCED_CACHE_VERSION" ) || NITROPACK_VERSION != NITROPACK_ADVANCED_CACHE_VERSION ) {
172 if ( ! nitropack_install_advanced_cache() ) {
173 if ( $conflictingPlugins->nitropack_is_conflicting_plugin_active() ) {
174 $errors[] = array(
175 'title' => $notification_title,
176 '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' ),
177 'actions' => '<a href="' . admin_url() . 'plugins.php" target="_blank" class="btn btn-primary">Plugins page</a>',
178 'classes' => $notification_class,
179 );
180 } else {
181 $errors[] = array(
182 'title' => $notification_title,
183 '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' ),
184 'classes' => $notification_class,
185 );
186 }
187 }
188 }
189 }
190 } else {
191 if ( nitropack_has_advanced_cache() ) {
192 nitropack_uninstall_advanced_cache();
193 }
194 }
195
196 if ( ( ! defined( "WP_CACHE" ) || ! WP_CACHE ) ) {
197 $notification_class = [ 'wp-cache' ];
198 if ( \NitroPack\Integration\Hosting\Flywheel::detect() ) { // Flywheel: This is configured throught the FW control panel
199 $warnings[] = array(
200 'title' => esc_html__( "WP_CACHE not enabled", 'nitropack' ),
201 'msg' => esc_html__( "Please go to your FlyWheel control panel and enable this setting.", 'nitropack' ),
202 'actions' => '<a href="https://getflywheel.com/wordpress-support/how-to-enable-wp_cache/" target="_blank" class="btn btn-primary">View more</a>',
203 'classes' => $notification_class,
204 );
205 } else if ( ! nitropack_set_wp_cache_const( true ) ) {
206 $errors[] = array(
207 'title' => esc_html__( 'Constant WP_CACHE cannot be set', 'nitropack' ),
208 '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' ),
209 'classes' => $notification_class,
210 );
211 }
212 }
213
214 if ( apply_filters( 'nitropack_needs_htaccess_changes', false ) ) {
215 if ( ! nitropack_set_htaccess_rules( true ) ) {
216 $warnings[] = array(
217 'title' => esc_html__( "File .htaccess is not writable", 'nitropack' ),
218 'msg' => esc_html__( 'Unable to configure LiteSpeed specific rules for maximum performance. Please make sure your .htaccess file is writable or contact support.', 'nitropack' ),
219 'classes' => [ 'htaccess' ],
220 );
221 }
222 }
223
224 if ( ! get_nitropack()->dataDirExists() && ! get_nitropack()->initDataDir() ) {
225 $errors[] = array(
226 'title' => esc_html__( 'NitroPack data directory cannot be created', 'nitropack' ),
227 'msg' => esc_html__( 'Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack' ),
228 'classes' => [ 'np-data-dir' ],
229 );
230 return [
231 'error' => $errors,
232 'warning' => $warnings,
233 'info' => $infos
234 ];
235 }
236
237 if ( ! get_nitropack()->pluginDataDirExists() && ! get_nitropack()->initPluginDataDir() ) {
238 $errors[] = array(
239 'title' => esc_html__( 'NitroPack plugin data directory cannot be created', 'nitropack' ),
240 'msg' => esc_html__( 'Please make sure that the /wp-content/ directory is writable and refresh this page.', 'nitropack' ),
241
242 'classes' => [ 'np-data-dir' ],
243 );
244 return [
245 'error' => $errors,
246 'warning' => $warnings,
247 'info' => $infos
248 ];
249 }
250
251 $siteConfig = nitropack_get_site_config();
252 $siteId = $siteConfig ? $siteConfig["siteId"] : NULL;
253 $siteSecret = $siteConfig ? $siteConfig["siteSecret"] : NULL;
254 $webhookToken = esc_attr( get_option( 'nitropack-webhookToken' ) );
255 $blogId = get_current_blog_id();
256 $isConfigOutdated = ! nitropack_is_config_up_to_date();
257 if ( ! get_nitropack()->Config->exists() && ! get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId ) ) {
258 $errors[] = array(
259 'title' => esc_html__( "NitroPack static config file cannot be created", 'nitropack' ),
260 'msg' => esc_html__( 'Please make sure that the /wp-content/config-nitropack/ directory is writable and refresh this page.', 'nitropack' ),
261 );
262 } else if ( $isConfigOutdated ) {
263 if ( ! get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId ) ) {
264 $errors[] = array(
265 'title' => esc_html__( "NitroPack static config file cannot be updated", 'nitropack' ),
266 'msg' => esc_html__( 'Please make sure that the /wp-content/config-nitropack/ directory is writable and refresh this page.', 'nitropack' ),
267 );
268 } else {
269
270 if ( ! $siteConfig ) {
271 nitropack_event( "update" );
272 } else {
273 $prevVersion = ! empty( $siteConfig["pluginVersion"] ) ? $siteConfig["pluginVersion"] : "1.1.4 or older";
274 nitropack_event( "update", null, array( "previous_version" => $prevVersion ) );
275 if ( empty( $siteConfig["pluginVersion"] ) || version_compare( $siteConfig["pluginVersion"], "1.4", "<" ) ) {
276 $nitropack_v1_3_notice_id = 'nitropack_upgrade_to_1_3';
277 }
278 }
279 }
280
281 try {
282 nitropack_setup_webhooks( get_nitropack_sdk(), $webhookToken );
283 } catch (\NitroPack\SDK\WebhookException $e) {
284 $warnings[] = array(
285 'title' => esc_html__( "Unable to configure webhooks", 'nitropack' ),
286 'msg' => esc_html__( 'This can impact the stability of the plugin. Please disconnect and connect again in order to retry configuring the webhooks.', 'nitropack' ),
287 );
288 }
289 } else {
290 $optionsMismatch = false;
291 if ( array_key_exists( 'options_cache', $siteConfig ) ) {
292 foreach ( \NitroPack\WordPress\NitroPack::$optionsToCache as $opt ) {
293 if ( is_array( $opt ) ) {
294 foreach ( $opt as $option => $suboption ) {
295 // Handle both nested and flat structures
296 if ( is_array( $suboption ) ) {
297 // Nested structure
298 if ( ! isset( $siteConfig['options_cache'][ $option ] ) || ! is_array( $siteConfig['options_cache'][ $option ] ) ) {
299 $optionsMismatch = true;
300 break 2;
301 }
302 foreach ( $suboption as $subkey => $subvalue ) {
303 if (
304 ! isset( $siteConfig['options_cache'][ $option ][ $subkey ] ) ||
305 $siteConfig['options_cache'][ $option ][ $subkey ] !== get_option( $option )[ $subkey ]
306 ) {
307 $optionsMismatch = true;
308 break 3;
309 }
310 }
311 } else {
312 // Flat structure within the nested loop
313 if (
314 ! isset( $siteConfig['options_cache'][ $option ] ) ||
315 $siteConfig['options_cache'][ $option ] !== get_option( $option )
316 ) {
317 $optionsMismatch = true;
318 break 2;
319 }
320 }
321 }
322 } else {
323 // Flat structure outside the nested loop
324 if (
325 ! isset( $siteConfig['options_cache'][ $opt ] ) ||
326 is_bool( $siteConfig['options_cache'][ $opt ] ) ||
327 $siteConfig['options_cache'][ $opt ] !== get_option( $opt )
328 ) {
329 $optionsMismatch = true;
330 break;
331 }
332 }
333 }
334 } else {
335 $optionsMismatch = true;
336 }
337
338 if (
339 $optionsMismatch ||
340 ( ! array_key_exists( "isEzoicActive", $siteConfig ) || $siteConfig["isEzoicActive"] !== \NitroPack\Integration\Plugin\Ezoic::isActive() ) ||
341 ( ! array_key_exists( "isLateIntegrationInitRequired", $siteConfig ) || $siteConfig["isLateIntegrationInitRequired"] !== nitropack_is_late_integration_init_required() ) ||
342 ( ! array_key_exists( "isDlmActive", $siteConfig ) || $siteConfig["isDlmActive"] !== \NitroPack\Integration\Plugin\DownloadManager::isActive() ) ||
343 ( ! array_key_exists( "isAeliaCurrencySwitcherActive", $siteConfig ) || $siteConfig["isAeliaCurrencySwitcherActive"] !== \NitroPack\Integration\Plugin\AeliaCurrencySwitcher::isActive() ) ||
344 ( ! array_key_exists( "isGeoTargetingWPActive", $siteConfig ) || $siteConfig["isGeoTargetingWPActive"] !== \NitroPack\Integration\Plugin\GeoTargetingWP::isActive() ) ||
345 ( ! array_key_exists( "isWoocommerceActive", $siteConfig ) || $siteConfig["isWoocommerceActive"] !== \NitroPack\Integration\Plugin\WooCommerce::isActive() ) ||
346 ( ! array_key_exists( "isWoocommerceCacheHandlerActive", $siteConfig ) || $siteConfig["isWoocommerceCacheHandlerActive"] !== \NitroPack\Integration\Plugin\WoocommerceCacheHandler::isActive() )
347 ) {
348 if ( ! get_nitropack()->updateCurrentBlogConfig( $siteId, $siteSecret, $blogId ) ) {
349 $errors[] = array(
350 'title' => esc_html__( "NitroPack static config file cannot be updated", 'nitropack' ),
351 'msg' => esc_html__( 'Please make sure that the /wp-content/config-nitropack/ directory is writable and refresh this page.', 'nitropack' ),
352 );
353 }
354 }
355
356 if ( empty( $_COOKIE["nitropack_webhook_sync"] ) || ! $siteConfig["webhookToken"] ) {
357 if ( null !== $nitro = get_nitropack_sdk() ) {
358 try {
359 if ( ! headers_sent() ) {
360 nitropack_setcookie( "nitropack_webhook_sync", "1", time() + 300 ); // Do these checks in 5 minute intervals.
361 }
362 $configWebhook = $nitro->getApi()->getWebhook( "config" );
363 if ( ! empty( $configWebhook ) ) {
364 $query = parse_url( $configWebhook, PHP_URL_QUERY );
365 if ( $query ) {
366 parse_str( $query, $webhookParams );
367 if ( empty( $webhookParams["token"] ) || $webhookParams["token"] != $webhookToken ) {
368 $warnings[] = array(
369 'title' => esc_html__( "Connection problems detected", 'nitropack' ),
370 '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.', 'nitropaack' ),
371 'actions' => '<a id="nitro-restore-connection-btn" class="btn btn-warning">Restore connection</a>',
372 );
373 }
374 }
375 }
376 } catch (\Exception $e) {
377 //Do nothing
378 }
379 }
380 }
381
382 if ( apply_filters( 'nitropack_should_modify_htaccess', false ) && ( empty( $_SERVER["NitroPackHtaccessVersion"] ) || NITROPACK_VERSION != $_SERVER["NitroPackHtaccessVersion"] ) ) {
383 if ( ! nitropack_set_htaccess_rules( true ) ) {
384 $errors[] = array(
385 'title' => esc_html__( "The .htaccess file cannot be modified", 'nitropack' ),
386 'msg' => esc_html__( 'Please make sure that it is writable and refresh this page.', 'nitropack' ),
387 );
388 }
389 }
390 }
391 if ( isset( $nitropack_v1_3_notice_id ) ) {
392 $warnings[] = array(
393 'title' => esc_html__( "NitroPack upgraded to 1.3", 'nitropack' ),
394 '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' ),
395 'dismissibleId' => $nitropack_v1_3_notice_id,
396 'dismissBy' => 'option',
397 );
398 }
399
400 if ( \NitroPack\Integration\Plugin\Cloudflare::isApoActive() && ! \NitroPack\Integration\Plugin\Cloudflare::isApoCacheByDeviceTypeEnabled() ) {
401 $warnings[] = array(
402 'title' => esc_html__( "Cache By Device Type is not activate", 'nitropack' ),
403 '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' ),
404 );
405 }
406 }
407
408 $npPluginNotices = [
409 'error' => $errors,
410 'warning' => $warnings,
411 'info' => $infos
412 ];
413
414 return $npPluginNotices;
415 }
416
417 /**
418 * Display admin notices in the NitroPack -> Dashboard plugin page.
419 *
420 * This function checks if the current user has the necessary capabilities to view the notices.
421 * It renders specific notifications related to hosting information, system, compatibilities and notifications coming from the NitroPack app
422 *
423 * @return void
424 */
425 public function nitropack_display_admin_notices() {
426 if ( ! $this->pass_notification_capabilities() )
427 return;
428
429 $noticesArray = $this->nitropack_plugin_notices();
430 $components = new \NitroPack\WordPress\Settings\Components;
431 foreach ( $noticesArray as $type => $notices ) {
432 foreach ( $notices as $notice ) {
433 $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 );
434 }
435 }
436 //render app notifications
437 $this->render_app_notifications();
438 }
439
440 /**
441 * Render notifications coming from notifications.json file such as ones from the NitroPack app.
442 *
443 * @return void
444 */
445 public function render_app_notifications() {
446 $components = new \NitroPack\WordPress\Settings\Components();
447 $app_notifications = AppNotifications::getInstance();
448 foreach ( $app_notifications->get( 'system' ) as $notification ) {
449 $msg = $notification['message'];
450 $type = 'info';
451 $title = '';
452
453 if ( ! empty( $notification['type'] ) ) {
454 $type = $notification['type'];
455 }
456 if ( ! empty( $notification['message_details']['title'] ) ) {
457 $title = $notification['message_details']['title'];
458 }
459 if ( ! empty( $notification['message_details']['message'] ) ) {
460 $msg = $notification['message_details']['message'];
461 }
462
463 $components->render_notification( $msg, $type, $title, '', [ 'app-notification' ], $notification['id'], 'transient', $notification );
464 }
465 }
466 /**
467 * Prints a hosting notice for NitroPack.
468 *
469 * @return void
470 */
471 private function nitropack_print_hosting_notice() {
472
473 $hostingNoticeFile = nitropack_get_hosting_notice_file();
474 if ( ! get_nitropack()->isConnected() || file_exists( $hostingNoticeFile ) )
475 return;
476
477 $documentedHostingSetups = array(
478 "flywheel" => array(
479 "name" => "Flywheel",
480 "helpUrl" => "https://getflywheel.com/wordpress-support/how-to-enable-wp_cache/"
481 ),
482 "cloudways" => array(
483 "name" => "Cloudways",
484 "helpUrl" => "https://support.nitropack.io/hc/en-us/articles/360060916674-Cloudways-Hosting-Configuration-for-NitroPack"
485 )
486 );
487
488 $siteConfig = nitropack_get_site_config();
489
490 if ( $siteConfig && ! empty( $siteConfig["hosting"] ) && array_key_exists( $siteConfig["hosting"], $documentedHostingSetups ) ) {
491
492 $hostingInfo = $documentedHostingSetups[ $siteConfig["hosting"] ];
493 $showNotice = true;
494 if ( $siteConfig["hosting"] == "flywheel" && defined( "WP_CACHE" ) && WP_CACHE ) {
495 $showNotice = false;
496 }
497
498 if ( $showNotice ) {
499 $components = new \NitroPack\WordPress\Settings\Components;
500 $components->render_notification( esc_html__( "Please follow the instructions in order to make sure that everything works correctly.", 'nitropack' ), 'info',
501 sprintf( esc_html__( 'It looks like you are hosted on %s', 'nitropack' ), $hostingInfo['name'] ),
502 '<a href="' . $hostingInfo["helpUrl"] . '" target="_blank" class="btn btn-info btn-ghost">' . esc_html__( 'Read Instructions', 'nitropack' ) . '</a>',
503 [ 'hosting-notice' ], 'hosting-' . $siteConfig["hosting"], 'option' );
504 }
505 }
506 }
507 /**
508 * Prints a WooCommerce notice for NitroPack across WordPress admin
509 * @return void
510 */
511 private function nitropack_print_woocommerce_notice() {
512 if ( get_nitropack()->isConnected() ) {
513 if ( class_exists( 'WooCommerce' ) ) {
514 $np_notices = get_option( 'nitropack-dismissed-notices', [] );
515 $woocommerce_notice = in_array( 'WooCommerce', $np_notices, true ) ? true : false;
516
517 if ( ! $woocommerce_notice ) {
518 $components = new \NitroPack\WordPress\Settings\Components;
519 $components->render_notification( __( 'Your <strong>account</strong>, <strong>cart</strong>, and <strong>checkout</strong> pages are automatically excluded from optimization.', 'nitropack' ),
520 'success',
521 esc_html__( 'WooCommerce detected', 'nitropack' ),
522 '<a class="btn btn-secondary" href="' . admin_url( 'admin.php?page=nitropack' ) . '">' . esc_html__( 'Settings', 'nitropack' ) . '</a>',
523 [ 'woocommerce-notice' ],
524 'WooCommerce', 'option' );
525 }
526 }
527 }
528 }
529
530 public function admin_bar_notices_counter() {
531 if ( ! $this->pass_notification_capabilities() )
532 return;
533
534 $notices = $this->nitropack_plugin_notices();
535
536 $numberOfPluginErrors = 0;
537 $numberOfPluginWarnings = 0;
538 $notificationCount = 0;
539 foreach ( array( "warning", "error", "info" ) as $type ) {
540
541 foreach ( $notices[ $type ] as $notice ) {
542
543 if ( ! empty( $notice['dismissibleId'] ) ) {
544 switch ( $type ) {
545 case "error":
546 $numberOfPluginErrors++;
547 break;
548 case "warning":
549 $numberOfPluginWarnings++;
550 break;
551 case "info":
552 $notificationCount++;
553 break;
554 }
555 }
556
557 }
558 }
559
560 /* Notifications from the app */
561 $app_notifications = AppNotifications::getInstance();
562 foreach ( $app_notifications->get( 'system' ) as $notification ) {
563
564 if ( ! empty( $notification['id'] ) ) {
565
566 /* Don't count if dismissed by transient and the time has passed */
567 $notice = get_transient( $notification['id'] );
568 if ( ! empty( $notice ) && ( $notice && time() < $notice ) ) {
569 continue;
570 }
571
572 if ( ! empty( $notification['type'] ) ) {
573 switch ( $notification['type'] ) {
574 case 'error':
575 $numberOfPluginErrors++;
576 break;
577 case 'warning':
578 $numberOfPluginWarnings++;
579 break;
580 case 'info':
581 $notificationCount++;
582 break;
583 }
584 } else {
585 $notificationCount++;
586 }
587 }
588 }
589
590 $numberOfPluginIssues = $numberOfPluginErrors + $numberOfPluginWarnings;
591
592 if ( $numberOfPluginErrors > 0 ) {
593 $pluginStatus = 'error';
594 } else if ( $numberOfPluginWarnings > 0 ) {
595 $pluginStatus = 'warning';
596 } else {
597 $pluginStatus = 'ok';
598 }
599 $data = [ 'issues' => $numberOfPluginIssues, 'status' => $pluginStatus, 'errors' => $numberOfPluginErrors, 'warnings' => $numberOfPluginWarnings, 'notifications' => $notificationCount ];
600
601 return $data;
602 }
603 /**
604 * Checks if the user has capabilities to manage options - administrators typically have this capability.
605 * @return void|bool
606 */
607 private function pass_notification_capabilities() {
608 if ( ! current_user_can( 'manage_options' ) )
609 return;
610 else {
611 return true;
612 }
613 }
614
615 public function test_mode_notification_html() {
616 $components = new \NitroPack\WordPress\Settings\Components;
617 $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' ] );
618 }
619 public function nitropack_safemode_notification() {
620 nitropack_verify_ajax_nonce( $_REQUEST );
621 $this->test_mode_notification_html();
622 wp_die();
623 }
624
625 /* Dismiss notification by using set_transient -> temporary dismissal with auto-expiry */
626 public function nitropack_dismiss_notification_by_transient() {
627 if ( ! $this->pass_notification_capabilities() ) {
628 wp_die( __( 'You do not have sufficient permissions.' ) );
629 }
630
631 if ( empty( $_POST['notification_id'] ) ) {
632 wp_send_json_error( [ 'message' => __( 'Missing notification ID.' ) ] );
633 }
634
635 nitropack_verify_ajax_nonce( $_REQUEST );
636
637 $notification_id = $_POST['notification_id'];
638 $notification_end = $_POST['notification_end'];
639 $midpoint = get_date_midpoint( $notification_end );
640 $notification_end = strtotime( $notification_end ) - time();
641 $transient_status = set_transient( $notification_id, $midpoint, $notification_end );
642
643 nitropack_json_and_exit( array(
644 "transient_status" => $transient_status,
645 ) );
646 }
647
648 /**
649 * Handles the dismissal of a notification permanently by updating nitropack-dismissed-notices option in the database.
650 *
651 * @return void Outputs a JSON response and terminates the script execution.
652 */
653
654 public function nitropack_dismiss_permanently_notification() {
655 if ( ! $this->pass_notification_capabilities() ) {
656 wp_send_json_error( [ 'message' => __( 'You do not have sufficient permissions.' ) ] );
657 }
658
659 if ( empty( $_POST['notification_id'] ) ) {
660 wp_send_json_error( [ 'message' => __( 'Missing notification ID.' ) ] );
661 }
662
663 nitropack_verify_ajax_nonce( $_REQUEST );
664
665 $notification_id = sanitize_text_field( wp_unslash( $_POST['notification_id'] ) );
666 $notices = get_option( 'nitropack-dismissed-notices', [] );
667
668 if ( ! in_array( $notification_id, $notices, true ) ) {
669 $notices[] = $notification_id;
670 update_option( 'nitropack-dismissed-notices', $notices );
671 }
672
673 wp_send_json_success();
674 }
675
676 /**
677 * Moves existing dismissed notices to the new dismissed option as an array.
678 *
679 * Notices being migrated:
680 * - `nitropack-wcNotice` (mapped to `WooCommerce`)
681 * - `nitropack-noticeOptimizeCPT` (mapped to `OptimizeCPT`)
682 *
683 * @return void
684 */
685
686 public function move_existing_notices() {
687 $existing_notices = [ 'nitropack-wcNotice' => 'WooCommerce', 'nitropack-noticeOptimizeCPT' => 'OptimizeCPT' ];
688 foreach ( $existing_notices as $notice => $new_notice ) {
689 if ( get_option( $notice ) ) {
690 $notices = get_option( 'nitropack-dismissed-notices', [] );
691 if ( ! in_array( $notice, $notices, true ) ) {
692 $notices[] = $new_notice;
693 update_option( 'nitropack-dismissed-notices', $notices );
694 }
695 delete_option( $notice );
696 }
697 }
698 }
699 /**
700 * Deactivates a conflicting plugin from NitroPack.
701 *
702 * It verifies the nonce for security and checks if the specified plugin is in the list of conflicting plugins
703 * and finally deactivates it if it is active.
704 *
705 * @return void Outputs a JSON response indicating success or failure.
706 */
707 public function nitropack_conflict_plugin_deactivate() {
708 if ( ! $this->pass_notification_capabilities() ) {
709 wp_send_json_error( [ 'message' => __( 'You do not have sufficient permissions.' ) ] );
710 }
711
712 if ( empty( $_POST['plugin'] ) ) {
713 wp_send_json_error( [ 'message' => __( 'Missing plugin.' ) ] );
714 }
715 $plugin = sanitize_text_field( wp_unslash( $_POST['plugin'] ) );
716
717 if ( empty( $_POST['plugin_name'] ) ) {
718 wp_send_json_error( [ 'message' => __( 'Missing plugin name.' ) ] );
719 }
720 $plugin_name = sanitize_text_field( wp_unslash( $_POST['plugin_name'] ) );
721
722 nitropack_verify_ajax_nonce( $_REQUEST );
723
724 // Check if the plugin is in the list of conflicting plugins for extra security measures.
725 $conflictingPlugins = \NitroPack\WordPress\ConflictingPlugins::getInstance();
726 $conflictingPlugins_list = $conflictingPlugins->nitropack_get_conflicting_plugins();
727 $plugin_found = false;
728 foreach ( $conflictingPlugins_list as $conflict_plugin ) {
729 if ( $conflict_plugin['plugin'] === $plugin ) {
730 $plugin_found = true;
731 break;
732 }
733 }
734 if ( ! $plugin_found ) {
735 wp_send_json_error( [ 'message' => __( 'Plugin not found in the list of conflicting plugins.' ) ] );
736 }
737
738 if ( is_plugin_active( $plugin ) ) {
739 deactivate_plugins( $plugin );
740 if ( ! is_plugin_active( $plugin ) ) {
741 wp_send_json_success( [ 'message' => sprintf( esc_html__( '%s deactivated successfully.', 'nitropack' ), $plugin_name ) ] );
742 } else {
743 wp_send_json_error( [ 'message' => __( 'Failed to deactivate the plugin.' ) ] );
744 }
745 } else {
746 wp_send_json_error( [ 'message' => sprintf( esc_html__( '%s is not active.', 'nitropack' ), $plugin_name ) ] );
747 }
748 }
749 }
750