Distance search in themes
Distance search lets visitors find listings within a distance of a city or of where they
are. Site owners switch it on in Settings → General. When it is off, none of this
shows and the search page ignores the fields below. The
REST API answers 422 instead, for a bad bbox
too.
The form fields
Section titled “The form fields”A search form sends these, as GET fields:
| Field | Value |
|---|---|
iRadius |
5, 10, 25, 50 or 100, in the site’s unit. Other numbers snap to the nearest. |
sLat, sLng |
The visitor’s position, rounded to two decimals. |
sOrder=distance |
Nearest first. |
bbox |
A map area: west,south,east,north. See A map area. |
With iRadius and no sLat/sLng, the radius is measured from the centre of the one
city, or else the one region, in the search. The radius then replaces that city filter.
A map area
Section titled “A map area”bbox=west,south,east,north keeps results to listings whose point is inside the box, such
as the area a map shows. Longitudes run from -180 to 180 and latitudes from -90 to 90, and
south must not be above north. West above east means the box crosses the date line.
Each edge is rounded to four decimals.
On the search page, a bbox that is not a valid box is ignored. With iRadius both apply, and so do the
place filters. Search URLs and pagination keep it, the canonical URL drops it, and a
saved search keeps it.
osc_search_bbox() gives the box in use as [west, south, east, north], or null. Plugins
building a Search call $search->inBox($west, $south, $east, $north); $search->box()
reads it back. A search backend finds it in SearchFilters::$box.
The core field
Section titled “The core field”Core adds osc_search_distance_field() to the search_form action. It prints a
<fieldset class="osc-distance" data-osc-distance> with the radius list and a
Use my location button (.osc-near-me, data-osc-near-me). Core ships no CSS for
it, so style those classes. The button needs osc-ui-common, which the field enqueues,
and it must sit inside the search <form>.
To draw it somewhere else, take it off the action and call it yourself:
osc_remove_hook('search_form', 'osc_search_distance_field');// later, in your sidebarif (osc_geo_search_enabled()) { osc_search_distance_field();}To draw your own markup, use osc_search_radius_options() for the choices,
osc_search_radius() for the current one and osc_search_near() for the point in use.
Sort and results
Section titled “Sort and results”osc_list_orders() includes Nearest first when distance search is on. A theme with
its own sort menu adds sOrder=distance&iOrderType=asc. With no distance picked,
nearest first keeps to the largest one.
On a result, osc_item_distance() is the distance in whole units of the site, or null
outside a distance search. osc_distance_label() turns a number into text such as
“25 km” or “3 miles”.
Listings from plugins
Section titled “Listings from plugins”Core sets each listing’s search point when a listing is saved through core. A plugin
that writes t_item_location itself leaves the listing out of distance search until
the weekly job sets its point.
Exact positions from an address
Section titled “Exact positions from an address”With no provider, a listing searches from its city or region centre. A geocode provider plugin finds the exact position from the listing’s street address. The owner picks it in Settings → General → Maps → Address lookup.
Core looks the address up from a job after the listing is saved, only when the listing has a
street and no position. With no provider picked, nothing is looked up; the map’s own key is
not used for it. Each answer is kept in the key-value store for as long as the provider’s cacheTtl()
allows, at most a year; an address with no match is kept for a day. A provider that
throws a RuntimeException fails the job, and the queue tries again later. A provider whose
request allowance is used up throws mindstellar\location\GeocodeLimitReached($message, $seconds)
instead: the job waits that long and tries again, with no failure counted.
ListingGeocode::queueExisting() queues the lookup of every enabled listing that has a street
and no position. One job adds them to the queue 50 at a time, and adds more only once those have run.
A provider plugin implements mindstellar\location\GeocodeProvider and registers it on
register_geocode_providers (7.0+):
osc_add_hook('register_geocode_providers', static function ($registry): void { $registry->register(new MyProvider());});geocode() returns [lat, lng] or null for no match. attribution() returns the credit
the service requires; themes echo osc_geocode_attribution() as it is, without escaping. Other code can look an
address up with osc_geocode($address, $countryCode). The geocode_address filter can rewrite
an address first, and geocode_coordinates can change or drop an answer. geocode_coordinates
runs only on a cache miss, so a cached answer skips it.
A theme that calls osc_geocode() on visitor input must cap or throttle it: each new string is a
paid call to the provider.