Fold for Craft CMS

Lite free · Pro $79 · Craft CMS 5

Find the nearest shop that has it in stock

Fold is a store locator for Craft: a map, a search box, and your shops sorted by distance, with opening hours that are right after midnight. If you run Craft Commerce, it can also filter that list to the shops that have a product available today.

Fold

One line is a working locator

The search box, radius select, results list and map, all rendered in Twig before any JavaScript runs. Without scripting it's still a complete, linkable list of your shops, and the script adds the map and live search on top. The default map is Leaflet on OpenStreetMap, so you don't need an API key.

twig
{{ craft.fold.locator({ group: 'retail', radius: 25 }) }}

{# Or build your own: it's an ordinary element query #}
{% set stores = craft.fold.locations
    .group('retail')
    .nearby({ lat: 35.2271, lng: -80.8431, radius: 25 })
    .limit(10)
    .all() %}

{% for store in stores %}
    {{ store.title }}: {{ store.distance|round(1) }} mi,
    {{ store.isOpenNow() ? 'open now' : 'closed' }}
{% endfor %}

Features

Everything a store locator has to get right, built on the parts of Craft you already use.

Locations are elements

Each shop has a field layout from its group, a URL and template per site, element search, relations and the trash. A Locations relation field links entries to the shops they belong to.

  • Groups, such as Retail and Service Centres, carry different fields and URLs
  • Address, coordinates and hours are shared across sites; titles and fields are translated

Radius search that scales

An indexed bounding box rules out the distant shops first, then a haversine filters and sorts the rest, all in one query. It runs the same on MySQL and Postgres and doesn't need spatial types or PostGIS.

Opening hours that are actually right

A bar open 22:00 to 02:00 is still open at half past midnight. "Open now" is worked out in each shop's own timezone, not the server's, and the hours model has room for holiday exceptions.

Geocoding that respects the provider

Fold only geocodes a location again when its address changes, so editing a phone number never costs a request. Every lookup is cached, including misses. Nominatim gets one request per second across the whole site, as its usage policy asks.

  • Coordinates you type are never overwritten
  • Pro adds Google and Mapbox, with a separate server-only Google key

Searches that understand people

Visitors type "NoDa" and "the airport one" into a locator box. When a geocoder can't place a term, Fold matches it against your shop names. It also tells "we couldn't find that place" apart from "there's nothing near it", because they need different messages.

A JSON endpoint for your own front end

GET /fold/search.json returns the same results the built-in locator shows, from the same search code. It's anonymous, read-only and cacheable, with a per-visitor rate limit and a fixed response shape that adding a custom field won't change.

Commerce inventory, read properly

Link a location to a Commerce inventory location and its address comes from Commerce. A stock search then uses Commerce's own available quantity, not on-hand, so nobody is sent across town for an item that's already been sold.

Import the spreadsheet you already have

The CSV importer recognises the column names other systems export, such as Store Name, address_1, ZIP, Telephone and a column per weekday. It matches existing rows by slug or name, so a second run updates instead of duplicating. Export writes the same columns back out.

Learn where to open next

With search recording on, Fold lists the places people searched for and found nothing. A town that keeps turning up there is a lead for your next shop, and you won't see it in any other analytics tool. Coordinates are rounded to about a kilometre and old rows expire.

Which shop near me has this in stock?

WP Store Locator can't answer this one. Fold asks Craft Commerce, through Commerce's own inventory service, which linked locations have the item available, then sorts those shops by distance. The JSON endpoint reports in or out of stock for each shop, and exact counts only if you turn them on.

twig
{% set stockists = craft.fold.locations
    .nearby({ lat: lat, lng: lng, radius: 50 })
    .inStockOf(product.defaultVariant)
    .all() %}

{# At least four available, not just one #}
{% set stockists = craft.fold.locations
    .inStockOf(variant, 4)
    .all() %}

{# The same filter from JavaScript:
   GET /fold/search.json?q=28202&radius=50&inStockOf=1234 #}

Frequently Asked Questions

Questions worth answering before you install it.

Put your shops on a map

Lite is free for up to 10 locations and doesn't need an API key. Pro is $79 with a $59/year renewal, and adds unlimited locations, Google and Mapbox, import and export, and Commerce stock search.