ns' ) ); if ( ! $dismissed ) { $notifications = array_filter( $notifications, array( $this, 'filter_dismissed_notifications' ) ); } return count( $notifications ); } /** * Get the number of notifications resolved this execution. * * These notifications have been resolved and should be counted when active again. * * @return int */ public function get_resolved_notification_count() { return $this->resolved; } /** * Return the notifications sorted on type and priority. * * @return array|Yoast_Notification[] Sorted Notifications */ public function get_sorted_notifications() { $notifications = $this->get_notifications(); if ( empty( $notifications ) ) { return array(); } // Sort by severity, error first. usort( $notifications, array( $this, 'sort_notifications' ) ); return $notifications; } /** * AJAX display notifications. */ public function ajax_get_notifications() { $echo = filter_input( INPUT_POST, 'version' ) === '2'; // Display the notices. $this->display_notifications( $echo ); // AJAX die. exit; } /** * Remove storage when the plugin is deactivated. */ public function deactivate_hook() { $this->clear_notifications(); } /** * Save persistent notifications to storage. * * We need to be able to retrieve these so they can be dismissed at any time during the execution. * * @since 3.2 * * @return void */ public function update_storage() { $notifications = $this->get_notifications(); /** * Filter: 'yoast_notifications_before_storage' - Allows developer to filter notifications before saving them. * * @api Yoast_Notification[] $notifications */ $notifications = apply_filters( 'yoast_notifications_before_storage', $notifications ); // No notifications to store, clear storage if it was previously present. if ( empty( $notifications ) ) { $this->remove_storage(); return; } $notifications = array_map( array( $this, 'notification_to_array' ), $notifications ); // Save the notifications to the storage. update_user_option( get_current_user_id(), self::STORAGE_KEY, $notifications ); } /** * Provide a way to verify present notifications. * * @return array|Yoast_Notification[] Registered notifications. */ public function get_notifications() { return $this->notifications; } /** * Get newly added notifications. * * @return array */ public function get_new_notifications() { return array_map( array( $this, 'get_notification_by_id' ), $this->new ); } /** * Get information from the User input. * * @param string $key Key to retrieve. * * @return mixed value of key if set. */ private static function get_user_input( $key ) { $filter_input_type = INPUT_GET; if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === strtoupper( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) { $filter_input_type = INPUT_POST; } return filter_input( $filter_input_type, $key ); } /** * Retrieve the notifications from storage. * * @return array|void Yoast_Notification[] Notifications. */ private function retrieve_notifications_from_storage() { if ( $this->notifications_retrieved ) { return; } $this->notifications_retrieved = true; $stored_notifications = get_user_option( self::STORAGE_KEY, get_current_user_id() ); // Check if notifications are stored. if ( empty( $stored_notifications ) ) { return; } if ( is_array( $stored_notifications ) ) { $notifications = array_map( array( $this, 'array_to_notification' ), $stored_notifications ); // Apply array_values to ensure we get a 0-indexed array. $notifications = array_values( array_filter( $notifications, array( $this, 'filter_notification_current_user' ) ) ); $this->notifications = $notifications; } } /** * Sort on type then priority. * * @param Yoast_Notification $a Compare with B. * @param Yoast_Notification $b Compare with A. * * @return int 1, 0 or -1 for sorting offset. */ private function sort_notifications( Yoast_Notification $a, Yoast_Notification $b ) { $a_type = $a->get_type(); $b_type = $b->get_type(); if ( $a_type === $b_type ) { return WPSEO_Utils::calc( $b->get_priority(), 'compare', $a->get_priority() ); } if ( 'error' === $a_type ) { return -1; } if ( 'error' === $b_type ) { return 1; } return 0; } /** * Clear local stored notifications. */ private function clear_notifications() { $this->notifications = array(); $this->notifications_retrieved = false; } /** * Filter out non-persistent notifications. * * @param Yoast_Notification $notification Notification to test for persistent. * * @since 3.2 * * @return bool */ private function filter_persistent_notifications( Yoast_Notification $notification ) { return $notification->is_persistent(); } /** * Filter out dismissed notifications. * * @param Yoast_Notification $notification Notification to check. * * @return bool */ private function filter_dismissed_notifications( Yoast_Notification $notification ) { return ! $this->maybe_dismiss_notification( $notification ); } /** * Convert Notification to array representation. * * @param Yoast_Notification $notification Notification to convert. * * @since 3.2 * * @return array */ private function notification_to_array( Yoast_Notification $notification ) { $notification_data = $notification->to_array(); if ( isset( $notification_data['nonce'] ) ) { unset( $notification_data['nonce'] ); } return $notification_data; } /** * Convert stored array to Notification. * * @param array $notification_data Array to convert to Notification. * * @return Yoast_Notification */ private function array_to_notification( $notification_data ) { if ( isset( $notification_data['options']['nonce'] ) ) { unset( $notification_data['options']['nonce'] ); } return new Yoast_Notification( $notification_data['message'], $notification_data['options'] ); } /** * Filter notifications that should not be displayed for the current user. * * @param Yoast_Notification $notification Notification to test. * * @return bool */ private function filter_notification_current_user( Yoast_Notification $notification ) { return $notification->display_for_current_user(); } /** * Checks if given notification is persistent. * * @param Yoast_Notification $notification The notification to check. * * @return bool True when notification is not persistent. */ private function is_notification_persistent( Yoast_Notification $notification ) { return ! $notification->is_persistent(); } /** * Queues a notification transaction for later execution if notifications are not yet set up. * * @param callable $callback Callback that performs the transaction. * @param array $args Arguments to pass to the callback. * * @return bool True if transaction was queued, false if it can be performed immediately. */ private function queue_transaction( $callback, $args ) { if ( $this->notifications_retrieved ) { return false; } $this->add_transaction_to_queue( $callback, $args ); return true; } /** * Adds a notification transaction to the queue for later execution. * * @param callable $callback Callback that performs the transaction. * @param array $args Arguments to pass to the callback. */ private function add_transaction_to_queue( $callback, $args ) { $this->queued_transactions[] = array( $callback, $args ); } /** * Removes all notifications from storage. * * @return bool True when notifications got removed. */ protected function remove_storage() { if ( ! $this->has_stored_notifications() ) { return false; } delete_user_option( get_current_user_id(), self::STORAGE_KEY ); return true; } /** * Checks if there are stored notifications. * * @return bool True when there are stored notifications. */ protected function has_stored_notifications() { $stored_notifications = $this->get_stored_notifications(); return ! empty( $stored_notifications ); } /** * Retrieves the stored notifications. * * @codeCoverageIgnore * * @return array|false Array with notifications or false when not set. */ protected function get_stored_notifications() { return get_user_option( self::STORAGE_KEY, get_current_user_id() ); } }