all(); $fingerprint = md5( $type . '|' . $file . '|' . $line . '|' . $message ); if ( isset( $errors[ $fingerprint ] ) ) { ++$errors[ $fingerprint ]['count']; $errors[ $fingerprint ]['last_seen'] = $now; } else { $errors[ $fingerprint ] = array( 'type' => $type, 'message' => substr( $message, 0, 500 ), 'file' => $file, 'line' => $line, 'count' => 1, 'first_seen' => $now, 'last_seen' => $now, ); } // Newest first; drop the oldest beyond the cap. uasort( $errors, static function ( array $a, array $b ): int { return $b['last_seen'] <=> $a['last_seen']; } ); $errors = array_slice( $errors, 0, self::MAX, true ); update_option( self::OPTION, $errors, false ); } /** * All stored errors, newest first. * * @return array */ public function all(): array { $errors = get_option( self::OPTION, array() ); return is_array( $errors ) ? $errors : array(); } /** * Errors seen after a timestamp. * * @param int $since Unix timestamp. * @return array */ public function since( int $since ): array { return array_filter( $this->all(), static function ( array $error ) use ( $since ): bool { return (int) $error['last_seen'] >= $since; } ); } /** * Forget all errors. */ public function clear(): void { delete_option( self::OPTION ); } }