PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 2.1
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v2.1
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
imagify / classes / Notices / Notices.php

Notices.php in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 2.1, at classes/Notices/Notices.php

947 lines 23.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 declare(strict_types=1);
3
4 namespace Imagify\Notices;
5
6 use Imagify\Traits\InstanceGetterTrait;
7
8 /**
9 * Class that handles the admin notices.
10 *
11 * @since 1.6.10
12 */
13 class Notices {
14 use InstanceGetterTrait;
15
16 /**
17 * Class version.
18 *
19 * @var string
20 */
21 const VERSION = '1.0.1';
22
23 /**
24 * Name of the transient storing temporary notices.
25 *
26 * @var string
27 */
28 const TEMPORARY_NOTICES_TRANSIENT_NAME = 'imagify_temporary_notices';
29
30 /**
31 * Name of the user meta that stores the dismissed notice IDs.
32 *
33 * @var string
34 */
35 const DISMISS_META_NAME = '_imagify_ignore_notices';
36
37 /**
38 * Action used in the nonce to dismiss a notice.
39 *
40 * @var string
41 */
42 const DISMISS_NONCE_ACTION = 'imagify-dismiss-notice';
43
44 /**
45 * Action used in the nonce to deactivate a plugin.
46 *
47 * @var string
48 */
49 const DEACTIVATE_PLUGIN_NONCE_ACTION = 'imagify-deactivate-plugin';
50
51 /**
52 * List of notice IDs.
53 * They correspond to method names and IDs stored in the "dismissed" transient.
54 * Only use "-" character, not "_".
55 *
56 * @var array
57 */
58 protected static $notice_ids = [
59 // This warning is displayed when the API key is empty. Dismissible.
60 'welcome-steps',
61 // This warning is displayed when the API key is wrong. Dismissible.
62 'wrong-api-key',
63 // This warning is displayed if some plugins are active. NOT dismissible.
64 'plugins-to-deactivate',
65 // This notice is displayed when external HTTP requests are blocked via the WP_HTTP_BLOCK_EXTERNAL constant. Dismissible.
66 'http-block-external',
67 // This warning is displayed when the grid view is active on the library. Dismissible.
68 'grid-view',
69 // This warning is displayed to warn the user that the quota is almost consumed for the current month. Dismissible.
70 'almost-over-quota',
71 // This warning is displayed if the backup folder is not writable. NOT dismissible.
72 'backup-folder-not-writable',
73 // This notice is displayed to rate the plugin after 100 optimizations & 7 days after the first installation. Dismissible.
74 'rating',
75 // Add a message about WP Rocket on the "Bulk Optimization" screen. Dismissible.
76 'wp-rocket',
77 'bulk-optimization-complete',
78 'bulk-optimization-running',
79 ];
80
81 /**
82 * List of user capabilities to use for each notice.
83 * Default value 'manage' is not listed.
84 *
85 * @var array
86 */
87 protected static $capabilities = [
88 'grid-view' => 'optimize',
89 'backup-folder-not-writable' => 'bulk-optimize',
90 'rating' => 'bulk-optimize',
91 'wp-rocket' => 'bulk-optimize',
92 'bulk-optimization-complete' => 'bulk-optimize',
93 'bulk-optimization-running' => 'bulk-optimize',
94 ];
95
96 /**
97 * List of plugins that conflict with Imagify.
98 *
99 * @var array
100 */
101 protected static $conflicting_plugins = [
102 'wp-smush' => 'wp-smushit/wp-smush.php', // WP Smush.
103 'wp-smush-pro' => 'wp-smush-pro/wp-smush.php', // WP Smush Pro.
104 'kraken' => 'kraken-image-optimizer/kraken.php', // Kraken.io.
105 'tinypng' => 'tiny-compress-images/tiny-compress-images.php', // TinyPNG.
106 'shortpixel' => 'shortpixel-image-optimiser/wp-shortpixel.php', // Shortpixel.
107 'ewww' => 'ewww-image-optimizer/ewww-image-optimizer.php', // EWWW Image Optimizer.
108 'ewww-cloud' => 'ewww-image-optimizer-cloud/ewww-image-optimizer-cloud.php', // EWWW Image Optimizer Cloud.
109 'imagerecycle' => 'imagerecycle-pdf-image-compression/wp-image-recycle.php', // ImageRecycle.
110 ];
111
112 /**
113 * The constructor.
114 *
115 * @return void
116 */
117 protected function __construct() {}
118
119
120 /** ----------------------------------------------------------------------------------------- */
121 /** INIT ==================================================================================== */
122 /** ----------------------------------------------------------------------------------------- */
123
124 /**
125 * Launch the hooks.
126 *
127 * @since 1.6.10
128 */
129 public function init() {
130 // For generic purpose.
131 add_action( 'all_admin_notices', [ $this, 'render_notices' ] );
132 add_action( 'wp_ajax_imagify_dismiss_notice', [ $this, 'admin_post_dismiss_notice' ] );
133 add_action( 'admin_post_imagify_dismiss_notice', [ $this, 'admin_post_dismiss_notice' ] );
134 // For specific notices.
135 add_action( 'imagify_dismiss_notice', [ $this, 'clear_scheduled_rating' ] );
136 add_action( 'admin_post_imagify_deactivate_plugin', [ $this, 'deactivate_plugin' ] );
137 add_action( 'imagify_not_almost_over_quota_anymore', [ $this, 'renew_almost_over_quota_notice' ] );
138 }
139
140
141 /** ----------------------------------------------------------------------------------------- */
142 /** HOOKS =================================================================================== */
143 /** ----------------------------------------------------------------------------------------- */
144
145 /**
146 * Maybe display some notices.
147 *
148 * @since 1.6.10
149 */
150 public function render_notices() {
151 foreach ( $this->get_notice_ids() as $notice_id ) {
152 // Get the name of the method that will tell if this notice should be displayed.
153 $callback = 'display_' . str_replace( '-', '_', $notice_id );
154
155 if ( ! method_exists( $this, $callback ) ) {
156 continue;
157 }
158
159 $data = call_user_func( [ $this, $callback ] );
160
161 if ( $data ) {
162 // The notice must be displayed: render the view.
163 \Imagify_Views::get_instance()->print_template( 'notice-' . $notice_id, $data );
164 }
165 }
166
167 // Temporary notices.
168 $this->render_temporary_notices();
169 }
170
171 /**
172 * Process a dismissed notice.
173 *
174 * @since 1.6.10
175 * @see _do_admin_post_imagify_dismiss_notice()
176 */
177 public function admin_post_dismiss_notice() {
178 imagify_check_nonce( self::DISMISS_NONCE_ACTION );
179
180 $notice = ! empty( $_GET['notice'] ) ? esc_html( wp_unslash( $_GET['notice'] ) ) : false;
181 $notices = $this->get_notice_ids();
182 $notices = array_flip( $notices );
183
184 if ( ! $notice || ! isset( $notices[ $notice ] ) || ! $this->user_can( $notice ) ) {
185 imagify_die();
186 }
187
188 self::dismiss_notice( $notice );
189
190 /**
191 * Fires when a notice is dismissed.
192 *
193 * @since 1.4.2
194 *
195 * @param int $notice The notice slug
196 */
197 do_action( 'imagify_dismiss_notice', $notice );
198
199 imagify_maybe_redirect();
200 wp_send_json_success();
201 }
202
203 /**
204 * Stop the rating cron when the notice is dismissed.
205 *
206 * @since 1.6.10
207 * @see _imagify_clear_scheduled_rating()
208 *
209 * @param string $notice The notice name.
210 */
211 public function clear_scheduled_rating( $notice ) {
212 if ( 'rating' === $notice ) {
213 set_site_transient( 'do_imagify_rating_cron', 'no' );
214 \Imagify_Cron_Rating::get_instance()->unschedule_event();
215 }
216 }
217
218 /**
219 * Disable a plugin which can be in conflict with Imagify.
220 *
221 * @since 1.6.10
222 * @see _imagify_deactivate_plugin()
223 */
224 public function deactivate_plugin() {
225 imagify_check_nonce( self::DEACTIVATE_PLUGIN_NONCE_ACTION );
226
227 if ( empty( $_GET['plugin'] ) || ! $this->user_can( 'plugins-to-deactivate' ) ) {
228 imagify_die();
229 }
230
231 $plugin = esc_html( wp_unslash( $_GET['plugin'] ) );
232 $plugins = $this->get_conflicting_plugins();
233 $plugins = array_flip( $plugins );
234
235 if ( empty( $plugins[ $plugin ] ) ) {
236 imagify_die();
237 }
238
239 deactivate_plugins( $plugin );
240
241 imagify_maybe_redirect();
242 wp_send_json_success();
243 }
244
245 /**
246 * Renew the "almost-over-quota" notice when the consumed quota percent decreases back below 80%.
247 *
248 * @since 1.7
249 */
250 public function renew_almost_over_quota_notice() {
251 global $wpdb;
252
253 $results = $wpdb->get_results( $wpdb->prepare( "SELECT umeta_id, user_id FROM $wpdb->usermeta WHERE meta_key = %s AND meta_value LIKE %s", self::DISMISS_META_NAME, '%almost-over-quota%' ) );
254
255 if ( ! $results ) {
256 return;
257 }
258
259 // Prevent multiple queries to the DB by caching user metas.
260 $not_cached = [];
261
262 foreach ( $results as $result ) {
263 if ( ! wp_cache_get( $result->umeta_id, 'user_meta' ) ) {
264 $not_cached[] = $result->umeta_id;
265 }
266 }
267
268 if ( $not_cached ) {
269 update_meta_cache( 'user', $not_cached );
270 }
271
272 // Renew the notice for all users.
273 foreach ( $results as $result ) {
274 self::renew_notice( 'almost-over-quota', $result->user_id );
275 }
276 }
277
278
279 /** ----------------------------------------------------------------------------------------- */
280 /** NOTICES ================================================================================= */
281 /** ----------------------------------------------------------------------------------------- */
282
283 /**
284 * Tell if the 'welcome-steps' notice should be displayed.
285 *
286 * @since 1.6.10
287 *
288 * @return bool
289 */
290 public function display_welcome_steps() {
291 static $display;
292
293 if ( isset( $display ) ) {
294 return $display;
295 }
296
297 $display = false;
298
299 if ( ! $this->user_can( 'welcome-steps' ) ) {
300 return $display;
301 }
302
303 if ( imagify_is_screen( 'imagify-settings' ) ) {
304 return $display;
305 }
306
307 if ( self::notice_is_dismissed( 'welcome-steps' ) || get_imagify_option( 'api_key' ) ) {
308 return $display;
309 }
310
311 $display = true;
312 return $display;
313 }
314
315 /**
316 * Tell if the 'wrong-api-key' notice should be displayed.
317 *
318 * @since 1.6.10
319 *
320 * @return bool
321 */
322 public function display_wrong_api_key() {
323 static $display;
324
325 if ( isset( $display ) ) {
326 return $display;
327 }
328
329 $display = false;
330
331 if ( ! $this->user_can( 'wrong-api-key' ) ) {
332 return $display;
333 }
334
335 if ( ! imagify_is_screen( 'bulk' ) ) {
336 return $display;
337 }
338
339 if ( self::notice_is_dismissed( 'wrong-api-key' ) || ! get_imagify_option( 'api_key' ) || \Imagify_Requirements::is_api_key_valid() ) {
340 return $display;
341 }
342
343 $display = true;
344 return $display;
345 }
346
347 /**
348 * Tell if the 'plugins-to-deactivate' notice should be displayed.
349 *
350 * @since 1.6.10
351 *
352 * @return array An array of plugins to deactivate.
353 */
354 public function display_plugins_to_deactivate() {
355 static $display;
356
357 if ( isset( $display ) ) {
358 return $display;
359 }
360
361 if ( ! $this->user_can( 'plugins-to-deactivate' ) ) {
362 $display = false;
363 return $display;
364 }
365
366 $display = $this->get_conflicting_plugins();
367 return $display;
368 }
369
370 /**
371 * Tell if the 'plugins-to-deactivate' notice should be displayed.
372 *
373 * @since 1.6.10
374 *
375 * @return bool
376 */
377 public function display_http_block_external() {
378 static $display;
379
380 if ( isset( $display ) ) {
381 return $display;
382 }
383
384 $display = false;
385
386 if ( ! $this->user_can( 'http-block-external' ) ) {
387 return $display;
388 }
389
390 if ( imagify_is_screen( 'imagify-settings' ) ) {
391 return $display;
392 }
393
394 if ( self::notice_is_dismissed( 'http-block-external' ) || ! \Imagify_Requirements::is_imagify_blocked() ) {
395 return $display;
396 }
397
398 $display = true;
399 return $display;
400 }
401
402 /**
403 * Tell if the 'grid-view' notice should be displayed.
404 *
405 * @since 1.6.10
406 *
407 * @return bool
408 */
409 public function display_grid_view() {
410 global $wp_version;
411 static $display;
412
413 if ( isset( $display ) ) {
414 return $display;
415 }
416
417 $display = false;
418
419 if ( ! $this->user_can( 'grid-view' ) ) {
420 return $display;
421 }
422
423 if ( ! imagify_is_screen( 'library' ) ) {
424 return $display;
425 }
426
427 $media_library_mode = get_user_option( 'media_library_mode', get_current_user_id() );
428
429 if ( 'list' === $media_library_mode || self::notice_is_dismissed( 'grid-view' ) || version_compare( $wp_version, '4.0' ) < 0 ) {
430 return $display;
431 }
432
433 // Don't display the notice if the API key isn't valid.
434 if ( ! \Imagify_Requirements::is_api_key_valid() ) {
435 return $display;
436 }
437
438 $display = true;
439 return $display;
440 }
441
442 /**
443 * Tell if the 'almost-over-quota' notice should be displayed.
444 *
445 * @since 1.7.0
446 *
447 * @return bool|object An Imagify user object. False otherwise.
448 */
449 public function display_almost_over_quota() {
450 static $display;
451
452 if ( isset( $display ) ) {
453 return $display;
454 }
455
456 $display = false;
457
458 if ( ! $this->user_can( 'almost-over-quota' ) ) {
459 return $display;
460 }
461
462 if ( ! imagify_is_screen( 'imagify-settings' ) && ! imagify_is_screen( 'bulk' ) ) {
463 return $display;
464 }
465
466 if ( self::notice_is_dismissed( 'almost-over-quota' ) ) {
467 return $display;
468 }
469
470 $user = new \Imagify_User();
471
472 // Don't display the notice if the user's unconsumed quota is superior to 20%.
473 if ( $user->get_percent_unconsumed_quota() > 20 ) {
474 return $display;
475 }
476
477 $display = $user;
478 return $display;
479 }
480
481 /**
482 * Tell if the 'backup-folder-not-writable' notice should be displayed.
483 *
484 * @since 1.6.10
485 *
486 * @return bool
487 */
488 public function display_backup_folder_not_writable() {
489 static $display;
490
491 if ( isset( $display ) ) {
492 return $display;
493 }
494
495 $display = false;
496
497 if ( ! $this->user_can( 'backup-folder-not-writable' ) ) {
498 return $display;
499 }
500
501 // Every places where images can be optimized, automatically or not (+ the settings page).
502 if ( ! imagify_is_screen( 'imagify-settings' ) && ! imagify_is_screen( 'library' ) && ! imagify_is_screen( 'upload' ) && ! imagify_is_screen( 'bulk' ) && ! imagify_is_screen( 'media-modal' ) ) {
503 return $display;
504 }
505
506 if ( ! get_imagify_option( 'backup' ) ) {
507 return $display;
508 }
509
510 if ( \Imagify_Requirements::attachments_backup_dir_is_writable() ) {
511 return $display;
512 }
513
514 $display = true;
515 return $display;
516 }
517
518 /**
519 * Tell if the 'rating' notice should be displayed.
520 *
521 * @since 1.6.10
522 *
523 * @return bool|int
524 */
525 public function display_rating() {
526 static $display;
527
528 if ( isset( $display ) ) {
529 return $display;
530 }
531
532 $display = false;
533
534 if ( ! $this->user_can( 'rating' ) ) {
535 return $display;
536 }
537
538 if ( ! imagify_is_screen( 'bulk' ) && ! imagify_is_screen( 'library' ) && ! imagify_is_screen( 'upload' ) ) {
539 return $display;
540 }
541
542 if ( self::notice_is_dismissed( 'rating' ) ) {
543 return $display;
544 }
545
546 $user_images_count = (int) get_site_transient( 'imagify_user_images_count' );
547
548 if ( ! $user_images_count || get_site_transient( 'imagify_seen_rating_notice' ) ) {
549 return $display;
550 }
551
552 $display = $user_images_count;
553 return $display;
554 }
555
556 /**
557 * Tell if the 'wp-rocket' notice should be displayed.
558 *
559 * @since 1.6.10
560 *
561 * @return bool
562 */
563 public function display_wp_rocket() {
564 static $display;
565
566 if ( isset( $display ) ) {
567 return $display;
568 }
569
570 $display = false;
571
572 if ( ! $this->user_can( 'wp-rocket' ) ) {
573 return $display;
574 }
575
576 if ( ! imagify_is_screen( 'bulk' ) ) {
577 return $display;
578 }
579
580 $plugins = get_plugins();
581
582 if ( isset( $plugins['wp-rocket/wp-rocket.php'] ) || self::notice_is_dismissed( 'wp-rocket' ) ) {
583 return $display;
584 }
585
586 $display = true;
587 return $display;
588 }
589
590 /**
591 * Tell if the bulk optimization complete notice should be displayed
592 *
593 * @since 2.1
594 *
595 * @return array
596 */
597 public function display_bulk_optimization_complete(): array {
598 if ( ! $this->user_can( 'bulk-optimization-complete' ) ) {
599 return [];
600 }
601
602 if ( imagify_is_screen( 'bulk' ) ) {
603 return [];
604 }
605
606 if ( self::notice_is_dismissed( 'bulk-optimization-complete' ) ) {
607 return [];
608 }
609
610 if ( false === get_transient( 'imagify_bulk_optimization_complete' ) ) {
611 return [];
612 }
613
614 $data = get_transient( 'imagify_bulk_optimization_result' );
615
616 if ( empty( $data ) ) {
617 return [];
618 }
619
620 $global_gain = $data['original_size'] - $data['optimized_size'];
621
622 $data['original_size'] = imagify_size_format( $data['original_size'], 2 );
623 $data['optimized_size'] = imagify_size_format( $global_gain, 2 );
624 $data['bulk_page_url'] = admin_url( 'upload.php?page=imagify-bulk-optimization' );
625
626 return $data;
627 }
628
629 /**
630 * Tell if the bulk optimization running notice should be displayed
631 *
632 * @since 2.1
633 *
634 * @return array
635 */
636 public function display_bulk_optimization_running(): array {
637 if ( ! $this->user_can( 'bulk-optimization-running' ) ) {
638 return [];
639 }
640
641 if ( imagify_is_screen( 'bulk' ) ) {
642 return [];
643 }
644
645 if ( self::notice_is_dismissed( 'bulk-optimization-running' ) ) {
646 return [];
647 }
648
649 $custom_folders = get_transient( 'imagify_custom-folders_optimize_running' );
650 $library_wp = get_transient( 'imagify_wp_optimize_running' );
651
652 if (
653 ! $custom_folders
654 &&
655 ! $library_wp
656 ) {
657 return [];
658 }
659
660 $data = [];
661
662 $data['bulk_page_url'] = admin_url( 'upload.php?page=imagify-bulk-optimization' );
663
664 return $data;
665 }
666
667 /** ----------------------------------------------------------------------------------------- */
668 /** TEMPORARY NOTICES ======================================================================= */
669 /** ----------------------------------------------------------------------------------------- */
670
671 /**
672 * Maybe display some notices.
673 *
674 * @since 1.7
675 */
676 protected function render_temporary_notices() {
677 if ( is_network_admin() ) {
678 $notices = $this->get_network_temporary_notices();
679 } else {
680 $notices = $this->get_site_temporary_notices();
681 }
682
683 if ( ! $notices ) {
684 return;
685 }
686
687 $views = \Imagify_Views::get_instance();
688
689 foreach ( $notices as $i => $notice_data ) {
690 $notices[ $i ]['type'] = ! empty( $notice_data['type'] ) ? $notice_data['type'] : 'error';
691 }
692
693 $views->print_template( 'notice-temporary', $notices );
694 }
695
696 /**
697 * Get temporary notices for the network.
698 *
699 * @since 1.7
700 *
701 * @return array
702 */
703 protected function get_network_temporary_notices() {
704 $notices = get_site_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME );
705
706 if ( false === $notices ) {
707 return [];
708 }
709
710 delete_site_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME );
711
712 return $notices && is_array( $notices ) ? $notices : [];
713 }
714
715 /**
716 * Create a temporary notice for the network.
717 *
718 * @since 1.7
719 *
720 * @param array|object|string $notice_data Some data, with the message to display.
721 */
722 public function add_network_temporary_notice( $notice_data ) {
723 $notices = get_site_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME );
724 $notices = is_array( $notices ) ? $notices : [];
725
726 if ( is_wp_error( $notice_data ) ) {
727 $notice_data = $notice_data->get_error_messages();
728 $notice_data = implode( '<br/>', $notice_data );
729 }
730
731 if ( is_string( $notice_data ) ) {
732 $notice_data = [
733 'message' => $notice_data,
734 ];
735 } elseif ( is_object( $notice_data ) ) {
736 $notice_data = (array) $notice_data;
737 }
738
739 if ( ! is_array( $notice_data ) || empty( $notice_data['message'] ) ) {
740 return;
741 }
742
743 $notices[] = $notice_data;
744
745 set_site_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME, $notices, 30 );
746 }
747
748 /**
749 * Get temporary notices for the current site.
750 *
751 * @since 1.7
752 *
753 * @return array
754 */
755 protected function get_site_temporary_notices() {
756 $notices = get_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME );
757
758 if ( false === $notices ) {
759 return [];
760 }
761
762 delete_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME );
763
764 return $notices && is_array( $notices ) ? $notices : [];
765 }
766
767 /**
768 * Create a temporary notice for the current site.
769 *
770 * @since 1.7
771 *
772 * @param array|string $notice_data Some data, with the message to display.
773 */
774 public function add_site_temporary_notice( $notice_data ) {
775 $notices = get_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME );
776 $notices = is_array( $notices ) ? $notices : [];
777
778 if ( is_string( $notice_data ) ) {
779 $notice_data = [
780 'message' => $notice_data,
781 ];
782 } elseif ( is_object( $notice_data ) ) {
783 $notice_data = (array) $notice_data;
784 }
785
786 if ( ! is_array( $notice_data ) || empty( $notice_data['message'] ) ) {
787 return;
788 }
789
790 $notices[] = $notice_data;
791
792 set_transient( self::TEMPORARY_NOTICES_TRANSIENT_NAME, $notices, 30 );
793 }
794
795
796 /** ----------------------------------------------------------------------------------------- */
797 /** PUBLIC TOOLS ============================================================================ */
798 /** ----------------------------------------------------------------------------------------- */
799
800 /**
801 * Renew a dismissed Imagify notice.
802 *
803 * @since 1.6.10
804 *
805 * @param string $notice A notice ID.
806 * @param int $user_id A user ID.
807 */
808 public static function renew_notice( $notice, $user_id = 0 ) {
809 $user_id = $user_id ? (int) $user_id : get_current_user_id();
810 $notices = get_user_meta( $user_id, self::DISMISS_META_NAME, true );
811 $notices = $notices && is_array( $notices ) ? array_flip( $notices ) : [];
812
813 if ( ! isset( $notices[ $notice ] ) ) {
814 return;
815 }
816
817 unset( $notices[ $notice ] );
818 $notices = array_flip( $notices );
819 $notices = array_filter( $notices );
820 $notices = array_values( $notices );
821
822 update_user_meta( $user_id, self::DISMISS_META_NAME, $notices );
823 }
824
825 /**
826 * Dismiss an Imagify notice.
827 *
828 * @since 1.6.10
829 * @see imagify_dismiss_notice()
830 *
831 * @param string $notice A notice ID.
832 * @param int $user_id A user ID.
833 */
834 public static function dismiss_notice( $notice, $user_id = 0 ) {
835 $user_id = $user_id ? (int) $user_id : get_current_user_id();
836 $notices = get_user_meta( $user_id, self::DISMISS_META_NAME, true );
837 $notices = $notices && is_array( $notices ) ? array_flip( $notices ) : [];
838
839 if ( isset( $notices[ $notice ] ) ) {
840 return;
841 }
842
843 $notices = array_flip( $notices );
844 $notices[] = $notice;
845 $notices = array_filter( $notices );
846 $notices = array_values( $notices );
847
848 update_user_meta( $user_id, self::DISMISS_META_NAME, $notices );
849 }
850
851 /**
852 * Tell if an Imagify notice is dismissed.
853 *
854 * @since 1.6.10
855 * @see imagify_notice_is_dismissed()
856 *
857 * @param string $notice A notice ID.
858 * @param int $user_id A user ID.
859 * @return bool
860 */
861 public static function notice_is_dismissed( $notice, $user_id = 0 ) {
862 $user_id = $user_id ? (int) $user_id : get_current_user_id();
863 $notices = get_user_meta( $user_id, self::DISMISS_META_NAME, true );
864 $notices = $notices && is_array( $notices ) ? array_flip( $notices ) : [];
865
866 return isset( $notices[ $notice ] );
867 }
868
869 /**
870 * Tell if one or more notices will be displayed later in the page.
871 *
872 * @since 1.6.10
873 *
874 * @return bool
875 */
876 public function has_notices() {
877 foreach ( self::$notice_ids as $notice_id ) {
878 $callback = 'display_' . str_replace( '-', '_', $notice_id );
879
880 if ( method_exists( $this, $callback ) && call_user_func( [ $this, $callback ] ) ) {
881 return true;
882 }
883 }
884
885 return false;
886 }
887
888
889 /** ----------------------------------------------------------------------------------------- */
890 /** INTERNAL TOOLS ========================================================================== */
891 /** ----------------------------------------------------------------------------------------- */
892
893 /**
894 * Get all notice IDs.
895 *
896 * @since 1.6.10
897 * @since 1.10 Cast return value to array.
898 *
899 * @return array The filtered notice ids.
900 */
901 protected function get_notice_ids() {
902 /**
903 * Filter the notices Imagify can display.
904 *
905 * @since 1.6.10
906 *
907 * @param array $notice_ids An array of notice "IDs".
908 */
909 return (array) apply_filters( 'imagify_notices', self::$notice_ids );
910 }
911
912 /**
913 * Tell if the current user can see the notices.
914 * Notice IDs that are not listed in self::$capabilities are assumed as 'manage'.
915 *
916 * @since 1.6.10
917 *
918 * @param string $notice_id A notice ID.
919 * @return bool
920 */
921 protected function user_can( $notice_id ) {
922 $capability = isset( self::$capabilities[ $notice_id ] ) ? self::$capabilities[ $notice_id ] : 'manage';
923
924 return imagify_get_context( 'wp' )->current_user_can( $capability );
925 }
926
927 /**
928 * Get a list of plugins that can conflict with Imagify.
929 *
930 * @since 1.6.10
931 *
932 * @return array
933 */
934 protected function get_conflicting_plugins() {
935 /**
936 * Filter the recommended plugins to deactivate to prevent conflicts.
937 *
938 * @since 1.0
939 *
940 * @param string $plugins List of recommended plugins to deactivate.
941 */
942 $plugins = apply_filters( 'imagify_plugins_to_deactivate', self::$conflicting_plugins );
943
944 return array_filter( $plugins, 'is_plugin_active' );
945 }
946 }
947