value context pairs */ public static function log( $event, $context = array() ) { $user_id = get_current_user_id(); $user = $user_id ? get_userdata( $user_id ) : null; $username = $user ? $user->user_login : 'system'; $time = current_time( 'Y-m-d H:i:s' ); $ctx_parts = array(); foreach ( $context as $k => $v ) { $ctx_parts[] = $k . ':' . ( is_scalar( $v ) ? $v : wp_json_encode( $v ) ); } $ctx_string = ! empty( $ctx_parts ) ? ' | ' . implode( ' | ', $ctx_parts ) : ''; $message = sprintf( '[MFE AUDIT] %s | %s | user:%s%s', $time, strtoupper( $event ), $username, $ctx_string ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- System audit logging output. error_log( $message ); // Optionally persist to wp_options for a future admin UI $log_history = get_option( 'metaforge_audit_log', array() ); $log_history[] = array( 'time' => $time, 'event' => $event, 'user' => $username, 'ctx' => $context, ); // Keep only the last 200 entries to avoid bloating the options table if ( count( $log_history ) > 200 ) { $log_history = array_slice( $log_history, -200 ); } update_option( 'metaforge_audit_log', $log_history, false ); } /** * Retrieve stored audit logs with optional filter. * * @param int $limit Max number of log entries to return. * @param string $event_filter Optional event type filter. * @return array */ public static function get_logs( $limit = 100, $event_filter = '' ) { $log_history = get_option( 'metaforge_audit_log', array() ); if ( ! is_array( $log_history ) ) { $log_history = array(); } if ( ! empty( $event_filter ) ) { $log_history = array_filter( $log_history, function ( $entry ) use ( $event_filter ) { return isset( $entry['event'] ) && stripos( $entry['event'], $event_filter ) !== false; } ); } $log_history = array_reverse( $log_history ); return array_slice( $log_history, 0, $limit ); } /** * Clear all stored audit logs. * * @return bool */ public static function clear_logs() { return update_option( 'metaforge_audit_log', array(), false ); } /** * Format logs as plain text for copy-to-clipboard or export. * * @return string */ public static function get_raw_log_string() { $logs = self::get_logs( 200 ); if ( empty( $logs ) ) { return 'No audit logs recorded yet.'; } $lines = array(); foreach ( $logs as $l ) { $ctx = ! empty( $l['ctx'] ) ? wp_json_encode( $l['ctx'] ) : '{}'; $lines[] = sprintf( '[%s] [%s] User: %s | Data: %s', $l['time'] ?? 'N/A', strtoupper( $l['event'] ?? 'INFO' ), $l['user'] ?? 'system', $ctx ); } return implode( "\n", $lines ); } }