Skip to content

locator tag ​

A ready-made store locator in one tag: a search form, a list of the locations and a map. It works without Javascript and a search is in the URL, so it can be shared and bookmarked. (from v4.0.0, requires Maps 5.0.0+)

Like every map it needs the html_header and html_footer tags of Maps on the page. Without html_footer the form and the list work, but the map stays empty:

<html>
<head>
    {exp:reinos_maps:html_header}
</head>
<body>
    {exp:reinos_maps_locator:locator channel="stores"}

    {exp:reinos_maps:html_footer}
</body>
</html>

Before a visitor searches the tag shows all locations. A search shows the locations within the chosen distance, nearest first. When there are none, it shows the nearest locations.

Categories ​

Add checkboxes for the categories with category_group. A visitor can filter with them with or without a location.

{exp:reinos_maps_locator:locator channel="stores" category_group="3" label:categories="Store type"}

Use my location ​

The form has a Use my location button: the browser asks the visitor for permission and the tag searches around the device, without a geocoding request. The button is only shown with Javascript, on a browser that supports it and on an HTTPS page. Turn it off with locate="no".

Suggestions while typing ​

The search field suggests the cities and postal codes of your own locations, with their number of locations. The suggestions come from the search index on your own server: they are free, don't need an API key or geocoder and no typed text goes to a third party. A place without locations isn't suggested, but a visitor can still type and search it.

A city or postal code is only in the index after it is geocoded, see Reverse geocoding. Turn the suggestions off with suggest="no".

Search without a page reload ​

With Javascript a search updates the list, the text and the markers on the page. The address in the browser changes with it, so a search can still be shared and the back button works. The script gets the same page, so your own template and tags work the same. Without Javascript, or when the update fails, it is a normal page load. A form with a result_url to another page always loads that page.

When a visitor moves the map and not all locations are on it, a Search this area button appears, e.g. when there are more locations than the limit or after a search with a small distance. When all locations are on the map there is no button, the visitor can just look at the map. It searches around the center of the map, with the smallest of the radius_options that covers the map, and the map stays where it is.

A new search is the page again, so it counts for the Searches per minute setting, like a search with a page reload. Turn this off with sync="no".

The list and the map together ​

When the map is loaded, a small script keeps the list and the map together:

  • Hover or focus a location and its marker lights up, and the other way around.
  • Click a location, or its Show on the map button, and the map shows the marker with its popup. A marker in a cluster is shown first.
  • Click a marker and its location is marked in the list, the list scrolls to it.

Without Javascript, or while the map waits for consent, the form and the list keep working. The buttons are only added when there is a map to show the marker on.

To place the button yourself, add data-maps-locator-show-button to your own button in the template of a location. Turn the script off with sync="no".

Your own layout ​

Use the tag as a tag pair to place the parts in your own HTML, e.g. in the grid of your theme. You only need the parts you use.

{exp:reinos_maps_locator:locator channel="stores"}
    <header class="search-bar">{locator:form}</header>

    <div class="grid">
        <main>{locator:map}</main>
        <aside>
            {locator:status}
            {locator:results}
                <h3><a href="{path='stores/detail'}/{url_title}">{title}</a></h3>
                <p>{address}</p>
                {if distance}<p>{distance} {distance_unit}</p>{/if}
                <a href="{directions_url}">Route</a>
            {/locator:results}
        </aside>
    </div>
{/exp:reinos_maps_locator:locator}
Part
{locator:form}The search form
{locator:status}The text with the result of the search, or an error message
{locator:results}The list of the locations. As a tag pair: your own template of one location, with the variables and other tags, e.g. the nested channel:entries tag for custom fields
{locator:map}The map

Only a search form ​

For example in the header of your site. A layout with only the form doesn't search. Point result_url to the page with the result, that page needs a locator tag too.

{exp:reinos_maps_locator:locator channel="stores" result_url="stores" stylesheet="no"}
    {locator:form}
{/exp:reinos_maps_locator:locator}

Your own form ​

Any form to the page with the tag works, the search is in the query string. Use the same names as the location_field and radius_field_max params.

{exp:reinos_maps_locator:locator channel="stores"}
    <form method="get" class="my-form">
        <input type="search" name="location_field" value="{locator:location}" required>
        <select name="radius_field_max">
            <option value="10" {if locator:radius == 10}selected{/if}>10 km</option>
            <option value="25" {if locator:radius == 25}selected{/if}>25 km</option>
        </select>
        <button>Search</button>
    </form>

    {if locator:searched}<p>{locator:count} results</p>{/if}
    {locator:results}
    {locator:map}
{/exp:reinos_maps_locator:locator}

A radius that is not in radius_options is ignored.

Variable
{locator:location}The searched location, escaped for HTML
{locator:radius}, {locator:unit}The distance of the search and its unit
{locator:searched}If the visitor searched
{locator:count}, {locator:total}The number of locations in the list, and the total without the limit

Tag parameters ​

channel ​

The channel(s) to search, separate multiple channels with a |. Required.

channel="stores" [REQUIRED]

layout ​

The place of the list: list-left, list-right or map-top. On a small screen the list is always below the map. This param is for the tag without your own layout.

layout="list-left" [OPTIONAL]

theme ​

light, dark or auto (dark when the visitor uses dark mode). It is also the theme of the map.

theme="light" [OPTIONAL]

radius ​

The default distance.

radius="25" [OPTIONAL]

radius_options ​

The distances a visitor can choose from. A visitor can't search with another distance.

radius_options="10|25|50|100" [OPTIONAL]

metric ​

km or mile.

metric="km" [OPTIONAL]

sticky_first ​

The locations of sticky entries first (featured stores), then the rest by distance. They get the class .maps-locator__item--featured and a Featured label. With no they are sorted by distance like the others.

sticky_first="yes" [OPTIONAL]

limit ​

The maximum number of locations in the list and on the map. The tag has no paging: the text above the list says when there are more locations. Use the search_result tag when you need paging.

limit="50" [OPTIONAL]

nearest ​

The number of nearest locations to show when a search has no results, 0 to turn it off.

nearest="5" [OPTIONAL]

category_group ​

The category group(s) to show as checkboxes in the form, separate multiple groups with a |. Without this param there are no checkboxes.

category_group="3" [OPTIONAL]

category_match ​

any: a location needs one of the checked categories. all: a location needs all of them.

category_match="any" [OPTIONAL]

search_category_field ​

The name of the checkboxes in the URL, the same as on the search_form tag.

search_category_field="search_category_field" [OPTIONAL]

suggest ​

With no the search field doesn't suggest places.

suggest="yes" [OPTIONAL]

locate ​

With no the form has no Use my location button.

locate="yes" [OPTIONAL]

status ​

The status of the entries.

status="open" [OPTIONAL]

default:show_all ​

Show all locations before a visitor searches (up to the limit). With no the tag only shows the form.

default:show_all="yes" [OPTIONAL]

result_url ​

The page of the search result, by default the current page. That page needs a locator tag too.

result_url="stores/search" [OPTIONAL]

location_field, radius_field_max ​

The names of the fields in the URL, the same as on the search_form tag.

location_field="location_field" radius_field_max="radius_field_max" [OPTIONAL]

sync ​

With no the list and the map stay separate and a search reloads the page.

sync="yes" [OPTIONAL]

class ​

An extra class name for the locator.

class="" [OPTIONAL]

stylesheet ​

With no the stylesheet is not loaded, so you can write your own.

stylesheet="yes" [OPTIONAL]

map: ​

Every param of the map tag with a map: prefix, e.g. the tiles or the consent gate. The list keeps working when the map waits for consent.

The map fits around the markers, one marker gets zoom level 15. Use map:fit_map:force_zoom to change that.

map:tiles="openstreetmap" map:consent="click" map:marker_cluster:enabled="no" [OPTIONAL]

Texts ​

Every text can be changed with a param, e.g. to translate it. [location], [radius], [unit], [count] and [total] are replaced where they apply.

ParamDefault
label:locationCity, postal code or address
label:radiusDistance
label:submitSearch
label:directionsGet directions
label:showShow on the map
label:featuredFeatured
label:locateUse my location
label:search_areaSearch this area
text:this_areathis area (the [location] after Search this area)
label:categoriesCategories
text:my_locationyour location (the [location] after Use my location)
text:locate_errorWe could not get your location. Enter a place instead.
text:result1 location within [radius] [unit] of [location]
text:results[count] locations within [radius] [unit] of [location]
text:results_limitedThe nearest [count] of [total] locations within [radius] [unit] of [location]
text:nearestNo locations within [radius] [unit] of [location]. These are the nearest locations.
text:no_resultsNo locations within [radius] [unit] of [location].
text:not_foundWe could not find [location]. Check the spelling and try again.
text:rate_limitToo many searches. Try again in a minute.
text:mapMap of the locations (the name of the map for screen readers)

Variables ​

The variables of a location in {locator:results}:

Variable
{title}, {url_title}, {entry_id}, {channel_id}The entry
{entry_date}, {expiration_date}The dates of the entry
{address}The street, postal code, city and country as one text
{street_name}, {street_number}, {postal_code}, {city}, {country}, {country_code}The parts of the address
{lat}, {lng}, {latlng}The coordinate
{distance}, {distance_unit}The distance to the searched location, empty before a search
{directions_url}A link to get directions in Google Maps
{sticky}1 for a sticky entry (a featured store), use {if sticky}
{location_key}The key of the marker for the Javascript API of Maps

Styling ​

Change the look with CSS variables on .maps-locator, you don't need to override the styles:

css
.maps-locator {
    --maps-locator-height: 640px;
    --maps-locator-list-width: 400px;
    --maps-locator-accent: #0a7c55;
}
Variable
--maps-locator-heightThe height of the map and the list
--maps-locator-list-widthThe width of the list
--maps-locator-gap, --maps-locator-radiusThe space between the parts and their rounded corners
--maps-locator-bg, --maps-locator-bg-hoverThe background
--maps-locator-text, --maps-locator-mutedThe text
--maps-locator-borderThe borders
--maps-locator-accent, --maps-locator-accent-textThe button and links
--maps-locator-errorAn error message

Every part has a class: .maps-locator__form, .maps-locator__field, .maps-locator__submit, .maps-locator__locate, .maps-locator__locate-error, .maps-locator__categories, .maps-locator__category, .maps-locator__suggestions, .maps-locator__suggestion, .maps-locator__status, .maps-locator__body, .maps-locator__list, .maps-locator__item, .maps-locator__title, .maps-locator__address, .maps-locator__distance, .maps-locator__directions, .maps-locator__show, .maps-locator__area and .maps-locator__map.

While a search is loading the locator has aria-busy="true". The script adds .maps-locator__item--highlight on hover and focus, .maps-locator__item--active (with aria-current="true") while the popup is open, and .maps-locator-marker--active to the icon of the marker.