time(), 'type' => strtolower( sanitize_key( $type ) ), 'message' => $message, // Saved raw, sanitized on output 'context' => $context, 'details' => is_wp_error( $details ) ? 'WP_Error: ' . $details->get_error_message() : $details, 'metadata' => (array) $metadata, ); // Prepend new entry array_unshift( $logs, $entry ); // Trim log to max entries $logs = array_slice( $logs, 0, self::MAX_LOG_ENTRIES ); // PERFORMANCE FIX: Explicitly set autoload to 'no'. // This prevents the log data from loading on every page view of the website. update_option( self::LOG_OPTION_KEY, $logs, 'no' ); } /** * Generates the HTML representation of the log entries for display. * * @return string HTML for the log list. */ public function get_log_entries_html() { $logs = get_option( self::LOG_OPTION_KEY, array() ); if ( empty( $logs ) ) { return '

' . esc_html__( 'No log entries yet.', 'ainp-ai-native-publisher' ) . '

'; } // Map types to translated labels and icons. $log_type_map = array( 'info' => array( 'label' => __( 'Info', 'ainp-ai-native-publisher' ), 'icon' => 'dashicons-info-outline', ), 'success' => array( 'label' => __( 'Success', 'ainp-ai-native-publisher' ), 'icon' => 'dashicons-yes-alt', ), 'warning' => array( 'label' => __( 'Warning', 'ainp-ai-native-publisher' ), 'icon' => 'dashicons-warning', ), 'error' => array( 'label' => __( 'Error', 'ainp-ai-native-publisher' ), 'icon' => 'dashicons-dismiss', ), ); // Map contexts to translated labels and icons. $log_context_map = array( 'user' => array( 'label' => __( 'Manual', 'ainp-ai-native-publisher' ), 'icon' => 'dashicons-admin-users', ), 'cron' => array( 'label' => __( 'System', 'ainp-ai-native-publisher' ), 'icon' => 'dashicons-admin-generic', ), ); $html = ''; // .ainp-log-list return $html; } /** * Updates the processing status stored in WordPress options. * Calculates progress and clears manual context transient when finished. * * @param string $status Status ('idle', 'processing', 'processing_images', 'completed'). * @param int $current Items processed so far. * @param int $total Total items in the batch. * @param string $message Descriptive status message. */ public function update_processing_status( $status, $current, $total, $message ) { $progress = 0; if ( $total > 0 ) { $progress = round( ( $current / $total ) * 100 ); } elseif ( 'completed' === $status || ( 'idle' === $status && 0 === $current && 0 === $total ) ) { $progress = 100; } $status_data = array( 'status' => sanitize_key( $status ), 'progress' => absint( $progress ), 'current' => absint( $current ), 'total' => absint( $total ), 'message' => wp_kses_post( $message ), 'last_update' => time(), ); // Status is small, autoload is fine/preferred for dashboard widget checks update_option( self::STATUS_OPTION_KEY, $status_data ); // Clear manual context transient when processing ends. if ( in_array( $status, array( 'completed', 'idle' ), true ) ) { delete_transient( 'ainp_manual_context' ); } } /** * Retrieves the current processing status from WordPress options. * * @return array Processing status data or defaults. */ public function get_processing_status() { return get_option( self::STATUS_OPTION_KEY, array( 'status' => 'idle', 'progress' => 0, 'current' => 0, 'total' => 0, 'message' => __( 'System is idle.', 'ainp-ai-native-publisher' ), 'last_update' => time(), ) ); } /** * Checks if a cancellation request flag is set. * * @return bool True if cancellation requested, false otherwise. */ public function is_cancellation_requested() { return (bool) get_option( self::CANCEL_FLAG_OPTION, false ); } }