get( 'Settings_Api' ); return current_user_can( $settings_api::get_capability() ) && ! $settings_api->get( 'hide-announcements' ); } /** * Register global assets. * * @since 1.7.3 */ public static function assets_global() { if ( ! self::has_access() ) { return; } if ( empty( self::get_count() ) ) { return; } wp_enqueue_style( 'searchwp-live-search-admin-notifications-global', SEARCHWP_LIVE_SEARCH_PLUGIN_URL . 'assets/styles/admin/notifications-global.css', [], SEARCHWP_LIVE_SEARCH_VERSION ); } /** * Register assets. * * @since 1.7.3 */ public static function assets() { if ( ! self::has_access() ) { return; } if ( ! Utils::is_settings_page() ) { return; } wp_enqueue_style( 'searchwp-live-search-admin-notifications', SEARCHWP_LIVE_SEARCH_PLUGIN_URL . 'assets/styles/admin/notifications.css', [], SEARCHWP_LIVE_SEARCH_VERSION ); wp_enqueue_script( 'searchwp-live-search-admin-notifications', SEARCHWP_LIVE_SEARCH_PLUGIN_URL . 'assets/js/admin/notifications.js', [], SEARCHWP_LIVE_SEARCH_VERSION ); Utils::localize_script( 'searchwp-live-search-admin-notifications' ); } /** * Add Notifications pseudo submenu item to the SearchWP admin menu. * * @since 1.7.3 * * @param array $submenu_pages List of registered SearchWP submenu pages. * * @return array */ public static function add_submenu_page( $submenu_pages ) { if ( ! self::has_access() ) { return $submenu_pages; } if ( empty( self::get_count() ) ) { return $submenu_pages; } $submenu_pages['notifications'] = [ 'menu_title' => esc_html__( 'Notifications', 'searchwp-live-ajax-search' ) . '', 'menu_slug' => SearchWP_Live_Search_Menu::MENU_SLUG . '#notifications', 'position' => 0, ]; return $submenu_pages; } /** * Hide a plugin setting to opt out of plugin notifications if SearchWP is active. * * @since 1.7.3 * * @param array $settings List of registered plugin settings. * * @return array */ public static function hide_opt_out_setting( $settings ) { if ( Utils::is_searchwp_active() ) { unset( $settings['misc-heading'], $settings['hide-announcements'] ); } return $settings; } /** * Output header action button. * * @since 1.7.3 */ public static function output_header_button() { $notifications = self::get(); ?>
$option['updated_at'] + ( 12 * HOUR_IN_SECONDS ) ) { self::save( self::fetch() ); $option = self::get_option( [ 'cache' => false ] ); // Make sure the notifications are available right away. } return ! empty( $option['notifications'] ) ? self::filter_active( $option['notifications'] ) : []; } /** * Get available notifications count. * * @since 1.7.3 * * @return int */ public static function get_count() { if ( ! self::has_access() ) { return 0; } return count( self::get() ); } /** * Fetch notifications from the remote server. * * @since 1.7.3 * * @return array */ private static function fetch() { $request = wp_remote_get( self::SOURCE_URL, [ 'sslverify' => false ] ); if ( is_wp_error( $request ) ) { return []; } $response = wp_remote_retrieve_body( $request ); $notifications = ! empty( $response ) ? json_decode( $response, true ) : []; if ( ! is_array( $notifications ) ) { return []; } return self::filter_fetched( $notifications ); } /** * Parse single notification data. * * @since 1.7.3 * * @param array $notification Raw data to parse. * * @return array */ private static function parse_notification( $notification ) { $remote_id = ! empty( $notification['id'] ) ? $notification['id'] : '0'; $type = ! empty( $notification['notification_type'] ) ? $notification['notification_type'] : 'info'; $title = ! empty( $notification['title'] ) ? $notification['title'] : ''; $slug = ! empty( $notification['slug'] ) ? $notification['slug'] : $title; $content = ! empty( $notification['content'] ) ? $notification['content'] : ''; $buttons = ! empty( $notification['btns'] ) && is_array( $notification['btns'] ) ? $notification['btns'] : []; $conditions = ! empty( $notification['type'] ) && is_array( $notification['type'] ) ? $notification['type'] : []; $start = ! empty( $notification['start'] ) ? $notification['start'] : date( 'Y-m-d H:i:s' ); $end = ! empty( $notification['end'] ) ? $notification['end'] : date( 'Y-m-d H:i:s', time() + ( YEAR_IN_SECONDS * 1 ) ); return [ 'remote_id' => sanitize_text_field( $remote_id ), 'type' => sanitize_text_field( $type ), 'title' => esc_html( $title ), 'slug' => sanitize_title( $slug ), 'content' => wp_kses_post( $content ), 'actions' => self::parse_notification_actions( $buttons ), 'conditions' => array_map( 'sanitize_text_field', $conditions ), 'start' => sanitize_text_field( $start ), 'end' => sanitize_text_field( $end ), ]; } /** * Parse single notification actions data. * * @since 1.7.3 * * @param array $buttons Raw data to parse. * * @return array */ private static function parse_notification_actions( $buttons ) { $actions = []; foreach ( $buttons as $type => $btn ) { $button_type = $type === 'main' ? 'primary' : 'secondary'; $actions[] = [ 'type' => sanitize_text_field( $button_type ), 'url' => esc_url_raw( $btn['url'] ), 'text' => esc_html( $btn['text'] ), ]; } return $actions; } /** * Filter fetched notifications before saving. * * @since 1.7.3 * * @param array $notifications Array of notifications items to verify. * * @return array */ private static function filter_fetched( $notifications ) { $data = []; if ( ! is_array( $notifications ) || empty( $notifications ) ) { return $data; } foreach ( $notifications as $notification ) { if ( self::verify_single( $notification ) ) { $data[] = self::parse_notification( $notification ); } } return $data; } /** * Filter active notifications and remove outdated ones. * * @since 1.7.3 * * @param array $notifications Array of notifications items to filter. * * @return array */ private static function filter_active( $notifications ) { if ( ! is_array( $notifications ) || empty( $notifications ) ) { return []; } // Remove notifications that are not active. foreach ( $notifications as $key => $notification ) { if ( ( ! empty( $notification['start'] ) && time() < strtotime( $notification['start'] ) ) || ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) ) ) { unset( $notifications[ $key ] ); } } return $notifications; } /** * Verify a single notification data. * * @since 1.7.3 * * @param array $notification Notification data to verify. * * @return bool */ private static function verify_single( $notification ) { $option = self::get_option(); // The message and license should never be empty, if they are, ignore. if ( empty( $notification['content'] ) || empty( $notification['type'] ) ) { return false; } $license_type = 'lite'; // Ignore if license type does not match. if ( ! in_array( $license_type, $notification['type'], true ) ) { return false; } // Ignore if expired. if ( ! empty( $notification['end'] ) && time() > strtotime( $notification['end'] ) ) { return false; } // Ignore if notification has already been dismissed. if ( ! empty( $option['dismissed_ids'] ) && in_array( $notification['id'], $option['dismissed_ids'] ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict return false; } return true; } /** * Get option value. * * @since 1.7.3 * * @param array $args Method arguments. * * @return array */ private static function get_option( $args = [] ) { static $option_cache; if ( ! isset( $args['cache'] ) ) { $args['cache'] = true; } if ( $option_cache && ! empty( $args['cache'] ) ) { return $option_cache; } $option = get_option( self::OPTION_NAME, [] ); if ( empty( $args['cache'] ) ) { return $option; } $option_cache = [ 'updated_at' => ! empty( $option['updated_at'] ) ? $option['updated_at'] : 0, 'dismissed_ids' => ! empty( $option['dismissed_ids'] ) ? $option['dismissed_ids'] : [], 'notifications' => ! empty( $option['notifications'] ) ? $option['notifications'] : [], ]; return $option_cache; } /** * Save notifications data in the database. * * @param array $notifications Array of notifications data to save. * * @since 1.7.3 */ private static function save( $notifications ) { $option = self::get_option(); update_option( self::OPTION_NAME, [ 'updated_at' => time(), 'dismissed_ids' => $option['dismissed_ids'], 'notifications' => $notifications, ] ); } /** * Dismiss notification via AJAX. * * @since 1.7.3 */ public static function dismiss() { Utils::check_ajax_permissions(); if ( searchwp_live_search()->get( 'Settings_Api' )->get( 'hide-announcements' ) ) { wp_send_json_error(); } if ( empty( $_POST['id'] ) ) { wp_send_json_error(); } $id = sanitize_text_field( wp_unslash( $_POST['id'] ) ); $option = self::get_option(); $option['dismissed_ids'][] = $id; $option['dismissed_ids'] = array_unique( $option['dismissed_ids'] ); // Remove notification. if ( is_array( $option['notifications'] ) && ! empty( $option['notifications'] ) ) { foreach ( $option['notifications'] as $key => $notification ) { if ( (int) $notification['remote_id'] === (int) $id ) { unset( $option['notifications'][ $key ] ); break; } } } update_option( self::OPTION_NAME, $option ); wp_send_json_success(); } }