base_url = rtrim($base_url ?? (string) get_option('powr_api_base_url', ''), '/'); $this->token = $token ?? (string) get_option('powr_api_token', ''); } public function is_configured(): bool { return $this->base_url !== '' && $this->token !== ''; } /** * @param array $args * @return array{data: list>, meta: array}|WP_Error */ public function get_providers(array $args = []) { $query = array_filter([ 'search' => $args['search'] ?? null, 'location_id' => $args['location_id'] ?? null, 'specialty' => $args['specialty'] ?? null, 'gender' => $args['gender'] ?? null, 'accepting_new_patients' => $args['accepting_new_patients'] ?? null, 'telehealth_available' => $args['telehealth_available'] ?? null, ], static function ($value) { return $value !== null && $value !== ''; }); $path = '/api/v1/providers'; if ($query !== []) { $path .= '?' . http_build_query($query); } $response = $this->request('GET', $path, [], true); if (is_wp_error($response)) { return $response; } $data = $response['body']; return [ 'data' => is_array($data['data'] ?? null) ? $data['data'] : (is_array($data) && ! isset($data['data']) ? $data : []), 'meta' => is_array($data['meta'] ?? null) ? $data['meta'] : [], ]; } /** * @return array|WP_Error */ public function get_provider(string $slug) { $response = $this->request('GET', '/api/v1/providers/' . rawurlencode($slug), [], true); if (is_wp_error($response)) { return $response; } $body = $response['body']; return is_array($body['data'] ?? null) ? $body['data'] : $body; } /** * @return array{data: list>, meta: array}|WP_Error */ public function get_locations() { $response = $this->request('GET', '/api/v1/locations', [], true); if (is_wp_error($response)) { return $response; } $body = $response['body']; return [ 'data' => is_array($body['data'] ?? null) ? $body['data'] : (is_array($body) && ! isset($body['data']) ? $body : []), 'meta' => is_array($body['meta'] ?? null) ? $body['meta'] : [], ]; } /** * @return array|WP_Error */ public function get_location(string $slug) { $response = $this->request('GET', '/api/v1/locations/' . rawurlencode($slug), [], true); if (is_wp_error($response)) { return $response; } $body = $response['body']; return is_array($body['data'] ?? null) ? $body['data'] : $body; } /** * @return array{ * specialties: list, * languages: list, * genders: list, * insurances: list, * locationTypes: list, * cities: list, * locationServices: list * }|WP_Error */ public function get_filters() { $response = $this->request('GET', '/api/v1/filters', [], true); if (is_wp_error($response)) { return $response; } $body = $response['body']; return [ 'specialties' => is_array($body['specialties'] ?? null) ? $body['specialties'] : [], 'languages' => is_array($body['languages'] ?? null) ? $body['languages'] : [], 'genders' => is_array($body['genders'] ?? null) ? $body['genders'] : [], 'insurances' => is_array($body['insurances'] ?? null) ? $body['insurances'] : [], 'locationTypes' => is_array($body['locationTypes'] ?? null) ? $body['locationTypes'] : [], 'cities' => is_array($body['cities'] ?? null) ? $body['cities'] : [], 'locationServices' => is_array($body['locationServices'] ?? null) ? $body['locationServices'] : [], ]; } /** * @return array{name: string, colors: array{primary: ?string, secondary: ?string, accent: ?string}}|WP_Error */ public function get_brand() { $response = $this->request('GET', '/api/v1/brand', [], true); if (is_wp_error($response)) { return $response; } $body = $response['body']; $colors = is_array($body['colors'] ?? null) ? $body['colors'] : []; return [ 'name' => isset($body['name']) ? (string) $body['name'] : '', 'colors' => [ 'primary' => isset($colors['primary']) && is_string($colors['primary']) ? $colors['primary'] : null, 'secondary' => isset($colors['secondary']) && is_string($colors['secondary']) ? $colors['secondary'] : null, 'accent' => isset($colors['accent']) && is_string($colors['accent']) ? $colors['accent'] : null, ], ]; } /** * @return array|WP_Error */ public function verify_token(?string $plain_token = null) { $token = $plain_token ?? $this->token; if ($token === '' || $this->base_url === '') { return new WP_Error('powr_not_configured', __('API base URL and token are required.', 'sondy')); } $response = $this->request('POST', '/api/v1/token/verify', [ 'token' => $token, ], false, $token); if (is_wp_error($response)) { return $response; } return $response['body']; } /** * @param array $body * @return array{status: int, body: array}|WP_Error */ private function request(string $method, string $path, array $body = [], bool $use_cache = false, ?string $bearer = null) { if ($this->base_url === '') { return new WP_Error('powr_no_base', __('API base URL is not configured.', 'sondy')); } $url = $this->base_url . $path; $cache_key = 'powr_api_' . md5($method . '|' . $url . '|' . ($bearer ?? $this->token)); if ($use_cache && $method === 'GET') { $cached = get_transient($cache_key); if (is_array($cached)) { return $cached; } } $token = $bearer ?? $this->token; $args = [ 'method' => $method, 'timeout' => 20, 'headers' => [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', ], ]; if ($token !== '') { $args['headers']['Authorization'] = 'Bearer ' . $token; } if ($method === 'POST' && $body !== []) { $args['body'] = wp_json_encode($body); } $raw = wp_remote_request($url, $args); if (is_wp_error($raw)) { return $raw; } $status = (int) wp_remote_retrieve_response_code($raw); $decoded = json_decode((string) wp_remote_retrieve_body($raw), true); if (! is_array($decoded)) { $decoded = []; } if ($status < 200 || $status >= 300) { $message = isset($decoded['message']) ? (string) $decoded['message'] : sprintf( /* translators: %d: HTTP status code */ __('API request failed (HTTP %d).', 'sondy'), $status ); return new WP_Error('powr_api_http', $message, ['status' => $status, 'body' => $decoded]); } $result = [ 'status' => $status, 'body' => $decoded, ]; if ($use_cache && $method === 'GET') { set_transient($cache_key, $result, self::CACHE_TTL); } return $result; } }