| @@ -67,17 +67,26 @@ | ||
| 67 | 67 | wp_send_json_success(['results' => $cached]); |
| 68 | 68 | return; |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | - $url = add_query_arg([ | |
| 71 | + $limit = min(max($limit, 1), 50); | |
| 72 | + | |
| 73 | + // Forward geocode: global results by default. Optional filter | |
| 74 | + // `yatra_nominatim_search_query_args` may add `countrycodes` etc. if a site must | |
| 75 | + // restrict to specific ISO regions. | |
| 76 | + $baseArgs = [ | |
| 72 | 77 | 'format' => 'json', |
| 73 | 78 | 'q' => $query, |
| 74 | 79 | 'limit' => $limit, |
| 75 | 80 | 'addressdetails' => 1, |
| 76 | - 'accept-language' => 'en-US,en;q=0.9', | |
| 77 | - 'countrycodes' => 'id,np,us,gb,fr,de,it,es,au,nz', | |
| 78 | - ], 'https://nominatim.openstreetmap.org/search'); | |
| 81 | + 'dedupe' => 1, | |
| 82 | + 'accept-language' => $this->nominatimAcceptLanguage(), | |
| 83 | + ]; | |
| 79 | 84 | |
| 85 | + $args = apply_filters('yatra_nominatim_search_query_args', $baseArgs, $query, $limit); | |
| 86 | + | |
| 87 | + $url = add_query_arg($args, 'https://nominatim.openstreetmap.org/search'); | |
| 88 | + | |
| 80 | 89 | $response = wp_remote_get($url, [ |
| 81 | 90 | 'timeout' => 10, |
| 82 | 91 | 'user-agent' => 'Yatra Travel Plugin (https://wpyatra.com/)', |
| 83 | 92 | 'headers' => [ |
| @@ -96,8 +105,10 @@ | ||
| 96 | 105 | wp_send_json_success(['results' => []]); |
| 97 | 106 | return; |
| 98 | 107 | } |
| 99 | 108 | |
| 109 | + $data = self::sortNominatimSearchResults($data); | |
| 110 | + | |
| 100 | 111 | $this->geocodingRepository->setPayload($resultCacheKey, $data, 300); |
| 101 | 112 | |
| 102 | 113 | wp_send_json_success(['results' => $data]); |
| 103 | 114 | } |
| @@ -133,9 +144,9 @@ | ||
| 133 | 144 | 'lat' => $lat, |
| 134 | 145 | 'lon' => $lng, |
| 135 | 146 | 'zoom' => 18, |
| 136 | 147 | 'addressdetails' => 1, |
| 137 | - 'accept-language' => 'en-US,en;q=0.9', | |
| 148 | + 'accept-language' => $this->nominatimAcceptLanguage(), | |
| 138 | 149 | ], 'https://nominatim.openstreetmap.org/reverse'); |
| 139 | 150 | |
| 140 | 151 | $response = wp_remote_get($url, [ |
| 141 | 152 | 'timeout' => 10, |
| @@ -159,6 +170,53 @@ | ||
| 159 | 170 | |
| 160 | 171 | $this->geocodingRepository->setPayload($resultCacheKey, $data, 600); |
| 161 | 172 | |
| 162 | 173 | wp_send_json_success(['result' => $data]); |
| 174 | + } | |
| 175 | + | |
| 176 | + /** | |
| 177 | + * Prefer the site / user locale for Nominatim labels. | |
| 178 | + * English regions like en-US can skew free-text search ordering toward US places; | |
| 179 | + * use a neutral "en" first, then the full tag, so global queries (e.g. "Japan") stay global. | |
| 180 | + */ | |
| 181 | + private function nominatimAcceptLanguage(): string | |
| 182 | + { | |
| 183 | + $locale = function_exists('get_user_locale') ? (string) get_user_locale() : ''; | |
| 184 | + if ($locale === '') { | |
| 185 | + $locale = (string) get_locale(); | |
| 186 | + } | |
| 187 | + $primary = str_replace('_', '-', $locale); | |
| 188 | + if ($primary === '' || $primary === 'C') { | |
| 189 | + return 'en'; | |
| 190 | + } | |
| 191 | + | |
| 192 | + if (preg_match('/^en-/i', $primary)) { | |
| 193 | + return 'en,' . $primary . ';q=0.88,*;q=0.5'; | |
| 194 | + } | |
| 195 | + | |
| 196 | + return $primary . ',en;q=0.8'; | |
| 197 | + } | |
| 198 | + | |
| 199 | + /** | |
| 200 | + * Nominatim relevance order is not always ideal for short queries; re-rank by importance | |
| 201 | + * (countries/cities rank higher than homonymous hamlets). No country filter — full planet. | |
| 202 | + * | |
| 203 | + * @param list<array<string, mixed>> $rows | |
| 204 | + * @return list<array<string, mixed>> | |
| 205 | + */ | |
| 206 | + private static function sortNominatimSearchResults(array $rows): array | |
| 207 | + { | |
| 208 | + usort($rows, static function (array $a, array $b): int { | |
| 209 | + $ia = isset($a['importance']) ? (float) $a['importance'] : 0.0; | |
| 210 | + $ib = isset($b['importance']) ? (float) $b['importance'] : 0.0; | |
| 211 | + if ($ia !== $ib) { | |
| 212 | + return $ib <=> $ia; | |
| 213 | + } | |
| 214 | + $rankA = isset($a['place_rank']) ? (int) $a['place_rank'] : 0; | |
| 215 | + $rankB = isset($b['place_rank']) ? (int) $b['place_rank'] : 0; | |
| 216 | + | |
| 217 | + return $rankB <=> $rankA; | |
| 218 | + }); | |
| 219 | + | |
| 220 | + return $rows; | |
| 163 | 221 | } |
| 164 | 222 | } |