<?php
namespace Duplicator\Core\Notifications;
class Notice
{
/**
* Not dismissible.
*
* Constant attended to use as the value of the $args['dismiss'] argument.
* DISMISS_NONE means that the notice is not dismissible.
*/
const DISMISS_NONE = 0;
/**
* Dismissible global.
*
* Constant attended to use as the value of the $args['dismiss'] argument.
* DISMISS_GLOBAL means that the notice will have the dismiss button, and after clicking this button, the notice will be dismissed for all users.
*/
const DISMISS_GLOBAL = 1;
/**
* Dismissible per user.
*
* Constant attended to use as the value of the $args['dismiss'] argument.
* DISMISS_USER means that the notice will have the dismiss button, and after clicking this button, the notice will be dismissed only for the current user..
*/
const DISMISS_USER = 2;
/**
* Constant for notice type info with gray left border
*/
const NOTICE_TYPE_INFO = 'info';
/**
* Constant for notice type warning with yellow left border
*/
const NOTICE_TYPE_WARNING = 'warning';
/**
* Constant for notice type warning with red left border
*/
const NOTICE_TYPE_ERROR = 'error';
/**
* Constant for notice type warning with green left border
*/
const NOTICE_TYPE_SUCCESS = 'success';
/**
* Constant for notice id default prefix
*/
const DEFAULT_PREFIX = 'dup-notice-';
/**
* Constant for addition notice id prefix in case it's a global notice
*/
const GLOBAL_PREFIX = 'global-';
/**
* The wp-options key in which the notices are stored
*/
const DISMISSED_NOTICES_OPTKEY = 'duplicator_dismissed_admin_notices';
/**
* Notices.
*
* @var array
*/
private static $notices = array();
/**
* Init.
*
* @return void
*/
public static function init()
{
static::hooks();
}
/**
* Hooks.
*
* @return void
*/
public static function hooks()
{
add_action('admin_notices', array(__CLASS__, 'display'), PHP_INT_MAX);
add_action('wp_ajax_dup_notice_dismiss', array(__CLASS__, 'dismissAjax'));
}
/**
* Enqueue assets.
*
* @return void
*/
private static function enqueues()
{
wp_enqueue_script(
'dup-admin-notices',
DUPLICATOR_PLUGIN_URL . "assets/js/notifications/notices.js",
array('jquery'),
DUPLICATOR_VERSION,
true
);
wp_localize_script(
'dup-admin-notices',
'dup_admin_notices',
array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('duplicator-admin-notice'),
)
);
}
/**
* Display the notices.
*
* @return void
*/
public static function display()
{
$dismissed_notices = get_user_meta(get_current_user_id(), self::DISMISSED_NOTICES_OPTKEY, true);
$dismissed_notices = is_array($dismissed_notices) ? $dismissed_notices : array();
$dismissed_notices = array_merge($dismissed_notices, (array)get_option(self::DISMISSED_NOTICES_OPTKEY, array()));
foreach (self::$notices as $slug => $notice) {
if (isset($dismissed_notices[$slug])) {
unset(self::$notices[$slug]);
}
}
$output = implode('', self::$notices);
echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
// Enqueue script only when it's needed.
if (strpos($output, 'is-dismissible') !== false) {
self::enqueues();
}
}
/**
* Add notice to the registry.
*
* @param string $message Message to display.
* @param string $slug Unique slug identifying the notice
* @param string $type Type of the notice. Can be [ '' (default) | 'info' | 'error' | 'success' | 'warning' ].
* @param array $args The array of additional arguments. Please see the $defaults array below.
*
* @return void
*/
public static function add($message, $slug, $type = '', $args = array())
{
$defaults = array(
'dismiss' => self::DISMISS_NONE, // Dismissible level: one of the self::DISMISS_* const. By default notice is not dismissible.
'autop' => true, // `false` if not needed to pass message through wpautop().
'class' => '' // Additional CSS class.
);
$args = wp_parse_args($args, $defaults);
$dismiss = (int)$args['dismiss'];
$classes = array();
if (!empty($type)) {
$classes[] = 'notice-' . esc_attr(sanitize_key($type));
}
if (!empty($args['class'])) {
$classes[] = esc_attr(sanitize_key($args['class']));
}
if ($dismiss > self::DISMISS_NONE) {
$classes[] = 'is-dismissible';
}
$id = $dismiss === self::DISMISS_GLOBAL ? self::DEFAULT_PREFIX . self::GLOBAL_PREFIX . $slug : self::DEFAULT_PREFIX . $slug;
$message = $args['autop'] ? wpautop($message) : $message;
$notice = sprintf(
'<div class="notice dup-notice %s" id="%s">%s</div>',
esc_attr(implode(' ', $classes)),
esc_attr($id),
$message
);
self::$notices[$slug] = $notice;
}
/**
* Add multistep notice.
*
* @param array $steps Array of info for each step.
* @param string $slug Unique slug identifying the notice
* @param string $type Type of the notice. Can be [ '' (default) | 'info' | 'error' | 'success' | 'warning' ].
* @param array $args Array of additional arguments. Details in the self::add() method.
*
* @return void
*/
public static function addMultistep($steps, $slug, $type = '', $args = array())
{
$content = '<div class="dup-multi-notice">';
foreach ($steps as $i => $step) {
$hide = $i === 0 ? '' : ' style="display: none;"';
$content .= '<div class="dup-multi-notice-step dup-multi-notice-step-' . $i . '"' . $hide . '>';
$content .= $step['message'];
$content .= "<p>";
foreach ($step["links"] as $link) {
$url = isset($link['url']) ? $link['url'] : "#";
$target = isset($link['url']) ? 'target="_blank"' : '';
$switch = isset($link['switch']) ? ' data-step="' . $link['switch'] . '"' : '';
$dismiss = isset($link['dismiss']) && $link['dismiss'] ? ' class="dup-notice-dismiss"' : '';
$content .= '<a href="' . $url . '"' . $dismiss . $switch . $target . '>' . $link['text'] . '</a><br>';
}
$content .= "</p>";
$content .= "</div>";
}
$content .= "</div>";
self::add($content, $slug, $type, $args);
}
/**
* Add info notice.
*
* @param string $message Message to display.
* @param string $slug Unique slug identifying the notice
* @param array $args Array of additional arguments. Details in the self::add() method.
*
* @return void
*/
public static function info($message, $slug, $args = array())
{
self::add($message, $slug, self::NOTICE_TYPE_INFO, $args);
}
/**
* Add error notice.
*
* @param string $message Message to display.
* @param string $slug Unique slug identifying the notice
* @param array $args Array of additional arguments. Details in the self::add() method.
*
* @return void
*/
public static function error($message, $slug, $args = array())
{
self::add($message, $slug, self::NOTICE_TYPE_ERROR, $args);
}
/**
* Add success notice.
*
* @param string $message Message to display.
* @param string $slug Unique slug identifying the notice
* @param array $args Array of additional arguments. Details in the self::add() method.
*
* @return void
*/
public static function success($message, $slug, $args = array())
{
self::add($message, $slug, self::NOTICE_TYPE_SUCCESS, $args);
}
/**
* Add warning notice.
*
* @param string $message Message to display.
* @param string $slug Unique slug identifying the notice
* @param array $args Array of additional arguments. Details in the self::add() method.
*
* @return void
*/
public static function warning($message, $slug, $args = array())
{
self::add($message, $slug, self::NOTICE_TYPE_WARNING, $args);
}
/**
* AJAX routine that updates dismissed notices meta data.
*
* @return void
*/
public static function dismissAjax()
{
// Run a security check.
check_ajax_referer('duplicator-admin-notice', 'nonce');
// Sanitize POST data.
$post = array_map('sanitize_key', wp_unslash($_POST));
// Update notices meta data.
if (strpos($post['id'], self::GLOBAL_PREFIX) !== false) {
// Check for permissions.
if (!current_user_can('manage_options')) {
wp_send_json_error();
}
$notices = self::dismissGlobal($post['id']);
$level = self::DISMISS_GLOBAL;
} else {
$notices = self::dismissUser($post['id']);
$level = self::DISMISS_USER;
}
/**
* Allows developers to apply additional logic to the dismissing notice process.
* Executes after updating option or user meta (according to the notice level).
*
* @param string $notice_id Notice ID (slug).
* @param integer $level Notice level.
* @param array $notices Dismissed notices.
*/
do_action('duplicator_admin_notice_dismiss_ajax', $post['id'], $level, $notices);
wp_send_json_success(
array(
'id' => $post['id'],
'time' => time(),
'level' => $level,
'notices' => $notices
)
);
}
/**
* AJAX sub-routine that updates dismissed notices option.
*
* @param string $id Notice Id.
*
* @return array Notices.
*/
private static function dismissGlobal($id)
{
$id = str_replace(self::GLOBAL_PREFIX, '', $id);
$notices = get_option(self::DISMISSED_NOTICES_OPTKEY, array());
$notices[$id] = array(
'time' => time()
);
update_option(self::DISMISSED_NOTICES_OPTKEY, $notices, true);
return $notices;
}
/**
* AJAX sub-routine that updates dismissed notices user meta.
*
* @param string $id Notice Id.
*
* @return array Notices.
*/
private static function dismissUser($id)
{
$user_id = get_current_user_id();
$notices = get_user_meta($user_id, self::DISMISSED_NOTICES_OPTKEY, true);
$notices = !is_array($notices) ? array() : $notices;
$notices[$id] = array(
'time' => time()
);
update_user_meta($user_id, self::DISMISSED_NOTICES_OPTKEY, $notices);
return $notices;
}
/**
* Delete related option
*
* @return void
*/
public static function deleteOption()
{
delete_option(self::DISMISSED_NOTICES_OPTKEY);
}
}
|