The search page ships with three view modes: List (filters + results, no map), Split (filters + results + sticky map side-by-side), and Map (filters + full-width map, no results column). Split is the default on desktop. The map uses Leaflet with OpenStreetMap tiles, syncs hover state with the result cards, and surfaces a “Search this area” pill when the visitor pans away from their initial framing.
Three view modes
Three buttons in the page toolbar toggle the view. The toolbar shows List, Split, Map. Split is the default on desktop, with the URL falling back to ?view=list or ?view=map when the visitor picks the other two. Initial view is also configurable via shortcode attribute.
The 3-column layout
Split mode uses a CSS grid with three columns: filters sidebar (264px fixed), results column (1fr flexible), map column (clamped between 420px and 540px). The map sticks to the viewport top as the visitor scrolls the results list. Container max width is 1680px so the map gets breathing room on wide screens.
/* Real CSS shipped in assets/css/sdp-search.css */
.sdp-d__layout--split {
max-width: 1680px;
grid-template-columns: 264px minmax(0, 1fr) minmax(420px, 540px);
gap: 1.5rem;
}
.sdp-d__layout--split .sdp-d__map {
position: sticky;
top: calc(var(--wp-admin--admin-bar--height, 0px) + 16px);
height: calc(100vh - var(--wp-admin--admin-bar--height, 0px) - 32px);
min-height: 480px;
}
The CSS reads the WP admin bar height token so logged-in admins viewing the page get the right offset under the admin bar.
Search this area on pan
The first map render fits all markers via map.fitBounds(). We suppress the “Search this area” button for that one auto-fit. Any subsequent pan or zoom by the visitor surfaces a dark pill, centred at the top of the map, that says “↻ Search this area”. Clicking it does three things:
- Reads the map’s centre (
map.getCenter()) and bounds (map.getBounds()). - Calculates radius in km: half the diagonal from centre to north-east corner, via
centre.distanceTo(bounds.getNorthEast()) / 1000. - Sets the search filters:
userLat,userLng,useDistance,radiusKm. Reveals the Distance section in the sidebar (so the visitor sees the active radius). Reruns the search.
The new results refit the map (via fitBounds() again), and we suppress the Search this area button for that auto-fit too, so it only reappears if the visitor moves the map after the refit.
Card and marker hover sync
Two-way visual sync between cards and markers, no JavaScript framework required:
- Hovering a card looks up the matching marker by listing ID and toggles a
sdp-is-hoveredclass on the marker’s icon element. CSS scales it slightly and ups the z-index. - Hovering a marker looks up the matching card and toggles the same class on the card. CSS lifts the shadow and outlines the card with the accent colour.
- Clicking a marker scrolls the matching card into view (
card.scrollIntoView({ behavior:'smooth', block:'center' })) so the visitor can click through to the listing detail from the cards.
What happens on tablet and phone
The 3-column grid only kicks in above 1180px viewport width. Tablet drops to a 2-column layout (filters + results) and the map falls to a static block beneath both, sized between 420px and 640px tall. Phone (below 960px) hides the map entirely in Split mode; the visitor can still pick the Map view from the toggle to get the full-width map experience.
FAQ
Can I make List the default instead of Split?
Yes. Pass view="list" as a shortcode attribute or set ?view=list in the URL. The default for the bare shortcode is Split.
Does the map cluster markers?
Not by default. The page typically renders 12-100 markers, well within Leaflet’s comfortable rendering range. If your site’s typical result set is much larger, integrating Leaflet.markercluster is a small add. It’s on the roadmap for a future release.
What tile provider does the map use?
OpenStreetMap, via the standard https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png endpoint. Free, attribution required (rendered bottom-right of the map). To swap to Mapbox, Stadia, or another provider, override the L.tileLayer() call in your theme via the sdp_search_map_tiles filter.
How does the Search this area radius get calculated?
It’s the centre-to-north-east-corner distance in km, computed via Leaflet’s distanceTo() (which uses the WGS84 ellipsoid for accuracy). At Bedford’s latitude that’s a useful approximation of “the radius that covers the visible viewport.” If you’ve panned to a different latitude band, the visible-area-to-radius mapping shifts slightly, but it’s close enough for “search this area” UX.