File: /var/www/html/wp-content/plugins/wp-rss-aggregator/v4/includes/admin-ajax-notice.php
<?php
use Aventura\Wprss\Core\Model\AdminAjaxNotice\NoticeInterface;
use Aventura\Wprss\Core\Model\AdminAjaxNotice\ServiceProvider;
use Dhii\Di\WritableContainerInterface;
define ('WPRSS_NOTICE_SERVICE_ID_PREFIX', WPRSS_SERVICE_ID_PREFIX . 'notice.', false);
add_action( 'wp_ajax_wprss_hide_admin_notification', 'wprss_hide_admin_notification' );
/**
* JavaScript callback used to hide the administration notice when the 'Dismiss' anchor is clicked on the front end.
*
* @since 3.0
*/
function wprss_hide_admin_notification() {
// First, check the nonce to make sure it matches what we created when displaying the message.
// If not, we won't do anything.
if( wp_verify_nonce( $_REQUEST['nonce'], 'ajax-notification-nonce' ) ) {
// If the update to the option is successful, send 1 back to the browser;
// Otherwise, send 0.
$general_settings = get_option( 'wprss_settings_notices' );
$general_settings = true;
if( update_option( 'wprss_settings_notices', $general_settings ) ) {
die( '1' );
} else {
die( '0' );
}
}
}
/**
* Checks if the addon notices option exists in the database, and creates it
* if it does not.
*
* @return array The addon notices option
* @since 3.4.2
*/
function wprss_check_addon_notice_option() {
$option = get_option( 'wprss_addon_notices' );
if ( $option === FALSE ) {
update_option( 'wprss_addon_notices', array() );
return array();
}
return $option;
}
/**
* This function is called through AJAX to dismiss a particular addon notification.
*
* @since 3.4.2
*/
function wprss_dismiss_addon_notice() {
check_admin_referer('wprss_admin_addon_ajax');
$addon = isset($_POST['addon'])? $_POST['addon'] : null;
if ($addon === null) {
echo 'false';
die;
}
$addon = strip_tags($addon);
$notice = isset($_POST['notice'])? $_POST['notice'] : null;
if ($notice === null) {
echo 'false';
die;
}
$notices = wprss_check_addon_notice_option();
if (isset($notices[$addon])) {
$notices[$addon] = array();
}
if (isset($notices[$addon][$addon])) {
$notices[$addon][$notice] = '1';
}
update_option( 'wprss_addon_notices', $notices );
echo 'true';
die;
}
add_action( 'wp_ajax_wprss_dismiss_addon_notice', 'wprss_dismiss_addon_notice' );
/**
* Responsible for tracking and outputting admin notices
*
* Usage:
* Initialize by calling {@see init()} early, before `admin_init`. On `plugins_loaded`
* is a good place.
* Do not add notices conditionally. Instead, add them always, but specify
* the `condition` index to {@see add_notice()}.
*
* @since 4.7.4
*/
class WPRSS_Admin_Notices {
// How should a set of conditions be evaluated
const CONDITION_TYPE_ALL = 'all'; // Requires all conditions to be true
const CONDITION_TYPE_ANY = 'any'; // Requires one condition to be true
const CONDITION_TYPE_NONE = 'none'; // Requires none of the conditions to be true
const CONDITION_TYPE_ALMOST = 'almost'; // Requires at least one of the conditions to be false
// What happens if a condition encounters an error
// const CONDITION_ON_ERROR_STOP_FALSE = 'stop_false'; // Assume that the condition was not satisfied, and do not evaluate other conditions
// const CONDITION_ON_ERROR_STOP_TRUE = 'stop_true'; // Assume that the condition was satisfied, and do not evaluate other conditions
// const CONDITION_ON_ERROR_CONTINUE_FALSE = 'continue_false'; // Assume that the condition was not satisfied, and continue evaluating
// const CONDITION_ON_ERROR_CONTINUE_TRUE = 'continue_true'; // Assume that the condition was satisfied, and continue evaluating
const CONDITION_ON_ERROR_THROW_EXCEPTION = 'throw_exception'; // Just halt
protected $_notices = array();
protected $_setting_code;
protected $_id_prefix;
protected $_text_domain;
protected $_notice_base_class;
protected $_nonce_base_class;
protected $_btn_close_base_class;
protected $_dismiss_mode_class_prefix;
/**
*
* @since 4.7.4
* @param null|array The settings of this instance.
* Possible values are:
* - 'setting_code': The code of the database setting used for storing and managing notices of this instance.
* See {@link set_setting_code()}.
* If a string is passed as data, this is what it is assumed to be.
* - 'id_prefix': The prefix of all IDs generated by this instance.
* See {@link set_id_prefix()}.
* - 'text_domain': The text domain to use for translation.
* See {@link set_text_domain()}.
* - 'notice_base_class': The class for all notice elements.
* See {@link set_notice_base_class()}.
* - 'nonce_base_class': The class for all notice nonce elements.
* See {@link set_nonce_base_class()}.
*/
public function __construct( $data = array() ) {
if ( is_string( $data ) )
$data = array( 'setting_code' => $data );
if ( isset( $data['setting_code'] ) )
$this->set_setting_code ( $data['setting_code'] );
if ( isset( $data['id_prefix'] ) )
$this->set_id_prefix( $data['id_prefix'] );
if ( isset( $data['text_domain'] ) )
$this->set_text_domain( $data['text_domain'] );
// Common class for all notices
if ( !isset( $data['notice_base_class'] ) )
$data['notice_base_class'] = $this->prefix( 'admin-notice' );
$this->set_notice_base_class( $data['notice_base_class'] );
// Common class for all nonces
if ( !isset( $data['nonce_base_class'] ) )
$data['nonce_base_class'] = $this->prefix( 'admin-notice-nonce' );
$this->set_nonce_base_class( $data['nonce_base_class'] );
// Common class for all close buttons
if ( !isset( $data['btn_close_base_class'] ) )
$data['btn_close_base_class'] = $this->prefix( 'admin-notice-btn-close' );
$this->set_btn_close_base_class( $data['btn_close_base_class'] );
// Class prefix for dismiss mode
if ( !isset( $data['dismiss_mode_class_prefix'] ) )
$data['dismiss_mode_class_prefix'] = 'dismiss-mode-';
$this->set_dismiss_mode_class_prefix($data['dismiss_mode_class_prefix']);
$this->_construct();
}
/**
* Internal, parameter-less constructor.
*
* @since 4.7.4
*/
protected function _construct() {
}
/**
* Initializes the instance for use with WP.
*
* Essentially, this is what prepares it and hooks the handlers in.
*
* @since 4.7.4
* @uses-action admin_notice_before_init To expose the object before initialization
* @uses-action admin_notice_before_init To expose the object after initialization
* @return \WPRSS_Admin_Notices This instance.
*/
public function init() {
do_action( $this->prefix( 'admin_notice_before_init' ), $this );
add_action( 'admin_notices', array( $this, 'output_allowed_notices' ) );
do_action( $this->prefix( 'admin_notice_after_init' ), $this );
return $this;
}
/**
* Sets the prefix for dismiss mode class name.
*
* @since 4.11
*
* @param string $prefix The prefix.
* @return $this This instance.
*/
public function set_dismiss_mode_class_prefix($prefix) {
$this->_dismiss_mode_class_prefix = trim($prefix);
return $this;
}
/**
* Sets the prefix for dismiss mode class name.
*
* @since 4.11
*
* @return string The prefix.
*/
public function get_dismiss_mode_class_prefix() {
return $this->_dismiss_mode_class_prefix;
}
/**
* Get the ID prefix, or a prefixed string.
*
* This function is also used internally by this class to prefix generated
* IDs that are specific to this instance.
* Currently, this prefix is used in HTML of the notices, and in names
* of hooks.
*
* @param null|string $string The string to prefix.
* @return string The prefix, or prefixed string
*/
public function prefix( $string = null ) {
$prefix = (string)$this->_id_prefix;
return is_null( $string ) ? $prefix : $prefix . $string;
}
/**
* Sets a prefix that will be added to IDs specific to this collection.
*
* @since 4.7.4
* @param string $prefix The prefix to set.
* @return \WPRSS_Admin_Notices This instance.
*/
public function set_id_prefix( $prefix ) {
$this->_id_prefix = $prefix;
return $this;
}
/**
* Set the name of the setting to store the notices in.
*
* @since 4.7.4
* @see get_setting_name()
* @param string $name The name of the notices setting to use.
* @return \WPRSS_Admin_Notices This instance.
*/
public function set_setting_code( $name ) {
$this->_setting_code = $name;
return $this;
}
/**
* Get the name of the notices setting.
*
* @since 4.7.4
* @see set_setting_name()
* @return string The name of the setting which stores notices and their states.
*/
public function get_setting_name() {
return $this->_setting_code;
}
/**
* Retrieve the text domain that is used for translation by this instance.
*
* @since 4.7.4
* @return string The text domain.
*/
public function get_text_domain() {
return $this->_text_domain;
}
/**
* Set the text domain that is used for translation by this instance.
*
* @since 4.7.4
* @param string $text_domain The text domain.
* @return \WPRSS_Admin_Notices This instance.
*/
public function set_text_domain( $text_domain ) {
$this->_text_domain = $text_domain;
return $this;
}
/**
* Get the class that is the base, common class for all notices' top HTML elements.
*
* @since 4.7.4
* @uses-filter admin_notice_base_class To modify return value.
* @return string The class common to all notices
*/
public function get_notice_base_class() {
return apply_filters( $this->prefix( 'admin_notice_base_class' ), $this->_notice_base_class );
}
/**
* Set the class that will be the base, common class for all notices' top HTML elements.
*
* @since 4.7.4
* @param string $class The class name that will be common to all notices.
* @return \WPRSS_Admin_Notices This instance.
*/
public function set_notice_base_class( $class ) {
$this->_notice_base_class = $class;
return $this;
}
/**
* Get the class that is the base, common class for all notices' nonces' HTML elements.
*
* @since 4.7.4
* @uses-filter admin_notice_nonce_base_class To modify return value.
* @return string The class common to all nonces
*/
public function get_nonce_base_class() {
return apply_filters( $this->prefix( 'admin_notice_nonce_base_class' ), $this->_nonce_base_class );
}
/**
* Set the class that will be the base, common class for all notices' nonces' HTML elements.
*
* @since 4.7.4
* @param string $class The class name that will be common to all nonces.
* @return \WPRSS_Admin_Notices This instance.
*/
public function set_nonce_base_class( $class ) {
$this->_nonce_base_class = $class;
return $this;
}
/**
* Get the class that is the base, common class for all notices' close buttons' HTML elements.
*
* @since 4.7.4
* @uses-filter admin_notice_btn_close_base_class To modify return value.
* @return string The class common to all close buttons
*/
public function get_btn_close_base_class() {
return apply_filters( $this->prefix( 'admin_notice_btn_close_base_class' ), $this->_btn_close_base_class );
}
/**
* Set the class that will be the base, common class for all notices' close buttons' HTML elements.
*
* @since 4.7.4
* @param string $class The class name that will be common to close buttons.
* @return \WPRSS_Admin_Notices This instance.
*/
public function set_btn_close_base_class( $class ) {
$this->_btn_close_base_class = $class;
return $this;
}
/**
* Adds an admin notice.
*
* - If 'id' is not passed, a unique ID will be auto-generated.
* - If 'nonce' is not passed, a nonce will be auto-generated based on the ID.
* - A 'condition' is one or more callbacks. If none are passed, the notice will be displayed on all admin pages.
* - A 'condition_type' is one of the CONDITION_TYPE_* class constants. By default, all conditions have to be true.
* - The 'class' index determinces what type of notice it is. Currently, the valid values are 'updated', 'error' and 'update-nag'.
* See https://codex.wordpress.org/Plugin_API/Action_Reference/admin_notices
* - The 'content' index is the literal content of the notice.
* - If 'btn_close_id' is not passed, it will be auto-generated based on the ID.
* - The 'btn_close_class' index determines the class that the close button will have, in addition to the default 'btn-close'.
* - The 'btn_close_content' index determines the literal content of the element of the close button. HTML allowed.
*
* @since 4.7.4
* @uses-filter admin_notice_add_before_normalize To allow pre-normalization modification of notice.
* @uses-filter admin_notice_add_before To allow post-normalization modification of notice.
* @uses-action admin_notice_add_after To expose data of added notice. This will not be fired if notice was not added.
* @param array $notice Data of the notice to add.
* @return \WPRSS_Admin_Notices This instance.
*/
public function add_notice( $notice ) {
$notice = apply_filters( $this->prefix( 'admin_notice_add_before_normalize' ), $notice, $this );
$notice = $this->normalize_notice_data( $notice );
$notice = apply_filters( $this->prefix( 'admin_notice_add_before' ), $notice, $this );
$this->set_notice( $notice );
do_action( $this->prefix( 'admin_notice_add_after' ), $notice, $this );
return $this;
}
/**
* Sets the data for a notice with the specified ID.
*
* No normalization or checks are made, except for the presence of an ID.
*
* @since 4.7.4
* @uses-filter admin_notice_set_before To alter the data of the notice before setting.
* @uses-action admin_notice_set_after To expose the data of the notice after setting.
* @param array $notice Data of the notice.
* @param null|string $id The ID of the notice. If set, overrides 'id' index in notice data.
* @return \WPRSS_Admin_Notices This instance.
* @throws Exception If ID is missing.
*/
public function set_notice( $notice, $id = null ) {
$notice = apply_filters( $this->prefix( 'admin_notice_set_before' ), $notice, $id, $this );
$id = isset( $notice['id'] ) ? $notice['id'] : $id;
if ( is_null( $id ) )
throw new Exception( 'Could not set admin notice: ID must be specified in either notice data, or as separate argument' );
$this->_notices[ $id ] = $notice;
do_action( $this->prefix( 'admin_notice_set_after' ), $notice, $id, $this );
return $this;
}
/**
* Normalize data of a notice, adding defaults.
*
* Auto-generating 'id', 'nonce', 'btn_close_id', 'nonce_element_id', 'btn_close_id'.
*
* @since 4.7.4
* @uses-filter admin_notice_defaults Default values, before addin auto-generated values.
* @uses-filter admin_notice_defaults_autogenerated Default values, after adding auto-generated values.
* @param array $data The notice data to normalize
* @return array $data The normalized data of a notice
*/
public function normalize_notice_data( $data ) {
$data = wp_parse_args( $data, apply_filters( $this->prefix( 'admin_notice_defaults' ), array(
'id' => null, // ID of the notice. Unique for the notice in this collection.
'nonce' => null, // Nonce for the notice. Prevents unauthorised manipulation.
'condition' => array(), // These callbacks will decide whether or not the nonce is to be displayed
'condition_type' => self::CONDITION_TYPE_ALL, // Which of the conditions have to be satisfied
'conditon_on_error' => self::CONDITION_ON_ERROR_THROW_EXCEPTION,
'is_active' => true, // Whether this notice should be assumed to be active, unless set otherwise
'nonce_element_class' => $this->prefix( 'admin-notice-nonce' ), // HTML class for the element that contains the nonce
'nonce_element_id' => null,
'class' => '', // HTML class for the element of the notice
'notice_type' => 'updated', // Type of the notice.
'notice_element_class' => $this->prefix( 'admin-notice' ),
'content' => '', // The content of this notice
'btn_close_id' => null, // The HTML ID for the close button
'btn_close_class' => 'btn-close', // The HTML class for the close button, in addition to default
'btn_close_content' => __( 'Dismiss this notification', $this->get_text_domain() ), // The content of the close button. HTML allowed.
'dismiss_mode' => NoticeInterface::DISMISS_MODE_AJAX
)));
// Auto-generate ID
if ( is_null( $data['id'] ) )
$data['id'] = $this->generate_unique_id( 'admin-notice-', $data );
// Prefix ID
$data['id'] = $this->prefix( $data['id'] );
// Auto-generate nonce
if ( is_null( $data['nonce'] ) && !is_null( $data['id'] ) ) {
$me = $this;
$data['nonce'] = wprss()->getAdminHelper()->createCommand(function() use ($me, $data) {
$nonce = $me->generate_nonce_for_notice( $data['id'] );
return $nonce;
});
}
// Auto-generate nonce element ID
if ( is_null( $data['nonce_element_id'] ) && !is_null( $data['id'] ) )
$data['nonce_element_id'] = sprintf( '%1$s-nonce', $data['id'] );
// Auto-generate close button ID
if ( is_null( $data['btn_close_id'] ) && !is_null( $data['id'] ) )
$data['btn_close_id'] = sprintf( 'close-%1$s', $data['id'] );
return apply_filters( $this->prefix( 'admin_notice_defaults_autogenerated' ), $data );
}
/**
* Removes a notice from this collection.
*
* @since 4.7.4
* @uses-filter admin_notice_remove_before To modify the notice ID that will be removed. Returning falsy value prevents removal.
* @uses-action admin_notice_remove_after To expose notice ID after removal.
* @param array|int $notice A notice, or notice ID.
* @return \WPRSS_Admin_Notices This instance.
*/
public function remove_notice( $notice ) {
if ( is_array( $notice ) )
$notice = isset( $notice['id'] ) ? $notice['id'] : null;
if ( is_null( $notice ) )
return $this;
if ( !$this->has_notice( $notice ) )
return $this;
$notice = apply_filters( $this->prefix( 'admin_notice_remove_before' ), $notice, $this );
if( !$notice ) return $this;
$this->_remove_notice ( $notice, $this->_notices);
do_action( $this->prefix( 'admin_notice_remove_after' ), $notice, $this );
return $this;
}
/**
* Removes a notice by ID from the supplied array.
*
* @since 4.7.4
* @uses-filter admin_notice_internal_remove_before To modify notice before removal. Returning falsy value prevents removal.
* @uses-action admin_notice_internal_remove_after To expose data of notice after removal.
* @param array|string $notice A notice, or notice ID
* @param array $array The array, from which to remove the notice.
* @return \WPRSS_Admin_Notices This instance.
* @throws Exception If no ID specified.
*/
protected function _remove_notice( $notice, &$array = null ) {
if ( is_array( $notice ) )
$notice = isset( $notice['id'] ) ? $notice['id'] : null;
if ( is_null( $notice ) )
throw new Exception( 'Could not remove notice: an ID must be specified' );
if ( is_null( $array ) )
$array = &$this->_notices;
if ( !array_key_exists( $notice, $array ) )
return $this;
$notice = apply_filters( $this->prefix( 'admin_notice_internal_remove_before' ), $notice, $array, $this );
if ( !$notice ) return $this;
unset( $array[ $notice ] );
do_action( $this->prefix( 'admin_notice_internal_remove_after' ), $notice, $array, $this );
return $this;
}
/**
* Checks whether a notice already exists.
*
* @since 4.7.4
* @param array|int $notice A notice, or notice ID to check for.
* @return boolean True if notice already exists; false otherwise.
*/
public function has_notice( $notice ) {
if ( is_array( $notice ) )
$notice = isset( $notice['id'] ) ? $notice['id'] : null;
return array_key_exists( $notice , $this->_notices );
}
/**
* Get all notices, or a notice with the specified ID.
*
* @since 4.7.4
* @uses-filter admin_notice_get_all To modify all notices returned.
* @uses-filter admin_notice_get To modify single returned notice.
* @param null|string $id The ID of a notice to retrieve.
* @param null $default What to return if notice not found.
* @return array Retrieve all or one notice. See {@link normalize_notice_data()} for data keys.
*/
public function get_notices( $id = null, $default = null ) {
if ( is_null( $id ) )
return apply_filters( $this->prefix( 'admin_notice_get_all' ), $this->_notices, $this );
return apply_filters( $this->prefix( 'admin_notice_get' ),
isset( $this->_notices[ $id ] ) ? $this->_notices[ $id ] : $default,
$id,
$default,
$this );
}
/**
* Get all notices that are active.
*
* @since 4.7.4
* @see is_notice_active()
* @return array Notices that are currently active;
*/
public function get_active_notices( $is_default_active = null ) {
if ( is_null( $is_default_active ) )
$is_default_active = true;
$active_notices = array();
foreach ( $this->get_notices() as $_id => $_notice ) {
if ( $this->is_notice_active( $_notice, $is_default_active ) )
$active_notices[ $_id ] = $_notice;
}
return $active_notices;
}
/**
* Determine whether the specified notice is active.
*
* If data array is passed, it's 'is_active' key will be used as default.
* Otherwise, data will be retrieved by ID and compared to database.
*
* @since 4.7.4
* @uses-filter admin_notice_is_active To modify return value. Used in several places.
* @param array|string $notice Notice or notice ID.
* @param boolean $default What to return if no notice state data exists.
* @return boolean Whether or not the specified notice is active.
* @throws Exception If ID not specified.
*/
public function is_notice_active( $notice, $default = null ) {
// State if no state provided
if ( is_null( $default ) )
$default = true;
// If ID passed, retrieve the notice
if ( !is_array( $notice ) )
$notice = $this->get_notices( $notice, array() );
// Last resort defaults
$id = isset( $notice['id'] ) ? $notice['id'] : null;
$is_active_default = isset( $notice['is_active'] ) ? (bool)$notice['is_active'] : $default;
if ( is_null( $id ) )
throw new Exception( 'Could not determine notice state: ID must be specified' );
// Settings from DB
$settings = $this->get_notices_settings( $id );
// If no state, assume default
if ( !isset( $settings['is_active'] ) )
return apply_filters( $this->prefix( 'admin_notice_is_active' ), $is_active_default, $id, $this );
return apply_filters( $this->prefix( 'admin_notice_is_active' ), (bool)$settings['is_active'], $id, $this );
}
/**
* Set notice active state.
*
* @since 4.7.4
* @param array|string $notice Notice data or ID.
* @param null|boolean $is_active If true, notice state will be set to active; if false - to inactive. Default: true.
*/
public function set_notice_active( $notice, $is_active = null ) {
if ( is_null( $is_active ) )
$is_active = true;
$this->set_notices_settings( $notice, (bool)$is_active );
return $this;
}
/**
* Gets all notices that pass their conditions according to the condition type.
*
* Allowed notices are also only active ones. Inactive notices are not evaluated.
*
* @since 4.7.4
* @see is_notice_allowed()
* @uses-filter admin_notice_all_allowed To modify return value.
* @return array Allowed notices.
*/
public function get_allowed_notices() {
$allowed_notices = array();
foreach ( $this->get_active_notices() as $_id => $_notice ) {
if ( $this->is_notice_allowed( $_notice) )
$allowed_notices[ $_id ] = $_notice;
}
return apply_filters( $this->prefix( 'admin_notice_all_allowed' ), $allowed_notices, $this );
}
/**
* Checks if the specified notice is allowed.
*
* To determine that, the notice's conditions are evaluated according
* to the condition type.
*
* @since 4.7.4
* @uses-filter admin_notice_is_allowed To modify return value.
* @param array|string $notice Notice or notice ID.
* @return bool Whether or not the specified notice passed it's conditions to be allowed.
* @throws Exception If ID not specified.
*/
public function is_notice_allowed( $notice ) {
if ( !is_array( $notice ) )
$notice = $this->get_notices( $notice );
$conditions = isset( $notice['condition'] ) ? $notice['condition'] : array();
$condition_type = isset( $notice['condition_type'] ) ? $notice['condition_type'] : self::CONDITION_TYPE_ALL;
$is_allowed = $this->evaluate_conditions( $conditions, $condition_type, array( $notice ) );
return apply_filters( $this->prefix( 'admin_notice_is_allowed' ), $is_allowed, $notice );
}
/**
* Generates a nonce for a notice ID.
*
* @since 4.7.4
* @see wp_create_nonce()
* @see generate_nonce_code()
* @uses-filter admin_notice_nonce_for_notice
* @param array|string $notice Notice or notice ID.
* @return string The nonce.
* @throws Exception If ID not specified.
*/
public function generate_nonce_for_notice( $notice ) {
if ( is_array( $notice ) )
$notice = isset( $notice['id'] ) ? $notice['id'] : null;
if ( is_null( $notice ) )
throw new Exception( 'Could not get nonce for notice: notice ID must be specified' );
$nonce_code = $this->generate_nonce_code( $notice );
$nonce = wp_create_nonce( $nonce_code );
return apply_filters( $this->prefix( 'admin_notice_nonce_for_notice' ), $nonce, $notice, $nonce_code, $this );
}
/**
* Generates a code that is used to generate a nonce for a notice.
*
* @since 4.7.4
* @see wp_create_nonce()
* @see generate_nonce_for_notice()
* @uses-filter admin_notice_nonce_code To modify return value.
* @param array|string $notice Notice or notice ID;
* @return string Code (action) for the nonce.
* @throws Exception If nonce ID not specified.
*/
public function generate_nonce_code( $notice ) {
if ( is_array( $notice ) )
$notice = isset( $notice['id'] ) ? $notice['id'] : null;
if ( is_null( $notice ) )
throw new Exception( 'Could not generate nonce code for notice: notice ID must be specified' );
return apply_filters( $this->prefix( 'admin_notice_nonce_code' ), sprintf( '%1$s-nonce', $notice ), $notice, $this );
}
/**
* Evaluates a condition or group of conditions based on the condition type.
*
* A condition is a callable that returns true or false (no type checking is done here).
*
* @since 4.7.4
* @uses-filter admin_notice_conditions_evaluated To modify the return value.
* @uses-filter admin_notice_condition_result To alter the result of each condition's evaluated.
* @param array|callable $conditions A callable or an array of callables.
* @param string $condition_type One of the CONDITION_TYPE_* class constants. Default: CONDITION_TYPE_ALL.
* @param array $args These args will be passed to the condition callable.
* @return boolean Whether or not the conditions evaluate according to the condition type.
* @throws Exception If a condition cannot be called.
*/
public function evaluate_conditions( $conditions, $condition_type = self::CONDITION_TYPE_ALL, $args = array() ) {
$event_name = $this->prefix( 'admin_notice_conditions_evaluated' );
$result = true; // By default, evaluation passes
if ( empty( $conditions ) ) return apply_filters ( $event_name, $result, $condition_type, $this ); // Unconditional ;)
if ( !is_array( $conditions ) ) $conditions = array($conditions); // Normalizing
foreach ( $conditions as $_idx => $_condition ) {
$func = is_array( $_condition ) && isset( $_condition['func'] )
? $_condition['func']
: $_condition;
$args = array_merge( // Appending our args to the passed args
array_values( isset( $_condition['args'] ) ? (array)$_condition['args'] : array() ),
array_values( $args ));
if ( !is_callable( $func ) )
throw new Exception ( sprintf( 'Could not evaluate condition %1$d: condition must contain a callable', $_idx ) );
$_value = call_user_func_array( $func, $args );
$_value = apply_filters( $this->prefix( 'admin_notice_condition_result' ), $_value, $_idx, $condition_type, $_condition, $args, $this );
switch ( $condition_type ) {
case self::CONDITION_TYPE_ANY: // At least one must be true
if ( (bool)$_value ) return apply_filters ( $event_name, true, $condition_type, $this );
$result = false;
break;
case self::CONDITION_TYPE_ALMOST: // At least one must be false
if ( !(bool)$_value ) return apply_filters ( $event_name, true, $condition_type, $this );
$result = false;
break;
case self::CONDITION_TYPE_NONE: // All must be false
if ( (bool)$_value ) return apply_filters ( $event_name, false, $condition_type, $this );
$result = true;
break;
default:
case self::CONDITION_TYPE_ALL: // All must be true
if ( !(bool)$_value ) return apply_filters ( $event_name, false, $condition_type, $this );
$result = true;
break;
}
}
return apply_filters ( $event_name, $result, $condition_type, $this );
}
/**
* Get settings for all notices, or just one.
*
* It appears that options are already being cached by WP.
* Also, some notices in the returned array may not be registered for display,
* in which case they will not be displayed. And vice-versa: some of the registered
* notices will not have any settings associated with them, in which case
* defaults are assumed. See {@link is_notice_active()} for information.
* The settings contain states, not notice information.
*
* @since 4.7.4
* @uses-filter admin_notice_get_notices_settings_all To modify settings of all notices.
* @uses-filter admin_notice_get_notices_settings To modify settings of just one notice. May have been modified by admin_notice_get_notices_settings_all.
* @param null|string $id Notice ID
* @param null|mixed $default What to return if no settings for notice. Default: empty array.
* @return array An array, where key is notice ID, and value is boolean indicating whether or not it is active.
*/
public function get_notices_settings( $id = null, $default = null ) {
if( is_null( $default ) )
$default = array();
$settings = apply_filters( $this->prefix( 'admin_notice_get_notices_settings_all' ),
get_option( $this->get_setting_name(), array() ),
$this );
if ( is_null( $id ) )
return $settings;
// Normalize
$settings = isset( $settings[ $id ] ) ? $settings[ $id ] : $default;
$settings = $this->normalize_notice_data_from_db( $settings );
return apply_filters( $this->prefix( 'admin_notice_get_notices_settings' ),
$settings,
$id,
$default,
$this );
}
/**
*
*
* @since 4.7.4
* @uses-filter admin_notice_set_settings_before To modify what gets saved. Also see {@link prepare_notice_data_for_db()}.
* @uses-action admin_notice_set_settings_after To expose data that has been saved.
* @param string|array $notice The notice data, or notice ID, to save.
* @param null|array|boolean $settings The settings, or just the active state, to save.
* @return \WPRSS_Admin_Notices This instance.
* @throws Exception If an ID is nowhere to be found. How to save? :S
*/
public function set_notices_settings( $notice, $settings = null ) {
// Normalizing notice data
if ( !is_array( $notice ) )
$notice = array( 'id' => $notice );
// If using just the notice data to save everything
if ( is_null( $settings ) )
$settings = $notice;
// If saving just the active state
if ( is_bool( $settings ) )
$settings = array( 'is_active' => $settings );
// Making sure notice ID isn't overwritten
if( isset( $settings['id'] ) )
unset( $settings['id'] );
// Merging the data together to get all data to save
$settings = wp_parse_args( $settings, $notice );
// Making sure that an ID ultimately exists
if ( !isset( $settings['id'] ) )
throw new Exception( 'Could not set notice settings: ID must be specified' );
$id = $settings['id'];
$db_settings = $this->get_notices_settings( $id );
// Merge again to only update what is in the database
$settings = wp_parse_args( $settings, $db_settings );
// Get all settings data
$all_settings = $this->get_notices_settings();
// Set and finally save
$settings = apply_filters( $this->prefix( 'admin_notice_set_settings_before' ), $settings, $id, $this );
$settings = $this->prepare_notice_data_for_db( $settings );
$all_settings[ $id ] = $settings;
$this->set_notices_settings_all( $all_settings );
do_action( $this->prefix( 'admin_notice_set_settings_after' ), $settings, $id, $this );
return $this;
}
/**
* Saves the data of all specified notices to the database.
*
* The passed data will replace all data currently stored in the option.
*
* @since 4.7.4
* @see get_setting_name()
* @uses-filter admin_notice_set_settings_all_before To modify what gets saved.
* @uses-action admin_notice_set_settings_all_after To expose saved data.
* @param array $settings An array containing data of all notices.
* @return \WPRSS_Admin_Notices This instance.
*/
public function set_notices_settings_all( $settings ) {
$settings = apply_filters( $this->prefix( 'admin_notice_set_settings_all_before' ), $settings, $this );
update_option( $this->get_setting_name(), $settings );
do_action( $this->prefix( 'admin_notice_set_settings_all_after' ), $settings, $this );
return $this;
}
/**
* Normalize a single notice's data that was returned from the database.
*
* @since4.8.2
* @uses-filter admin_notice_normalize_notice_data_from_db To modify the return value.
* @param null|mixed|array $data The individual notice's data to normalize.
* @return array The notice data returned from the database.
*/
public function normalize_notice_data_from_db( $data ) {
if ( is_null( $data ) )
$data = array();
if ( !is_array( $data ) )
$data = array( 'is_active' => (bool)$data );
return apply_filters( $this->prefix( 'admin_notice_normalize_notice_data_from_db' ), $data, $this );
}
/**
* Prepares data of a single notice to be saved to the database.
*
* Is responsible for preserving only allowed fields, and adding some
* required ones, if necessary and possible.
*
* @since4.8.2
* @uses-filter admin_notice_prepare_notice_data_for_db To modify the resulting prepared data.
* @param array $data The data to prepare.
* @return array The data that should be saved to the database.
*/
public function prepare_notice_data_for_db( $data ) {
$prepared_data = array();
if ( isset( $data['is_active'] ) )
$prepared_data['is_active'] = (bool)$data['is_active'];
return apply_filters( $this->prefix( 'admin_notice_prepare_notice_data_for_db' ), $prepared_data, $data, $this );
}
/**
* Generates a unique ID.
*
* This ID will be unique to this collection.
*
* @since 4.7.4
* @see uniqid()
* @uses-filter admin_notice_generate_unique_id To allow modification of ID.
* @param string $prefix The prefix to give to the generated ID.
* @return string A notice ID unique to this instance in the scope of this collection.
*/
public function generate_unique_id( $prefix = '', $data = null ) {
do {
$id = is_null($data) ? uniqid( $prefix ) : $prefix . $this->hash($data);
} while ( $this->has_notice( $id ) );
return apply_filters( $this->prefix( 'admin_notice_generate_unique_id' ), $id, $prefix, $this );
}
public function hash($data) {
return md5(serialize($data));
}
/**
* Generate the HTML for all allowed notices, sequentially.
*
* @since 4.7.4
* @return string The rendered HTML.
*/
public function render_allowed_notices() {
$output = '';
foreach ( $this->get_allowed_notices() as $_id => $_notice ) {
$output .= $this->render_notice( $_notice );
}
return $output;
}
/**
* Directly output the rendered HTML of all allowed notices.
*
* @since 4.7.4
* @return \WPRSS_Admin_Notices This instance.
*/
public function output_allowed_notices() {
echo $this->render_allowed_notices();
return $this;
}
/**
* Generate the HTML of a notice.
*
* @since 4.7.4
* @uses-filter admin_notice_render_before To allow modification of notice data before rendering.
* @uses-action admin_notice_render_after To allow injection inside the notice HTML.
* @uses-filter admin_notice_rendered To allow modification of rendered HTML.
* @param array|string $id Notice, or notice ID.
* @return string The HTML output of the notice.
* @throws Exception If no notice found for ID.
*/
public function render_notice( $id ) {
$notice = is_array( $id )
? $id
: $this->get_notices( $id );
if ( !$notice )
throw new Exception( sprintf( 'Could not render notice: no notice found for ID "%1$s"', $id ) );
$helper = wprss()->getAdminHelper();
ob_start();
$notice = apply_filters( $this->prefix( 'admin_notice_render_before' ), $notice, $this );
$noticeId = esc_attr($notice['id']);
$content = $notice['content'];
$type = $notice['notice_type'];
$baseClass = $this->get_notice_base_class();
$elemClass = $notice['notice_element_class'];
$dismissMode = $notice['dismiss_mode'];
$fullClass = esc_attr("{$type} {$elemClass} {$baseClass} dismiss-mode-{$dismissMode}");
$nonce = $notice['nonce'];
$nonceId = esc_attr($notice['nonce_element_id']);
$nonceElemClass = $notice['nonce_element_class'];
$nonceBaseClass = $this->get_nonce_base_class();
$nonceFullClass = esc_attr("hidden {$nonceElemClass} {$nonceBaseClass}");
?>
<div id="<?= $noticeId ?>" class="<?= $fullClass ?>">
<div class="notice-inside">
<?= $content ?>
</div>
<?php if ($dismissMode !== NoticeInterface::DISMISS_MODE_NONE):
$btnId = esc_attr($notice['btn_close_id']);
$btnContent = $notice['btn_close_content'];
$btnElemClass = $notice['btn_close_class'];
$btnBaseClass = $this->get_btn_close_base_class();
$btnFullClass = esc_attr("{$btnBaseClass} {$btnElemClass}");
?>
<a href="javascript:void(0);" id="<?= $btnId ?>" style="float:right;" class="<?= $btnFullClass ?>">
<?= $btnContent ?>
</a>
<?php endif ?>
<span id="<?= $nonceId ?>" class="<?= $nonceFullClass ?>">
<?= $helper->resolveValue($nonce) ?>
</span>
</div>
<?php
do_action($this->prefix('admin_notice_render_after'), $notice, $this);
$output = ob_get_clean();
return apply_filters($this->prefix('admin_notice_rendered'), $output, $notice, $this);
}
/**
* Used to hide a notice, typically responding to a frontend event.
*
* @since 4.7.4
* @param array|string $notice Notice or notice ID.
* @param string $nonce The nonce from the frontend.
* @return \WPRSS_Admin_Notices This instance.
* @throws Exception If no notice ID specified, or no notice found for it,
* or specified nonce does not belong to the notice, or the nonce is not right.
*/
public function hide_notice( $notice, $nonce ) {
if ( is_array( $notice ) )
$notice = isset( $notice['id'] ) ? $notice['id'] : null;
$notice_id = $notice;
if ( is_null( $notice ) )
throw new Exception('Could not hide notice: Notice ID must be specified');
if ( is_null( $nonce ) )
throw new Exception('Could not hide notice: nonce must be specified');
if ( !($notice = $this->get_notices( $notice ) ) )
throw new Exception( sprintf( 'Could not hide notice: No notice found for ID "%1$s"', $notice_id ) );
// Is it the right nonce?
$noticeNonce = wprss()->getAdminHelper()->resolveValue($notice['nonce']);
if ( $noticeNonce !== $nonce )
throw new Exception( sprintf( 'Could not hide notice: Nonce "%1$s" does not belong to notice "%2$s"', $nonce, $notice_id ) );
// Verify nonce
if( !wp_verify_nonce( $nonce, $this->generate_nonce_code( $notice ) ) )
throw new Exception( sprintf( 'Could not hide notice: Nonce "%1$s" is incorrect', $nonce ) );
wprss_admin_notice_get_collection()->set_notice_active( $notice, false );
return $this;
}
}
// This should initialize the notice collection before anything can use it
add_action( 'init', 'wprss_admin_notice_get_collection', 9 );
// Trigger the component to initialize
add_action('wprss_pre_init', function() {
wprss_wp_container()->get(\WPRSS_SERVICE_ID_PREFIX.'admin_ajax_notices');
});
/**
* Returns the singleton, plugin-wide instane of the admin notices controller.
* Initializes it if necessary.
*
* @since 4.7.4
* @staticvar WPRSS_Admin_Notices $collection The singleton instance.
* @return \WPRSS_Admin_Notices|null The singleton instance of notice collection, or null if it is unavailable.
*/
function wprss_admin_notice_get_collection() {
static $collection = null;
if ( is_null( $collection ) && is_admin() ) {
$collection = wprss_wp_container()->get(\WPRSS_SERVICE_ID_PREFIX.'admin_ajax_notice_controller');
add_action( \WPRSS_EVENT_PREFIX.'admin_exclusive_scripts_styles', 'wprss_admin_notices_collection_enqueue_scripts' );
}
return $collection;
}
/**
* Enqueues the scripts for a notice collection.
*
* @since 4.7.8
*/
function wprss_admin_notices_collection_enqueue_scripts() {
$notices = wprss()->getAdminAjaxNotices();
$notices->_registerAssets();
$notices->enqueueAssets();
}
/**
* Centralizes access to the name of the AJAX action handler for dismissing admin notices.
*
* This is necessary for configuration of the frontend.
*
* @since 4.7.4
* @uses-filter wprss_admin_notice_action_code To modify return value.
* @return string The action code
*/
function wprss_admin_notice_get_action_code() {
return apply_filters( 'wprss_admin_notice_action_code', 'wprss_admin_notice_hide' );
}
/**
* Adds a notice to be displayed on top of an admin page.
*
* @since 4.7.4
* @param array $notice Data of the notice
* @return bool|WP_Error True if notice added, false if collection unavailable, or WP_Error if something went wrong.
*/
function wprss_admin_notice_add( $notice ) {
try {
if ( !($collection = wprss_admin_notice_get_collection()) )
return false;
$collection->add_notice( $notice );
} catch ( Exception $e ) {
return new WP_Error( 'could_not_add_admin_notice', $e->getMessage() );
}
return true;
}
add_action( sprintf( 'wp_ajax_%1$s', wprss_admin_notice_get_action_code() ), 'wprss_admin_notice_hide' );
/**
* This is what handles the AJAX action of dismissing admin notices.
*
* @see WPRSS_Admin_Notices::hide_notice()
* @since 4.7.4
*/
function wprss_admin_notice_hide() {
$notice_id = isset($_REQUEST['notice_id']) ? $_REQUEST['notice_id'] : null;
$notice_id = filter_var($notice_id, FILTER_DEFAULT);
$nonce = isset($_REQUEST['nonce']) ? $_REQUEST['nonce'] : null;
$nonce = filter_var($nonce, FILTER_DEFAULT);
try {
wprss_admin_notice_get_collection()->hide_notice($notice_id, $nonce);
} catch (Exception $e) {
// Failure
echo esc_html($e->getMessage());
exit();
}
// Success
exit('1');
}
/**
* Check whether the current page is related to WP RSS Aggregator.
*
* @since 4.7.4
* @uses-filter wprss_is_wprss_page To modify return value.
* @global string $typenow Post type of the current page.
* @return boolean True if the current page is a WPRSS-related page; false otherwise.
*/
function wprss_is_wprss_page() {
global $typenow;
if (!is_admin()) {
return false;
}
$postType = $typenow;
if ( empty( $postType ) && isset( $_GET['post'] ) && !empty( $_GET['post'] ) ) {
$post = get_post(filter_var($_GET['post'], FILTER_SANITIZE_NUMBER_INT));
if ( $post !== NULL && !is_wp_error( $post ) )
$postType = $post->post_type;
}
$filterFlags = FILTER_FLAG_STRIP_BACKTICK | FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH;
if (empty($postType) && isset($_GET['post_type'])) {
$postType = filter_var(trim($_GET['post_type']), FILTER_SANITIZE_STRING, $filterFlags);
}
$pagenow = isset($_GET['page']) ? filter_var($_GET['page'], FILTER_SANITIZE_STRING, $filterFlags) : null;
$wprss_post_types = apply_filters('wprss_post_types', array(
'wprss_feed',
'wprss_feed_item',
'wprss_blacklist',
));
$wprss_pages = apply_filters('wprss_page_slugs', array(
'wprss-aggregator',
'wprss-aggregator-settings',
'wprss-import-export-settings',
'wprss-debugging',
'wprss-addons',
'wprss-welcome',
'wprss-help',
'wpra-intro',
'wpra-update',
));
$is_wprss_post = in_array($postType, $wprss_post_types, true);
$is_wprss_page = in_array($pagenow, $wprss_pages, true);
return apply_filters( 'wprss_is_wprss_page', $is_wprss_post || $is_wprss_page );
}
/**
* Check whether the currently logged in user can manage WP options.
*
* This normally describes the administrator.
*
* @since 4.7.4
* @uses-filter wprss_user_can_manage_options To modify return value.
* @return bool True if the currently logged in user has the 'manage_options' privilege; false otherwise.
*/
function wprss_user_can_manage_options() {
return apply_filters( 'wprss_user_can_manage_options', current_user_can( 'manage_options' ) );
}
// Adds the AJAX notice service provider to the core container
add_filter(WPRSS_EVENT_PREFIX .'core_container_init', function(WritableContainerInterface $container) {
$noticeProvider = wprss_core_admin_ajax_notices_service_provider();
$container->register($noticeProvider);
});
/**
* Retrieves the service provider that provides notice service definitions.
*
* @since 4.11
*
* @staticvar ServiceProvider $provider
* @return ServiceProvider
*/
function wprss_core_admin_ajax_notices_service_provider()
{
static $provider = null;
if(is_null($provider)) {
$provider = new ServiceProvider(array(
'notice_service_id_prefix' => \WPRSS_NOTICE_SERVICE_ID_PREFIX,
'service_id_prefix' => \WPRSS_SERVICE_ID_PREFIX,
'event_prefix' => \WPRSS_EVENT_PREFIX,
));
}
return $provider;
}