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