On your e-commerce websites, functionality of searching the nearby stores of the brand and getting directions can help your customers have a more convenient shopping experience. So, in this guide, we’ll add that function to your websites with the help of MB Views from Meta Box.
To make this easier to understand, let’s look at a specific use case: searching for garages within a predefined radius. And this is the expected result we aimed for.

On this page, you can get your location and search for nearby garages by radius. As well as, the detailed information will be shown when you hover over the location of the shop on the map.
Video Version
Before Getting Started
In my case, each garage is a post of a custom post type. And the extra information of the garages will be stored in custom fields. And for the key feature: searching for garages by radius and getting directions, I will use code to create a custom template via MB Views.
So, we highly recommend you use Meta Box AIO to have a framework and all the mentioned functionalities from extensions in it. They are:
- MB Custom Post Type: to create a custom post type for the garages.
- MB Views: to create a view for searching posts by radius and other features on the map.
- MB Builder: to have a UI in the backend to create custom fields visually.
We already have a tutorial about searching posts on a map by multiple filters. The filter is based on the value of the Meta Box field. Also, you can get your location and filter posts by radius. And the extra information of the post will display when you hover over to the point.
However, this tutorial has some differences from it:
The first one is the layout of the page. Besides the filter, the page includes two columns, one is for the list of posts (garages), and another to show the map and the search results. They interact with each other in real time. Specifically, when you click on a post from the list, the map will focus on that location immediately.
Another difference is an advanced feature of the map. It is getting directions to the selected garage. And the visitor will be moved to the Google map interface. Also, if you use a mobile device, you can make a call to the shop through the phone number that is set in a custom field or on the website.
With these features, your website is sure to provide a great user experience. So if you’re looking to display your retail locations on a map, this can be a useful and interesting video for you.
Before going ahead, I’ve created the garage post type already, and a field group for the detailed information of each garage. You can add any field type to add extra information as needed.

After inputting data for the custom fields and posts, these are the garages we have.

Show Garage Listing on the Page
We need to have a page first.

Then, we’ll use MB Views to display garages and their information. Navigate to Meta Box > Views, and create a new view.
In the Template tab, I add code like this:
{% set args = { post_type: 'garage', posts_per_page: -1} %}
{% set posts = mb.get_posts(args) %}
{% for post in posts %}
{% endfor %}

In there:
{% set args = { post_type: 'garage', posts_per_page: -1} %}: is to declare that we’ll get all posts from the custom post type that has thegarageslug.mb.get_posts: a function to get those posts.{% for post in posts %}...{% endfor %}: a loop here to display all the post since there are various garages.
Inside the loop, just insert the field you want to show data from. I recommend you use the Insert Fields button, then your work is simply choose the field you want to insert from the list on the right panel. Besides the default fields, the list also includes the custom field you created before. MB Views allows you to choose the output or format of the special fields as well. And this is the code we have:

After inserting all the fields you need, scroll down to the Settings section, then set the Type as Singular and choose the created page to apply the template to it.

Now, on the frontend, you can see all the data is displayed, but in text format only.

Display Map Listing on a Map
I want to display them on a map. So, we’ll use JavaScript to transform it into the format we expected.
Back to the template.
Add some lines of code to declare that we’ll use the JavaScript libraries for the map and its style.
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" /> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
Next, I add a part for the page layout. As I said at first, it includes a list of garages and the map.
<div class="garage-layout">
<div class="garage-list" id="garage-list"></div>
<div class="garage-map">
<div id="map"></div>
</div>
</div>

Then, I create an empty array through {% set garages = [] %} to store the normalized garage data. We need to modify the code a little bit.
I also add <div id="garage-data"data-items='{{ garages|json_encode()|raw }}'></div>
to encode the garages array into JSON and store it in this attribute. It will be used for JavaScript access later.
For styling the page, move to the CSS tab and add some code.

Now, navigate to the JavaScript tab to add code for transforming garages to a map, based on the created classes.
Let’s break down each part for more details.
let rawData = $('#garage-data').data('items');
let Garages = typeof rawData === 'string' ? JSON.parse(rawData) : rawData;
Garages.forEach(g => {
g.lat = parseFloat(g.lat) || null;
g.lng = parseFloat(g.lng) || null;
});
This is to get data from HTML. In there, the first two lines retrieve the garage JSON data stored in the #garage-data attribute.
The next part is to convert latitude and longitude to a float.
Next, to initialize the map, I use this part:
const map = L.map('map').setView([21.0285, 105.85], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);
let markers = [];
let userMarker = null;
let userLocation = null;
function clearMarkers() {
markers.forEach(m => map.removeLayer(m));
markers = [];
}
This means we want the Leaflet map centered on a specific location with a zoom level of 12. You can change these numbers as you want.
Then, load OpenStreetMap tiles and attach them to the map.
Also, I manage the markers, including the garage markers, the user marker, and the user’s location.
Then, remove all garage markers from the map when you reset or get the new filter.
Next, to check whether a garage is currently open, I use this part:
function isOpenNow(openTime, closeTime) {
if (!openTime || !closeTime) {
return false;
}
let now = new Date();
let [oh, om] = openTime.split(':').map(Number);
let [ch, cm] = closeTime.split(':').map(Number);
let open = new Date();
let close = new Date();
open.setHours(oh, om, 0);
close.setHours(ch, cm, 0);
return now >= open && now <= close;
}
If the opening or closing time is missing, I mean, openTime and closeTime don’t have values, the status of the garage is closed. Otherwise, this gets the current system time and splits the time strings into hours and minutes.
Then, create Date objects for opening and closing times. After that, I set the opening and closing times on the current day and return true if the current time is within opening hours.
Now, to render the list and map, I use this part.
/* ===== RENDER ===== */
function render(items) {
clearMarkers();
$('#garage-list').empty();
let points = [];
items.forEach(g => {
if (!g.lat || !g.lng) {
return;
}
let open = isOpenNow(g.open_time, g.close_time);
let statusText = open
? '<span class="status-open">🟢 Open now</span>'
: '<span class="status-close">🔴 Closed</span>';
/* === LIST ITEM === */
$('#garage-list').append(`
<div class="garage-item"
data-lat="${g.lat}"
data-lng="${g.lng}">
<div class="garage-title">${g.title}</div>
<div class="garage-meta">📍 ${g.address}</div>
<div class="garage-meta">
⏰ ${g.open_time} - ${g.close_time} ${statusText}
</div>
<div class="garage-meta garage-phone">
📞 ${g.phone}
<a href="tel:${g.phone}" class="call-now">Call now</a>
</div>
</div>
`);
/* === MARKER === */
let popup = `
<strong>🏠 ${g.title}</strong><br>
📍 ${g.address}<br>
${open ? '🟢 Open now' : '🔴 Closed'}
`;
let marker = L.marker([g.lat, g.lng])
.addTo(map)
.bindPopup(popup);
markers.push(marker);
points.push([g.lat, g.lng]);
});
if (points.length) {
let bounds = L.latLngBounds(points);
if (userMarker) {
bounds.extend(userMarker.getLatLng());
}
map.fitBounds(bounds, {
padding: [40, 40]
});
}
$('#result-info').text(`Found ${items.length} garages`);
}
Specifically, I use the render() function to render. Before rendering, we should clear existing markers and list items through #garage-list attribute, skip garages without valid coordinates. Only the posts that have latitude and longitude are displayed. For each of them, we check whether the garage is currently open. I use two colors for the open status instead of the normal text for a more attractive look.
For the garage list, I have the List items part. I append each garage’s HTML into the list. and add some icons for each data.
The next part is for the markers. When you hover over a marker, a pop-up will be displayed with detailed information about that garage. I create a Leaflet marker and attach the pop-up. Then, store markers and coordinates for later map adjustments.
Don’t forget to regulate the UX of the map. Specifically, you can set it automatically zooms and adjusts the map so that all rendered garages and the user’s location (if available) are visible within the viewport. So, the visitors can have an overview of the listing on the map.
Additionally, I add a line to display the number of garages found:
$('#result-info').text(`Found ${items.length} garages`);
Now, let’s check the page on the frontend. It is displayed in two columns: the list of garages along with their information, and our map. The pop-up is shown as well.
Add Filter By Radius to the Page
Also, use the created template and add some code.
In the template tab, add a new class for the toolbar that includes: a button to get your location, a box for the filter by radius, the search button, and the number of result posts.

Next, move to the JavaScript tab to add some code for the behavior of the radius filter.
To filter garages within a given radius of the user’s location, add this code.
function distance(lat1, lon1, lat2, lon2) {
let R = 6371;
let dLat = (lat2 - lat1) * Math.PI / 180;
let dLon = (lon2 - lon1) * Math.PI / 180;
let a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1 * Math.PI / 180) *
Math.cos(lat2 * Math.PI / 180) *
Math.sin(dLon / 2) *
Math.sin(dLon / 2);
return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)));
}

In there, I use a function to calculate the distance between two geographic points. You need to convert the latitude and longitude differences from degrees to radians. Then, use the Haversine formula, which calculates real-world distance accounting for Earth’s curvature. Don’t forget to return the distance between the two points in kilometers.
Next, this is to prevent the phone link click from triggering the parent item click.
$(document).on('click', '.call-now', function (e) {
e.stopPropagation();
});

It means when the user clicks ‘Call now’, the action only initiates a phone call, without zooming the map or opening Google Maps. It’s good for the UX.
When the user clicks on an item, this code will be run.
$(document).on('click', '.garage-item', function () {
let lat = $(this).data('lat');
let lng = $(this).data('lng');
if (!lat || !lng) {
return;
}
// Zoom map
map.setView([lat, lng], 16);
// Open Google Maps directions
if (userLocation) {
let url = `https://www.google.com/maps/dir/?api=1&origin=${userLocation.lat},${userLocation.lng}&destination=${lat},${lng}`;
window.open(url, '_blank');
}
});

The selected garage will be zoomed. At the same time, open Google Maps directions from the user to the garage.
For the user’s location, add this code. The logic is retrieving the user’s current location and marking that location on the map.
$('#locate-btn').on('click', function () {
if (!navigator.geolocation) {
alert('Geolocation is not supported by your browser');
return;
}
navigator.geolocation.getCurrentPosition(pos => {
userLocation = {
lat: pos.coords.latitude,
lng: pos.coords.longitude
};
if (userMarker) {
map.removeLayer(userMarker);
}
userMarker = L.circleMarker(
[userLocation.lat, userLocation.lng],
{ radius: 8 }
)
.addTo(map)
.bindPopup('📍 Your location')
.openPopup();
map.setView([userLocation.lat, userLocation.lng], 13);
});
});

And finally is the action for the filter:
/* ===== FILTER BY RADIUS ===== */
$('#filter-btn').on('click', function () {
let rad = parseFloat($('#filter-radius').val());
if (!userLocation || !rad) {
alert('Please get your location and enter a radius');
return;
}
let filtered = Garages.filter(g => {
if (!g.lat || !g.lng) {
return false;
}
return distance(
userLocation.lat,
userLocation.lng,
g.lat,
g.lng
) <= rad;
});
render(filtered);
});

Based on the distance that we calculated above, filter garages that have a distance within the selected radius.
That’s done. I uploaded all the code to GitHub, so you can refer to it.
Now, go to the page to check the filter.

Last Words
I believe that this function will significantly improve the UX of your websites, which can help increase purchases. For more tutorials on seaching an filtering on the map, you can take a look at this series or suggest to us for more interesting guides. Thanks for reading.
- How To Display All Listings On A Map With Meta Box
- Insert Google Maps to a Website using Custom Fields
- How to Search Posts on a Map - Using MB Views
- How to Search Nearby Shops and Get Directions on a Map Listing - Using MB Views
- Author Bio
- Better 404 Page
- Blogs for Developers
- Building a Simple Listing Website with Filters
- Building an Event Website
- Building Forms with MB Frontend Submission
- Coding
- Create a Chronological Timeline
- Custom Fields Fundamentals
- Design Patterns
- Displaying Posts with Filters
- Download and Preview Buttons
- Dynamic Banners
- Dynamic Landing Page
- FAQs Page
- Featured Products
- Filter Posts by Relationships
- Filter Posts by Taxonomy
- Full Site Editing
- Google Fonts
- Gutenberg
- Hotel Booking
- Latest Products
- Logo Carousel
- Map Listing
- MB Builder Applications
- MB Group Applications
- MB Views Applications
- Most Viewed Posts
- Opening Hours
- OTA Website
- Pricing Table Page
- Product Page
- Product Variations
- Querying and Showing Posts by Custom Fields
- Recipe
- Related Posts via Relationship
- Restaurant Menus
- SEO Analysis
- Simple LMS
- Speed Up Website
- Taxonomy Thumbnails
- Team Members
- User Profile
- Video Gallery
How to Search Posts on a Map - Using MB Views
How to Filter Posts by Taxonomy on Archive Page - P2 - MB Views
Insert Google Maps to a Website using Custom Fields