client_ip() ); } /** * Whether the client is currently locked out. * * @return bool */ public function is_locked() { $state = get_transient( $this->key() ); return is_array( $state ) && ! empty( $state['count'] ) && $state['count'] >= $this->max_fails(); } /** * Seconds until the current lockout ends (0 if not locked). * * @return int */ public function retry_after() { $state = get_transient( $this->key() ); if ( is_array( $state ) && ! empty( $state['until'] ) ) { return max( 0, (int) $state['until'] - time() ); } return 0; } /** * Record a failed authentication attempt. Fixed window: the expiry is set * once when the window opens and not extended by later failures. * * @return void */ public function record_failure() { $key = $this->key(); $window = $this->window(); $state = get_transient( $key ); if ( ! is_array( $state ) || empty( $state['until'] ) || $state['until'] <= time() ) { $state = array( 'count' => 0, 'until' => time() + $window, ); } $state['count']++; $ttl = max( 1, $state['until'] - time() ); set_transient( $key, $state, $ttl ); } /** * Clear the lockout state (called after a successful authentication). * * @return void */ public function clear() { delete_transient( $this->key() ); } }