B4BY.588
Home
Terminal
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
sportmx
/
www
/
wp-content
/
plugins
/
wp-smushit
/
core
/
Filename :
class-activity-log-controller.php
back
Copy
<?php namespace Smush\Core; use Smush\Core\Bulk\Background_Bulk_Smush_Controller; use Smush\Core\Helper; use Smush\Core\Media_Library\Background_Media_Library_Scanner; use Smush\Core\Threads\Thread_Safe_Options; use Smush\Core\Modules\Helpers\WhiteLabel; class Activity_Log_Controller extends Controller { /** * Notification data key. * * @var string */ private static $notification_data_key = 'wp_smush_notifications'; /** * Maximum number of notifications. * * @var int */ private static $max_notification = 50; public static function get_max_notifications() { return self::$max_notification; } /** * @var Media_Library_Scan_Background_Process */ protected $scan_background_process; /** * @var Bulk_Smush_Background_Process */ protected $bulk_background_process; /** * @var String_Utils */ protected $string_utils; /** * @var Thread_Safe_Options */ private $thread_safe_options; /** * Activity_Log_Controller instance. * * @var mixed */ private static $instance; /** * @var WhiteLabel */ private $whitelabel; public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } public function __construct() { $this->string_utils = new String_Utils(); $this->thread_safe_options = new Thread_Safe_Options(); $this->whitelabel = new WhiteLabel(); $this->scan_background_process = Background_Media_Library_Scanner::get_instance()->get_background_process(); $this->bulk_background_process = Background_Bulk_Smush_Controller::get_instance()->get_background_process(); $this->register_filter( 'wp_smush_localize_ui_script_data', array( $this, 'localized_data_for_ui' ) ); $this->register_action( 'wp_ajax_smush_add_notification', array( $this, 'ajax_add_notification' ) ); $this->register_action( 'wp_ajax_smush_get_notifications', array( $this, 'ajax_get_notifications' ) ); $log_priority = 100; // $this->register_action( 'wp_smush_config_applied', array( $this, 'log_config_applied' ), $log_priority ); // Scan. $identifier = $this->scan_background_process->get_identifier(); $scan_dead_action = "{$identifier}_dead"; /** * Track early to ensure we capture the scan completed timing correctly, * since Bulk Smush can be auto-started when a scan is completed. */ $log_scan_completed_priority = 5; $this->register_action( "{$identifier}_completed", array( $this, 'log_scan_completed' ), $log_scan_completed_priority ); $this->register_action( $scan_dead_action, array( $this, 'log_scan_process_death' ), $log_priority ); // Bulk Smush. $identifier = $this->bulk_background_process->get_identifier(); $bulkd_smush_dead_action = "{$identifier}_dead"; $this->register_action( 'wp_smush_bulk_smush_completed', array( $this, 'log_bulk_smush_completed' ), $log_priority ); $this->register_action( $bulkd_smush_dead_action, array( $this, 'log_bulk_smush_process_death' ), $log_priority ); $this->register_action( 'wp_smush_cdn_activated', array( $this, 'log_cdn_activated' ), $log_priority ); } /** * Localize data for the UI. * * @param array $data * @return array */ public function localized_data_for_ui( $data ) { $data['activityLog'] = array( 'notifications' => $this->get_notifications_for_ui(), ); return $data; } /** * AJAX handler for adding a notification from the UI. * * @return void */ public function ajax_add_notification() { check_ajax_referer( 'wp-smush-ajax' ); if ( ! Helper::is_user_allowed( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions', 'wp-smushit' ) ), 403 ); } $raw = isset( $_POST['notification'] ) ? wp_unslash( $_POST['notification'] ) : ''; $notification = is_string( $raw ) ? json_decode( $raw, true ) : $raw; if ( empty( $notification ) || ! is_array( $notification ) ) { wp_send_json_error( array( 'message' => __( 'Invalid notification data.', 'wp-smushit' ) ) ); } $success = $this->add_notification( $notification ); if ( ! $success ) { wp_send_json_error( array( 'message' => __( 'Failed to save notification.', 'wp-smushit' ) ) ); } wp_send_json_success(); } /** * AJAX handler for fetching the latest notifications for the UI. * Called after a long-running background process completes or dies on-page, * so the frontend can replace optimistic entries with server-written ones. * * @return void */ public function ajax_get_notifications() { check_ajax_referer( 'wp-smush-ajax' ); if ( ! Helper::is_user_allowed( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions', 'wp-smushit' ) ), 403 ); } wp_send_json_success( array( 'notifications' => $this->get_notifications_for_ui(), ) ); } private function get_notifications_for_ui() { $this->enforce_notification_limit(); $notifications = $this->get_notifications(); if ( empty( $notifications ) ) { $this->add_notification( array( 'module' => 'smush', 'content' => $this->string_utils->get_raw_string( 'Welcome to Smush', $this->whitelabel->replace_branding_terms( __( 'Welcome to Smush', 'wp-smushit' ) ) ), ) ); $notifications = $this->get_notifications(); } return array_map( array( $this, 'sanitize_notification_for_ui' ), $notifications ); } /** * Track the completion of a scan process. * * @return void */ public function log_scan_completed() { $this->add_notification( array( 'module' => 'scan', 'content' => $this->string_utils->get_raw_string( 'Scan completed.', __( 'Scan completed.', 'wp-smushit' ) ), ) ); } /** * Track the death of a scan process. * * @return void */ public function log_scan_process_death() { $this->add_notification( array( 'module' => 'scan', 'content' => $this->string_utils->get_raw_string( 'Scan failed.', __( 'Scan failed.', 'wp-smushit' ) ), ) ); } /** * Track the completion of a bulk smush process. * * @return void */ public function log_bulk_smush_completed() { $this->add_notification( array( 'module' => 'bulk_smush', 'content' => $this->string_utils->get_raw_string( 'Bulk Optimization completed.', __( 'Bulk Optimization completed.', 'wp-smushit' ) ), ) ); } /** * Track the death of a bulk smush process. * * @return void */ public function log_bulk_smush_process_death() { $this->add_notification( array( 'module' => 'bulk_smush', 'content' => $this->string_utils->get_raw_string( 'Bulk Optimization failed.', __( 'Bulk Optimization failed.', 'wp-smushit' ) ), ) ); } /** * Track CDN going fully active after provisioning completes. * * @return void */ public function log_cdn_activated() { $this->add_notification( array( 'module' => 'cdn', 'content' => $this->string_utils->get_raw_string( 'CDN setup complete.', __( 'CDN setup complete.', 'wp-smushit' ) ), ) ); } /** * Get the notifications. * * Reads directly from the database (bypasses object cache) to ensure * writes from other background processes are visible. * * @return array */ public function get_notifications() { $notifications = $this->thread_safe_options->get_option( self::$notification_data_key, array() ); return is_array( $notifications ) ? $notifications : array(); } /** * Add a notification atomically. * * Uses a single JSON_ARRAY_APPEND database query so concurrent background * processes never overwrite each other's entries. * * @param mixed $notification Notification data. * * @return bool True if the notification was successfully stored, false otherwise. */ public function add_notification( $notification ) { $sanitized_notification = $this->sanitize_notification( $notification ); if ( empty( $sanitized_notification ) ) { return false; } $result = $this->thread_safe_options->append_object_to_array( self::$notification_data_key, $sanitized_notification ); return $result !== false && $result > 0; } /** * Sanitize a notification for display in the UI. * Translates the notification content. * * @param array $notification Notification data. * * @return array Sanitized notification data. */ private function sanitize_notification_for_ui( $notification ) { $sanitized = $this->sanitize_notification( $notification ); if ( empty( $sanitized['content'] ) ) { return array(); } $sanitized['content'] = $this->string_utils->get_translated_string( $sanitized['content'] ); return $sanitized; } /** * Sanitize a notification. * * @param mixed $notification Notification data. * * @return array{id: string, timestamp: string|int, type: string, content: string, url: string} */ private function sanitize_notification( $notification ) { if ( empty( $notification['content'] ) ) { return array(); } // Sanitize and ensure all expected fields exist. $sanitized = array(); $sanitized['id'] = isset( $notification['id'] ) ? sanitize_text_field( $notification['id'] ) : uniqid( 'smush_notification_' ); $sanitized['timestamp'] = isset( $notification['timestamp'] ) ? sanitize_text_field( $notification['timestamp'] ) : microtime( true ); $sanitized['type'] = isset( $notification['type'] ) ? sanitize_text_field( $notification['type'] ) : 'info'; $sanitized['module'] = isset( $notification['module'] ) ? sanitize_text_field( $notification['module'] ) : ''; $sanitized['content'] = isset( $notification['content'] ) ? sanitize_text_field( $notification['content'] ) : ''; $sanitized['url'] = isset( $notification['url'] ) ? sanitize_text_field( $notification['url'] ) : ''; return $sanitized; } /** * Trim the stored list to the maximum allowed size, keeping the most recent entries. * * Called once per UI read (localize / poll), so background processes can append * atomically without any per-write overhead. The worst-case outcome of deferring * this to read-time is storing a few extra entries between writes. * * @return void */ private function enforce_notification_limit() { $notifications = $this->get_notifications(); if ( count( $notifications ) <= self::$max_notification ) { return; } // Sort newest-first, then keep only the allowed maximum. usort( $notifications, function ( $a, $b ) { return $b['timestamp'] <=> $a['timestamp']; } ); $notifications = array_slice( $notifications, 0, self::$max_notification ); // Overwrite the option with the trimmed, sorted list. // Uses replace_array() so the value is stored as JSON, keeping it // consistent with the JSON-based read in get_notifications(). $this->thread_safe_options->replace_object_array( self::$notification_data_key, $notifications ); } }