}> */ public function search(string $query, int $limit = 5): array { if ($this->key === '') { throw new \RuntimeException('Address lookup is not configured. Enter an address and place the pin manually.'); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception messages are data; REST encodes them and admin callers escape output. } $args = ['text' => $query, 'limit' => min(5, max(1, $limit)), 'format' => 'json', 'lang' => $this->language, 'apiKey' => $this->key]; if (preg_match('/^[a-z]{2}$/', $this->country)) { $args['bias'] = 'countrycode:' . $this->country; } $response = wp_safe_remote_get(add_query_arg($args, 'https://api.geoapify.com/v1/geocode/autocomplete'), ['timeout' => 8, 'redirection' => 0, 'limit_response_size' => 131072]); if (is_wp_error($response)) { throw new \RuntimeException('Address lookup could not connect. You can still save the address.'); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception messages are data; REST encodes them and admin callers escape output. } $status = wp_remote_retrieve_response_code($response); if ($status !== 200) { throw new \RuntimeException(match ($status) { // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception messages are data; REST encodes them and admin callers escape output. 401, 403 => 'Address lookup credentials were rejected. Check Maps settings.', 429 => 'Address lookup limit reached. Try again later or place the pin manually.', default => 'Address lookup is temporarily unavailable. You can still save the address.', }); } return self::results(json_decode(wp_remote_retrieve_body($response), true)); } /** @return list}> */ public static function results(mixed $data): array { $results = []; foreach (is_array($data) && is_array($data['results'] ?? null) ? array_slice($data['results'], 0, 5) : [] as $item) { $lat = Location::coordinate($item['lat'] ?? null, 90); $lng = Location::coordinate($item['lon'] ?? null, 180); if ($lat === null || $lng === null || ! is_string($item['formatted'] ?? null)) { continue; } $address = []; foreach (['line' => 'address_line1', 'city' => 'city', 'region' => 'state', 'postal_code' => 'postcode', 'country' => 'country', 'formatted' => 'formatted'] as $field => $providerField) { $address[$field] = sanitize_text_field((string) ($item[$providerField] ?? '')); } $results[] = ['label' => $address['formatted'], 'latitude' => $lat, 'longitude' => $lng, 'address' => $address]; } return $results; } }