Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
/**
|
||||
* The Notification center handles notifications storage and display.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package RankMath
|
||||
* @subpackage RankMath
|
||||
* @author RankMath <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\Admin\Notifications;
|
||||
|
||||
/**
|
||||
* Notification_Center class.
|
||||
*/
|
||||
class Notification_Center {
|
||||
|
||||
/**
|
||||
* Option name to store notifications in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $storage_key = '';
|
||||
|
||||
/**
|
||||
* Notifications.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $notifications = [];
|
||||
|
||||
/**
|
||||
* Stores whether we need to clear storage or not.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $should_clear_storage = true;
|
||||
|
||||
/**
|
||||
* Stores already displayed notice texts to avoid duplication.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $displayed_notifications = [];
|
||||
|
||||
/**
|
||||
* Internal flag for whether notifications have been retrieved from storage.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $retrieved = false;
|
||||
|
||||
/**
|
||||
* Construct
|
||||
*
|
||||
* @param string $storage_key Option name to store notification in.
|
||||
*/
|
||||
public function __construct( $storage_key = 'mythemeshop_notifications' ) {
|
||||
$this->storage_key = $storage_key;
|
||||
add_action( 'plugins_loaded', [ $this, 'get_from_storage' ], 5 );
|
||||
add_action( 'all_admin_notices', [ $this, 'display' ] );
|
||||
add_action( 'shutdown', [ $this, 'update_storage' ] );
|
||||
add_action( 'admin_footer', [ $this, 'print_javascript' ] );
|
||||
|
||||
add_action( 'wp_ajax_wp_helpers_notice_dismissible', [ $this, 'notice_dismissible' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the notifications from storage
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return array Notification[] Notifications
|
||||
*/
|
||||
public function get_from_storage() {
|
||||
if ( $this->retrieved ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->retrieved = true;
|
||||
$notifications = get_option( $this->storage_key );
|
||||
|
||||
// Check if notifications are stored.
|
||||
if ( empty( $notifications ) ) {
|
||||
$this->should_clear_storage = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( is_array( $notifications ) ) {
|
||||
foreach ( $notifications as $notification ) {
|
||||
$this->notifications[] = new Notification(
|
||||
$notification['message'],
|
||||
$notification['options']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the notifications.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function display() {
|
||||
|
||||
// Never display notifications for network admin.
|
||||
if ( $this->is_network_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$notifications = $this->get_sorted_notifications();
|
||||
if ( empty( $notifications ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $notifications as $notification ) {
|
||||
if ( $notification->can_display() && ! in_array( (string) $notification, $this->displayed_notifications, true ) ) {
|
||||
echo $notification;
|
||||
$this->displayed_notifications[] = (string) $notification;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print JS for dismissile.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function print_javascript() {
|
||||
?>
|
||||
<script>
|
||||
;(function($) {
|
||||
$( '.wp-helpers-notice.is-dismissible' ).on( 'click', '.notice-dismiss', function() {
|
||||
var notice = $( this ).parent()
|
||||
|
||||
$.ajax({
|
||||
url: ajaxurl,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
action: 'wp_helpers_notice_dismissible',
|
||||
security: notice.data( 'security' ),
|
||||
notificationId: notice.attr( 'id' )
|
||||
}
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Save persistent or transactional notifications to storage.
|
||||
*
|
||||
* We need to be able to retrieve these so they can be dismissed at any time during the execution.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function update_storage() {
|
||||
$notifications = $this->get_notifications();
|
||||
$notifications = array_filter( $notifications, [ $this, 'remove_notification' ] );
|
||||
|
||||
/**
|
||||
* Filter: 'wp_helpers_notifications_before_storage' - Allows developer to filter notifications before saving them.
|
||||
*
|
||||
* @param Notification[] $notifications
|
||||
*/
|
||||
$notifications = apply_filters( 'wp_helpers_notifications_before_storage', $notifications );
|
||||
|
||||
// No notifications to store, clear storage.
|
||||
if ( empty( $notifications ) && $this->should_clear_storage ) {
|
||||
delete_option( $this->storage_key );
|
||||
return;
|
||||
}
|
||||
|
||||
$notifications = array_map( [ $this, 'notification_to_array' ], $notifications );
|
||||
|
||||
// Save the notifications to the storage.
|
||||
update_option( $this->storage_key, $notifications );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss persistent notice.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function notice_dismissible() {
|
||||
$notification_id = filter_input( INPUT_POST, 'notificationId' );
|
||||
check_ajax_referer( $notification_id, 'security' );
|
||||
|
||||
$notification = $this->remove_by_id( $notification_id );
|
||||
|
||||
/**
|
||||
* Filter: 'wp_helpers_notification_dismissed' - Allows developer to perform action after dismissed.
|
||||
*
|
||||
* @param Notification[] $notifications
|
||||
*/
|
||||
do_action( 'wp_helpers_notification_dismissed', $notification_id, $notification );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add notification
|
||||
*
|
||||
* @param string $message Message string.
|
||||
* @param array $options Set of options.
|
||||
*/
|
||||
public function add( $message, $options = [] ) {
|
||||
if ( isset( $options['id'] ) && ! is_null( $this->get_notification_by_id( $options['id'] ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->notifications[] = new Notification(
|
||||
$message,
|
||||
$options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a way to verify present notifications
|
||||
*
|
||||
* @return array|Notification[] Registered notifications.
|
||||
*/
|
||||
public function get_notifications() {
|
||||
return $this->notifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification by ID
|
||||
*
|
||||
* @param string $notification_id The ID of the notification to search for.
|
||||
* @return null|Notification
|
||||
*/
|
||||
public function get_notification_by_id( $notification_id ) {
|
||||
foreach ( $this->notifications as $notification ) {
|
||||
if ( $notification_id === $notification->args( 'id' ) ) {
|
||||
return $notification;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the notification by ID
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param string $notification_id The ID of the notification to search for.
|
||||
* @return Notification Instance of delete notification.
|
||||
*/
|
||||
public function remove_by_id( $notification_id ) {
|
||||
$notification = $this->get_notification_by_id( $notification_id );
|
||||
if ( ! is_null( $notification ) ) {
|
||||
$notification->dismiss();
|
||||
}
|
||||
|
||||
return $notification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove notification after it has been displayed.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Notification $notification Notification to remove.
|
||||
*/
|
||||
public function remove_notification( Notification $notification ) {
|
||||
if ( ! $notification->is_displayed() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $notification->is_persistent() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the notifications sorted on type and priority
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return array|Notification[] Sorted Notifications
|
||||
*/
|
||||
private function get_sorted_notifications() {
|
||||
$notifications = $this->get_notifications();
|
||||
if ( empty( $notifications ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Sort by severity, error first.
|
||||
usort( $notifications, [ $this, 'sort_notifications' ] );
|
||||
|
||||
return $notifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort on type then priority
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Notification $first Compare with B.
|
||||
* @param Notification $second Compare with A.
|
||||
* @return int 1, 0 or -1 for sorting offset.
|
||||
*/
|
||||
private function sort_notifications( Notification $first, Notification $second ) {
|
||||
|
||||
if ( 'error' === $first->args( 'type' ) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( 'error' === $second->args( 'type' ) ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Notification to array representation
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param Notification $notification Notification to convert.
|
||||
* @return array
|
||||
*/
|
||||
private function notification_to_array( Notification $notification ) {
|
||||
return $notification->to_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if is network admin.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_network_admin() {
|
||||
return function_exists( 'is_network_admin' ) && is_network_admin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a notification with the given ID exists.
|
||||
*
|
||||
* @param string $id Notification ID.
|
||||
* @return boolean
|
||||
*/
|
||||
public function has_notification( $id ) {
|
||||
$notifications = $this->get_notifications();
|
||||
foreach ( $notifications as $notification ) {
|
||||
if ( isset( $notification->options['id'] ) && $notification->options['id'] === $id ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
/**
|
||||
* The Notification
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @package RankMath
|
||||
* @subpackage RankMath
|
||||
* @author RankMath <support@rankmath.com>
|
||||
*/
|
||||
|
||||
namespace RankMath\Admin\Notifications;
|
||||
|
||||
use RankMath\Helpers\Str;
|
||||
use RankMath\Helpers\HTML;
|
||||
|
||||
/**
|
||||
* Notification class.
|
||||
*/
|
||||
class Notification {
|
||||
|
||||
/**
|
||||
* Notification type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const ERROR = 'error';
|
||||
|
||||
/**
|
||||
* Notification type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const SUCCESS = 'success';
|
||||
|
||||
/**
|
||||
* Notification type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const INFO = 'info';
|
||||
|
||||
/**
|
||||
* Notification type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const WARNING = 'warning';
|
||||
|
||||
/**
|
||||
* Screen check.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const SCREEN_ANY = 'any';
|
||||
|
||||
/**
|
||||
* User capability check.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CAPABILITY_ANY = '';
|
||||
|
||||
/**
|
||||
* The notification message.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $message = '';
|
||||
|
||||
/**
|
||||
* Contains optional arguments:
|
||||
*
|
||||
* - type: The notification type, i.e. 'updated' or 'error'
|
||||
* - id: The ID of the notification
|
||||
* - dismissal_key: Option name to save dismissal information in, ID will be used if not supplied.
|
||||
* - screen: Only display on plugin page or on every page.
|
||||
*
|
||||
* @var array Options of this Notification.
|
||||
*/
|
||||
public $options = [];
|
||||
|
||||
/**
|
||||
* Internal flag for whether notifications has been displayed.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $displayed = false;
|
||||
|
||||
/**
|
||||
* Notification class constructor.
|
||||
*
|
||||
* @param string $message Message string.
|
||||
* @param array $options Set of options.
|
||||
*/
|
||||
public function __construct( $message, $options = [] ) {
|
||||
$this->message = $message;
|
||||
$this->options = wp_parse_args(
|
||||
$options,
|
||||
[
|
||||
'id' => '',
|
||||
'classes' => '',
|
||||
'type' => self::SUCCESS,
|
||||
'screen' => self::SCREEN_ANY,
|
||||
'capability' => self::CAPABILITY_ANY,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds string (view) behaviour to the Notification.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
return $this->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return data from options.
|
||||
*
|
||||
* @param string $id Data to get.
|
||||
* @return mixed
|
||||
*/
|
||||
public function args( $id ) {
|
||||
return $this->options[ $id ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this Notification persistent.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return bool True if persistent, False if fire and forget.
|
||||
*/
|
||||
public function is_persistent() {
|
||||
return ! empty( $this->args( 'id' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this notification displayed.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_displayed() {
|
||||
return $this->displayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can display on current screen.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_display() {
|
||||
// Removed.
|
||||
if ( $this->displayed ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
if ( self::SCREEN_ANY === $this->args( 'screen' ) || Str::contains( $this->args( 'screen' ), $screen->id ) ) {
|
||||
$this->displayed = true;
|
||||
}
|
||||
|
||||
if ( self::CAPABILITY_ANY !== $this->args( 'capability' ) && ! current_user_can( $this->args( 'capability' ) ) ) {
|
||||
$this->displayed = false;
|
||||
}
|
||||
|
||||
return $this->displayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss persisten notification.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function dismiss() {
|
||||
$this->displayed = true;
|
||||
$this->options['id'] = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object properties as an array.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array() {
|
||||
return [
|
||||
'message' => $this->message,
|
||||
'options' => $this->options,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the notification as a string.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @return string The rendered notification.
|
||||
*/
|
||||
public function render() {
|
||||
$attributes = [];
|
||||
|
||||
// Default notification classes.
|
||||
$classes = [
|
||||
'notice',
|
||||
'notice-' . $this->args( 'type' ),
|
||||
$this->args( 'classes' ),
|
||||
];
|
||||
|
||||
// Maintain WordPress visualisation of alerts when they are not persistent.
|
||||
if ( $this->is_persistent() ) {
|
||||
$classes[] = 'is-dismissible';
|
||||
$classes[] = 'wp-helpers-notice';
|
||||
$attributes['id'] = $this->args( 'id' );
|
||||
$attributes['data-security'] = wp_create_nonce( $this->args( 'id' ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $classes ) ) {
|
||||
$attributes['class'] = implode( ' ', array_filter( $classes ) );
|
||||
}
|
||||
|
||||
// Build the output DIV.
|
||||
$output = '<div' . HTML::attributes_to_string( $attributes ) . '>' . wpautop( $this->message ) . '</div>' . PHP_EOL;
|
||||
|
||||
/**
|
||||
* Filter: 'wp_helpers_notifications_render' - Allows developer to filter notifications before the output is finalized.
|
||||
*
|
||||
* @param string $output HTML output.
|
||||
* @param array $message Notice message.
|
||||
* @param array $options Notice args.
|
||||
*/
|
||||
$output = apply_filters( 'wp_helpers_notifications_render', $output, $this->message, $this->options );
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user