507 lines
11 KiB
PHP
507 lines
11 KiB
PHP
<?php
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Notifications class.
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @package UserFeedback
|
|
* @author David Paternina
|
|
*/
|
|
class UserFeedback_Notifications {
|
|
|
|
|
|
/**
|
|
* Source of notifications content.
|
|
*
|
|
* @since 1.0.0
|
|
*
|
|
* @var string
|
|
*/
|
|
const REMOTE_SOURCE_URL = 'https://plugin.userfeedback.com/wp-content/notifications.json';
|
|
|
|
/**
|
|
* Option value.
|
|
*
|
|
* @since 1.0.0
|
|
* @var bool|array
|
|
*/
|
|
public $option = false;
|
|
|
|
/**
|
|
* The name of the option used to store the data.
|
|
*
|
|
* @since 1.0.0
|
|
* @var string
|
|
*/
|
|
public $option_name = 'userfeedback_notifications';
|
|
|
|
/**
|
|
*
|
|
*/
|
|
public function __construct() {
|
|
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
|
|
add_action( 'userfeedback_admin_notifications_update', array( $this, 'update_notifications' ) );
|
|
}
|
|
|
|
/**
|
|
* Register Ajax routes
|
|
*
|
|
* @return void
|
|
*/
|
|
public function register_routes() {
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/notifications',
|
|
array(
|
|
'methods' => 'GET',
|
|
'callback' => array( $this, 'get_notifications' ),
|
|
'permission_callback' => array( $this, 'notifications_permissions_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/notifications/(?P<id>\w+)/dismiss',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'dismiss_notification' ),
|
|
'permission_callback' => array( $this, 'notifications_permissions_check' ),
|
|
)
|
|
);
|
|
|
|
register_rest_route(
|
|
'userfeedback/v1',
|
|
'/notifications/action',
|
|
array(
|
|
'methods' => 'POST',
|
|
'callback' => array( $this, 'perform_notification_action' ),
|
|
'permission_callback' => array( $this, 'notifications_permissions_check' ),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
public function notifications_permissions_check() {
|
|
return current_user_can( 'userfeedback_create_edit_surveys' )
|
|
|| current_user_can( 'userfeedback_save_settings' );
|
|
}
|
|
|
|
/**
|
|
* Get notifications
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_notifications() {
|
|
|
|
do_action( 'userfeedback_run_notifications' );
|
|
|
|
return new WP_REST_Response(
|
|
array(
|
|
'notifications' => $this->get_active_notifications(),
|
|
'dismissed' => $this->get_dismissed_notifications(),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Dismiss a notification
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function dismiss_notification( WP_REST_Request $request ) {
|
|
$id = $request->get_param( 'id' );
|
|
|
|
if ( empty( $id ) ) {
|
|
return new WP_REST_Response( null, 422 );
|
|
}
|
|
|
|
$option = $this->get_option();
|
|
|
|
// Dismiss all notifications and add them to dismiss array.
|
|
if ( 'all' === $id ) {
|
|
|
|
$option['dismissed'] = array_merge(
|
|
$option['events'],
|
|
$option['feed'],
|
|
$option['dismissed']
|
|
);
|
|
|
|
$option['events'] = array();
|
|
$option['feed'] = array();
|
|
|
|
update_option( $this->option_name, $option, false );
|
|
|
|
return new WP_REST_Response( null, 204 );
|
|
}
|
|
|
|
$this->dismiss_notification_by_id( $id );
|
|
return new WP_REST_Response( null, 204 );
|
|
}
|
|
|
|
/**
|
|
* Dismiss notification by id
|
|
*
|
|
* @param $id
|
|
* @return void
|
|
*/
|
|
public function dismiss_notification_by_id( $id ) {
|
|
$option = $this->get_option();
|
|
|
|
$type = is_numeric( $id ) ? 'feed' : 'events';
|
|
|
|
// Remove notification and add in dismissed array.
|
|
if ( is_array( $option[ $type ] ) && ! empty( $option[ $type ] ) ) {
|
|
foreach ( $option[ $type ] as $key => $notification ) {
|
|
if ( $notification->id == $id ) { // phpcs:ignore WordPress.PHP.StrictComparisons
|
|
// Add notification to dismissed array.
|
|
array_unshift( $option['dismissed'], $notification );
|
|
// Remove notification from feed or events.
|
|
unset( $option[ $type ][ $key ] );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
update_option( $this->option_name, $option, false );
|
|
}
|
|
|
|
/**
|
|
* Trigger an action from a notification
|
|
*
|
|
* @param WP_REST_Request $request
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function perform_notification_action( WP_REST_Request $request ) {
|
|
$class = $request->get_param( 'class' );
|
|
$action = $request->get_param( 'action' );
|
|
|
|
// Check if class exists
|
|
if ( ! class_exists( $class ) ) {
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => false,
|
|
// translators: %s is the class name.
|
|
'message' => sprintf( __( 'Class %s does not exist.', 'userfeedback-lite' ), $class ),
|
|
),
|
|
404
|
|
);
|
|
}
|
|
|
|
$method_name = "perform_action_" . $action;
|
|
|
|
// Check if action method exists
|
|
if ( ! method_exists( $class, $method_name ) ) {
|
|
return new WP_REST_Response(
|
|
array(
|
|
'success' => false,
|
|
// translators: %1$s is the method name, %2$s is the class name.
|
|
'message' => sprintf( __( 'Method %1$s does not exist in class %2$s', 'userfeedback-lite' ), $method_name, $class ),
|
|
),
|
|
404
|
|
);
|
|
}
|
|
|
|
// Call action method in class
|
|
$class_instance = new $class();
|
|
$result = (method_exists($class_instance, $method_name)) ? $class_instance->$method_name() : array();
|
|
|
|
$result = array_merge(
|
|
array(
|
|
'success' => true,
|
|
),
|
|
$result
|
|
);
|
|
|
|
return new WP_REST_Response( $result, 200 );
|
|
}
|
|
|
|
// ----------------------
|
|
|
|
/**
|
|
* Verify notifications
|
|
*
|
|
* @param $notifications
|
|
* @return array|UserFeedback_Notification_External[]
|
|
*/
|
|
public function process_feed_notifications( $notifications ) {
|
|
$active_feed = array();
|
|
|
|
foreach ( $notifications as $raw_notification ) {
|
|
$notification = UserFeedback_Notification_External::make( $raw_notification );
|
|
if ( $notification->should_display() ) {
|
|
$active_feed[] = $notification;
|
|
}
|
|
}
|
|
|
|
return $active_feed;
|
|
}
|
|
|
|
/**
|
|
* Fetch remote notifications feed
|
|
*
|
|
* @return array
|
|
*/
|
|
public function fetch_feed() {
|
|
$res = wp_remote_get( self::REMOTE_SOURCE_URL );
|
|
|
|
if ( is_wp_error( $res ) ) {
|
|
return array();
|
|
}
|
|
|
|
$body = wp_remote_retrieve_body( $res );
|
|
|
|
if ( empty( $body ) ) {
|
|
return array();
|
|
}
|
|
|
|
return $this->process_feed_notifications( json_decode( $body, true ) );
|
|
}
|
|
|
|
/**
|
|
* Update notifications with remote feeds
|
|
*
|
|
* @return void
|
|
*/
|
|
public function update_notifications() {
|
|
$feed = $this->fetch_feed();
|
|
$option = $this->get_option();
|
|
|
|
update_option(
|
|
$this->option_name,
|
|
array(
|
|
'update' => time(),
|
|
'feed' => $feed,
|
|
'events' => $option['events'],
|
|
'dismissed' => array_slice( $option['dismissed'], 0, 30 ), // Limit dismissed notifications to last 30.
|
|
),
|
|
false
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get option value.
|
|
*
|
|
* @param bool $cache Reference property cache if available.
|
|
*
|
|
* @return array
|
|
* @since 1.0.0
|
|
*/
|
|
public function get_option( $cache = true ) {
|
|
|
|
if ( $this->option && $cache ) {
|
|
return $this->option;
|
|
}
|
|
|
|
$option = get_option( $this->option_name, array() );
|
|
|
|
$this->option = array(
|
|
'update' => ! empty( $option['update'] ) ? $option['update'] : 0,
|
|
'events' => ! empty( $option['events'] ) ? $option['events'] : array(),
|
|
'feed' => ! empty( $option['feed'] ) ? $option['feed'] : array(),
|
|
'dismissed' => ! empty( $option['dismissed'] ) ? $option['dismissed'] : array(),
|
|
);
|
|
|
|
return $this->option;
|
|
}
|
|
|
|
/**
|
|
* Get all notifications
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_all_notifications() {
|
|
$option = $this->get_option();
|
|
|
|
// Update notifications using async task.
|
|
if ( empty( $option['update'] ) || time() > $option['update'] + DAY_IN_SECONDS ) {
|
|
if ( false === wp_next_scheduled( 'userfeedback_admin_notifications_update' ) ) {
|
|
wp_schedule_single_event( time(), 'userfeedback_admin_notifications_update' );
|
|
}
|
|
}
|
|
|
|
$events = $option['events'];
|
|
$feed = $option['feed'];
|
|
|
|
return array(
|
|
'active' => array_merge( $events, $feed ),
|
|
'dismissed' => $option['dismissed'],
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get active notifications.
|
|
* Active notifications are limited to 5 at a time.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_active_notifications() {
|
|
$notifications = $this->get_all_notifications();
|
|
|
|
// Show only 5 active notifications plus any that has a priority of 1
|
|
$all_active = isset($notifications['active']) ? $notifications['active'] : array();
|
|
$displayed = array();
|
|
|
|
foreach ( $all_active as $notification ) {
|
|
if ( count( $displayed ) < 5 ) {
|
|
$displayed[] = $notification;
|
|
}
|
|
}
|
|
|
|
return $displayed;
|
|
}
|
|
|
|
/**
|
|
* Get dismissed notifications
|
|
*
|
|
* @return array|mixed
|
|
*/
|
|
public function get_dismissed_notifications() {
|
|
$notifications = $this->get_all_notifications();
|
|
|
|
return isset($notifications['dismissed']) ? $notifications['dismissed'] : array();
|
|
}
|
|
|
|
/**
|
|
* Get notifications count
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_notifications_count() {
|
|
return sizeof( $this->get_active_notifications() );
|
|
}
|
|
|
|
/**
|
|
* Get notifications badge for admin sidebar
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_count_for_admin_sidebar() {
|
|
$count = $this->get_notifications_count();
|
|
|
|
if ( ! $count ) {
|
|
return '';
|
|
}
|
|
|
|
return '<span class="userfeedback-notifications-indicator update-plugins">' . $count . '</span>';
|
|
}
|
|
|
|
/**
|
|
* Check if a notification has been dismissed before
|
|
*
|
|
* @param UserFeedback_Notification_Event $notification
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_dismissed( UserFeedback_Notification_Event $notification ) {
|
|
if ( empty( $notification->id ) ) {
|
|
return true;
|
|
}
|
|
|
|
$option = $this->get_option();
|
|
|
|
foreach ( $option['dismissed'] as $item ) {
|
|
if ( $item->id === $notification->id ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Perform last checks for a notification
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function verify_notification( UserFeedback_Notification_Event $notification ) {
|
|
if ( empty( $notification->id ) || $this->is_dismissed( $notification ) ) {
|
|
return false;
|
|
}
|
|
|
|
$option = $this->get_option();
|
|
|
|
// Ignore if notification has already been dismissed.
|
|
$notification_already_dismissed = false;
|
|
if ( is_array( $option['dismissed'] ) && ! empty( $option['dismissed'] ) ) {
|
|
foreach ( $option['dismissed'] as $dismiss_notification ) {
|
|
if ( $notification->id === $dismiss_notification->id ) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Add a manual notification event.
|
|
*
|
|
* @param UserFeedback_Notification_Event $notification Notification data.
|
|
*
|
|
* @return bool
|
|
* @since 1.0.0
|
|
*/
|
|
public function add( UserFeedback_Notification_Event $notification ) {
|
|
|
|
if ( ! $this->verify_notification( $notification ) ) {
|
|
return false;
|
|
}
|
|
|
|
$option = $this->get_option();
|
|
|
|
$current_notifications = $option['events'];
|
|
|
|
foreach ( $current_notifications as $item ) {
|
|
if ( $item->id === $notification->id ) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$notifications = array_merge( array( $notification ), $current_notifications );
|
|
|
|
// Sort notifications by priority
|
|
usort(
|
|
$notifications,
|
|
function( $a, $b ) {
|
|
if ( ! isset( $a->priority ) || ! isset( $b->priority ) ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( $a->priority == $b->priority ) {
|
|
return 0;
|
|
}
|
|
|
|
return $a->priority < $b->priority ? -1 : 1;
|
|
}
|
|
);
|
|
|
|
update_option(
|
|
$this->option_name,
|
|
array(
|
|
'update' => $option['update'],
|
|
'feed' => $option['feed'],
|
|
'events' => $notifications,
|
|
'dismissed' => $option['dismissed'],
|
|
),
|
|
false
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Delete the notification options.
|
|
*/
|
|
public function delete_notifications_data() {
|
|
delete_option( $this->option_name );
|
|
userfeedback_notification_event_runner()->delete_data();
|
|
}
|
|
}
|