PluginProbe ʕ •ᴥ•ʔ
Advanced Database Cleaner – Optimize & Clean Database to Speed Up Site Performance / 4.2.0
Advanced Database Cleaner – Optimize & Clean Database to Speed Up Site Performance v4.2.0
4.2.0 trunk 1.0.0 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.5 1.3.6 1.3.7 2.0.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.1.0 4.1.1
advanced-database-cleaner / includes / utils / class-adbc-notifications.php
advanced-database-cleaner / includes / utils Last commit date
validator 5 days ago class-adbc-common-utils.php 4 months ago class-adbc-files.php 7 months ago class-adbc-logging.php 3 months ago class-adbc-notifications.php 5 days ago class-adbc-rest.php 5 days ago
class-adbc-notifications.php
499 lines
1 <?php
2
3 // Exit if accessed directly
4 if ( ! defined( 'ABSPATH' ) )
5 exit;
6
7 /**
8 * ADBC Notifications class.
9 *
10 * Manages all types of plugin notifications, including warnings.
11 */
12 class ADBC_Notifications extends ADBC_Singleton {
13
14 private const WP_MIN_VERSION = '5.0';
15 private const PHP_MIN_VERSION = '7.0';
16
17 // Initializes the notifications meta array with the default keys.
18 private static $notifications_meta = [
19
20 // The messages are empty because they will be initialized in the constructor, because we can't use the translation functions in this context.
21 "php_is_old" => [
22 "type" => "warning",
23 "message" => "",
24 "is_critical" => true,
25 "dismissible" => false,
26 "save" => false,
27 "global" => false,
28 ],
29 "wp_is_old" => [
30 "type" => "warning",
31 "message" => "",
32 "is_critical" => true,
33 "dismissible" => false,
34 "save" => false,
35 "global" => false,
36 ],
37 "uploads_folder" => [
38 "type" => "warning",
39 "message" => "",
40 "is_critical" => false,
41 "dismissible" => false,
42 "save" => true,
43 "global" => false,
44 ],
45 "wp_file_system" => [
46 "type" => "warning",
47 "message" => "",
48 "is_critical" => false,
49 "dismissible" => false,
50 "save" => true,
51 "global" => false,
52 ],
53 "rating_notice" => [
54 "type" => "rating",
55 "message" => "",
56 "is_critical" => false,
57 "dismissible" => true,
58 "save" => true,
59 "global" => true,
60 "condition" => [ 'ADBC_Notifications', 'should_show_rating_notice' ]
61 ],
62 "addons_activity_info" => [
63 "type" => "info",
64 "message" => "",
65 "is_critical" => false,
66 "dismissible" => true,
67 "save" => true,
68 "global" => false,
69 "condition" => [ 'ADBC_Notifications', 'always_return_true' ] // Always true, so it can be added automatically later.
70 ],
71 "migration_available" => [
72 "type" => "info",
73 "message" => "",
74 "is_critical" => false,
75 "dismissible" => true,
76 "save" => true,
77 "global" => false,
78 "condition" => [ 'ADBC_Notifications', 'old_data_import_available' ]
79 ],
80 "imported_tasks_deactivated_notice" => [
81 "type" => "info",
82 "message" => "",
83 "is_critical" => false,
84 "dismissible" => true,
85 "save" => true,
86 "global" => false,
87 ],
88 "pro_remote_scan_upsell" => [
89 "type" => "info",
90 "message" => "",
91 "is_critical" => false,
92 "dismissible" => true,
93 "save" => true,
94 "global" => false,
95 "condition" => [ 'ADBC_Notifications', 'should_show_pro_remote_scan_upsell' ]
96 ],
97 "ltd_migration_notice" => [
98 "type" => "info",
99 "message" => "",
100 "is_critical" => false,
101 "dismissible" => true,
102 "save" => true,
103 "global" => true,
104 "condition" => [ 'ADBC_Notifications', 'should_show_ltd_migration_notice' ]
105 ],
106 "woptimize_notice" => [
107 "type" => "info",
108 "message" => "",
109 "is_critical" => false,
110 "dismissible" => true,
111 "save" => true,
112 "global" => false,
113 "condition" => [ 'ADBC_Notifications', 'should_show_woptimize_notice' ]
114 ],
115 "woocommerce_not_detected" => [
116 "type" => "info",
117 "message" => "",
118 "is_critical" => false,
119 "dismissible" => false,
120 "save" => false,
121 "global" => false,
122 ],
123
124 ];
125
126 private $notifications = [];
127
128 /**
129 * Constructor.
130 */
131 protected function __construct() {
132
133 parent::__construct();
134
135 // Initialize the notifications meta array with the messages.
136 $this->initialize_messages();
137
138 // Load the notifications from the settings.
139 $notifications = ADBC_Settings::instance()->get_setting( 'notifications' );
140
141 // Add the notifications fetched from the settings to the notifications array with their dismissed state.
142 foreach ( $notifications as $key => $dismissed ) {
143 $this->notifications[ $key ] = array_merge( self::$notifications_meta[ $key ], $dismissed );
144 }
145
146 // Check and add compatibility warnings to the notifications array.
147 $this->check_and_add_compatibility_warnings();
148
149 // Conditionally add or remove notifications based on specific conditions.
150 $this->conditionally_add_remove_notifications();
151
152 }
153
154 /**
155 * Get all non dismissed notifications.
156 *
157 * @return array Notifications array.
158 */
159 public function get_all_non_dismissed() {
160 return array_filter( $this->notifications, function ($n) {
161 return ! $n['dismissed'];
162 } );
163 }
164
165 /**
166 * Get all warnings.
167 *
168 * @return array Warnings array.
169 */
170 public function get_warnings() {
171 return array_filter( $this->get_all_non_dismissed(), function ($n) {
172 return $n['type'] === 'warning';
173 } );
174 }
175
176 /**
177 * Get all local notifications (non-global).
178 *
179 * @return array Local notifications array.
180 */
181 public function get_local_notifications() {
182 return array_filter( $this->get_all_non_dismissed(), function ($n) {
183 return ! $n['global'] && $n['type'] !== 'warning';
184 } );
185 }
186
187 /**
188 * Get all global notifications (non-warning).
189 *
190 * @return array Global notifications array.
191 */
192 public function get_global_notifications() {
193 return array_filter( $this->get_all_non_dismissed(), function ($n) {
194 return $n['global'] && $n['type'] !== 'warning';
195 } );
196 }
197
198 /**
199 * Add a notification.
200 *
201 * @param string $key Notification key.
202 *
203 * @return bool True if the notification was added, false otherwise.
204 */
205 public function add_notification( $key ) {
206
207 // If the notification already exists, return true.
208 if ( isset( $this->notifications[ $key ] ) ) {
209 return true;
210 }
211
212 // Check if the notification key is valid.
213 if ( ! isset( self::$notifications_meta[ $key ] ) ) {
214 return false;
215 }
216
217 // If the notification is not already set, add it with the default values.
218 $this->notifications[ $key ] = self::$notifications_meta[ $key ];
219 $this->notifications[ $key ]['dismissed'] = false;
220
221 return $this->update();
222
223 }
224
225 /**
226 * Dismiss a notification.
227 *
228 * @param string $key Notification key.
229 *
230 * @return bool True if the notification was dismissed, false otherwise.
231 */
232 public function dismiss_notification( $key ) {
233
234 // If the notification exist and is dismissible, update its dismissed state.
235 if ( isset( $this->notifications[ $key ] ) && $this->notifications[ $key ]['dismissible'] ) {
236 $this->notifications[ $key ]['dismissed'] = true;
237 return $this->update();
238 }
239
240 // If the notification doesn't exist or is not dismissible, return false.
241 return false;
242
243 }
244
245 /**
246 * Delete a notification.
247 *
248 * @param string $key Notification key.
249 *
250 * @return bool True if the notification was deleted, false otherwise.
251 */
252 public function delete_notification( $key ) {
253
254 // if it doesn't exist, return true.
255 if ( ! isset( $this->notifications[ $key ] ) ) {
256 return true;
257 }
258 // Check if the notification key is valid.
259 if ( ! isset( self::$notifications_meta[ $key ] ) ) {
260 return false;
261 }
262
263 // If the notification exists, unset it and update the database.
264 unset( $this->notifications[ $key ] );
265
266 return $this->update();
267
268 }
269
270 /**
271 * Update the notifications in the database.
272 *
273 * @return bool True if the update was successful, false otherwise.
274 */
275 private function update() {
276
277 $notifications_to_save = [];
278
279 // Save only the notifications that need to be saved in the database.
280 foreach ( $this->notifications as $key => $notification ) {
281 if ( $notification['save'] ) {
282 $notifications_to_save[ $key ] = [
283 'dismissed' => $notification['dismissed']
284 ];
285 }
286 }
287
288 return ADBC_Settings::instance()->update_settings( [ 'notifications' => $notifications_to_save ] );
289
290 }
291
292 /**
293 * Get all notification keys.
294 *
295 * @return array Array of notification keys.
296 */
297 public static function get_notifications_keys() {
298 return array_keys( self::$notifications_meta );
299 }
300
301 /**
302 * Check and add compatibility warnings to the notifications array.
303 *
304 * @return void
305 */
306 private function check_and_add_compatibility_warnings() {
307
308 // Check PHP version.
309 if ( version_compare( PHP_VERSION, self::PHP_MIN_VERSION, '<' ) )
310 $this->add_notification( 'php_is_old' );
311
312 // Check WordPress version.
313 if ( version_compare( get_bloginfo( 'version' ), self::WP_MIN_VERSION, '<' ) )
314 $this->add_notification( 'wp_is_old' );
315
316 // Check if WooCommerce is installed and activated.
317 if ( ! class_exists( 'WooCommerce' ) )
318 $this->add_notification( 'woocommerce_not_detected' );
319
320 }
321
322 /**
323 * Conditionally add notifications based on specific conditions.
324 *
325 * @return void
326 */
327 private function conditionally_add_remove_notifications() {
328
329 foreach ( self::$notifications_meta as $key => $meta ) {
330
331 // If the condition is empty, or the condition is not callable, or the notification has been dismissed, skip it.
332 if ( empty( $meta['condition'] ) || $this->is_notification_dismissed( $key ) || ! is_callable( $meta['condition'] ) ) {
333 continue;
334 }
335
336 // Only add it if the condition passes, otherwise, if it exists, remove it.
337 if ( call_user_func( $meta['condition'] ) ) {
338 $this->notifications[ $key ] = $meta;
339 $this->notifications[ $key ]['dismissed'] = false;
340 } else if ( isset( $this->notifications[ $key ] ) ) {
341 unset( $this->notifications[ $key ] );
342 }
343
344 }
345
346 $this->update();
347
348 }
349
350 /**
351 * Initialize the messages for the notifications.
352 *
353 * @return void
354 */
355 private function initialize_messages() {
356
357 // Add message for notifications with type 'warning' since they are printed directly on the screen. For other types, we hardcode them in frontend.
358
359 self::$notifications_meta["php_is_old"]["message"] =
360 sprintf(
361 /* translators: 1: PHP version */
362 __( "Please upgrade your PHP to %s or higher to use the plugin without issues.", "advanced-database-cleaner" ), self::PHP_MIN_VERSION );
363
364 self::$notifications_meta["wp_is_old"]["message"] =
365 sprintf(
366 /* translators: 1: WordPress version */
367 __( "Please upgrade WordPress to %s or higher to use the plugin without issues.", "advanced-database-cleaner" ), self::WP_MIN_VERSION );
368
369 self::$notifications_meta["uploads_folder"]["message"] =
370 __( "Uploads folder is not writable. Check permissions.", "advanced-database-cleaner" );
371
372 self::$notifications_meta["wp_file_system"]["message"] =
373 __( "WordPress file system API is not initialized.", "advanced-database-cleaner" );
374
375 }
376
377 /**
378 * Check if the user should see the rating notice.
379 *
380 * @return bool True if the user should see the rating notice, false otherwise.
381 */
382 private static function should_show_rating_notice() {
383
384 $rating_notice_date = ADBC_Settings::instance()->get_setting( 'rating_notice_date' );
385
386 // No need to check if the date is valid, because the setting validator ensures it.
387 $timestamp = DateTime::createFromFormat( 'd/m/Y', $rating_notice_date );
388
389 return ( time() - $timestamp->getTimestamp() ) >= 7 * DAY_IN_SECONDS;
390
391 }
392
393 /**
394 * Always return true, used for conditions that should always pass.
395 *
396 * @return bool Always true.
397 */
398 private static function always_return_true() {
399 return true;
400 }
401
402 /**
403 * Whether to show the Pro remote scan upsell in the scan modal.
404 * Only for Pro version (lifetime plan) users; dismissed when they redeem/sync credits.
405 *
406 * @return bool True if ADBC_IS_PRO_VERSION.
407 */
408 private static function should_show_pro_remote_scan_upsell() {
409 return defined( 'ADBC_IS_PRO_VERSION' ) && ADBC_IS_PRO_VERSION === true;
410 }
411
412 /**
413 * Whether to show the LTD migration (V4 upgrade) global notice.
414 * Shows when reminder date is not set or 7+ days have passed since "Remind me in a week".
415 *
416 * @return bool True if the notice should show.
417 */
418 private static function should_show_ltd_migration_notice() {
419
420 // Return false if we are not in pro version, because the notice is only for pro users.
421 if ( ! ADBC_IS_PRO_VERSION )
422 return false;
423
424 $reminder_date = ADBC_Settings::instance()->get_setting( 'ltd_migration_reminder_date' );
425
426 $timestamp = DateTime::createFromFormat( 'd/m/Y', $reminder_date );
427
428 return ( time() - $timestamp->getTimestamp() ) >= 7 * DAY_IN_SECONDS;
429 }
430
431 /**
432 * Delay the LTD migration notice by 7 days (remind me in a week).
433 *
434 * @return bool True on success.
435 */
436 public function delay_ltd_migration_notice() {
437 // Set the LTD migration reminder date to today.
438 ADBC_Settings::instance()->update_settings( [ 'ltd_migration_reminder_date' => date( 'd/m/Y' ) ] );
439 return $this->delete_notification( 'ltd_migration_notice' );
440 }
441
442 /**
443 * Whether to show the WOptimize promo notice.
444 * Shows only when WOptimize is not installed yet.
445 *
446 * @return bool True if the notice should show.
447 */
448 private static function should_show_woptimize_notice() {
449
450 // Don't promote WOptimize if it is already installed.
451 if ( ADBC_Admin_Init::is_woptimize_installed() )
452 return false;
453
454 return true;
455
456 }
457
458 /**
459 * Delay the rating notice by 7 days.
460 *
461 * @return bool True if the notice was delayed, false otherwise.
462 */
463 public function delay_rating_notice() {
464 // Set the rating notice date to today.
465 ADBC_Settings::instance()->update_settings( [ 'rating_notice_date' => date( 'd/m/Y' ) ] );
466 return $this->delete_notification( 'rating_notice' );
467 }
468
469 /**
470 * Check if there is a need to migrate from an old version (before 4.0.0).
471 *
472 * @return bool True if there is a need to migrate, false otherwise.
473 */
474 public static function old_data_import_available() {
475
476 // If we are in free or pro, return false.
477 if ( ADBC_VERSION_TYPE === 'FREE' || ADBC_IS_PRO_VERSION === true )
478 return false;
479
480 // If the free migration is not done, check all available migration data.
481 if ( ADBC_Settings::instance()->get_setting( 'free_migration_done' ) === '0' )
482 return count( ADBC_Migration::get_available_migration_data() ) > 0;
483 else // If the free migration is done, check only the available migration data for the pro version.
484 return count( ADBC_Migration::get_available_migration_data( 'pro' ) ) > 0;
485
486 }
487
488 /**
489 * Check if a notification is dismissed.
490 *
491 * @param string $key Notification key.
492 *
493 * @return bool True if the notification is dismissed, false otherwise.
494 */
495 public function is_notification_dismissed( $key ) {
496 return isset( $this->notifications[ $key ] ) && isset( $this->notifications[ $key ]['dismissed'] ) && $this->notifications[ $key ]['dismissed'] === true;
497 }
498
499 }