Build location-based pages with HubDB

Last updated:

HubDB supports locations as a field type, which enables you to build location-based pages on HubSpot's CMS. 

In this tutorial, learn how to create a page with a map on HubSpot’s CMS using HubDB. You can reference more detailed HubDB documentation here.

You’ll need:

  • Approximately one hour.
  • Some prior knowledge of HubSpot's CMS, HTML and CSS will be needed to customize your page.

What's a location?

When you create a column on a HubDB table with the Location field type, you're designating this column as a place to store coordinates that point to a specific location in the world. 

A location is often represented as coordinates (a pair of decimal numbers) such as 42.36, -71.11. The first number is the latitude, or the degrees North or South of the equator. The second number is the longitude, or the degrees from the Prime Meridian. The Prime Meridian is an imaginary line starting at the North Pole, running through Greenwich, England, France, Spain, Algeria, Ghana and ending at the South Pole. Longitudes east of that line are positive, west is negative. At 180 degrees, the positive and negative degree values meet.

1. Find the visitor's location

With the Global Positioning System (GPS), you can determine the location of a visitor to your site. Mobile phone devices have GPS chips that can receive GPS signals. These devices can also use nearby Wi-Fi networks or mobile network towers to determine their location. Laptop and desktop computers typically use Wi-Fi to determine their location.

Within a page loaded in the web browser, you can use JavaScript to request a device's location.

<script> navigator.geolocation.getCurrentPosition(function(position) { console.log("I'm at " + position.coords.latitude + ", " + position.coords.longitude); }); </script>

This will first ask the visitor if it's OK for the page to get the visitor's location, and then respond with the coordinates. The response may appear like the following:

I'm at 42.370354299999995, -71.0765916

2. Build a database

Once you know the visitor's location, you can help them find different locations in their general area. 

Create a new table in HubDB and add two columns: 'location' (type: Location) an 'cuisine' (type: Text).

It should look like this:

location-example

You can build your own database of local eateries or you can import data for lunch spots near HubSpot in Cambridge, Massachusetts. Here's a sample file you can use: lunch-spots.csv. Upload the file to HubDB, and map the columns as shown.

map-fields-location-table

 

Once you finish the import, you should have a list of eateries that looks like this: 

list-of-cambridge-eateries

 

Publish your table, make a note of the table ID (the last number in the URL) and you're ready to start using your data.

3. Create a simple listing page

Create a simple list for this data using HubL and the HubDB functions.

In the design manager, create a new template using the code editor. You can name it something like "lunchspots.html".

Add this code just after <body> tag, using the table ID you noted above.

{% set table_id = YOUR_TABLE_ID %} <table> {% for row in hubdb_table_rows(table_id) %} <tr> <td>{{ row.name }}</td> <td>{{ row.cuisine }}</td> </tr> {% endfor %} </table>

When you preview the template, a simple list of restaurants and a description of their cuisine should appear. If nothing appears, double-check that your table ID is correct and that the table is published.

4. Filter to a single listing

Your listing page can also double as a detail page. You can link the restaurant name to a page specific to that restaurant. Make sure to leave in the set table_id... line here and in all other code samples on this page.

<table> {% for row in hubdb_table_rows(table_id) %} <tr> <td><a href="?{{ request.query }}&row_id={{ row.hs_id }}">{{ row.name }}</a></td> <td>{{ row.cuisine }}</td> </tr> {% endfor %} </table>

Each row will now be linked back to the same page with a query string parameter in row_id which is the unique ID of this row. Note the use of request.query to make sure any existing query string parameters are preserved on the current URL.

Now we'll add the details:

{% if request.query_dict['row_id'] %} {% set row = hubdb_table_row(table_id, request.query_dict['row_id']) %} <h1>{{ row.name }}</h1> <h3>{{ row.cuisine }}</h3> <p>{{ row.location['lat'] }}, {{ row.location['lon'] }}</p> {% else %} <table> {% for row in hubdb_table_rows(table_id) %} <tr> <td><a href="?{{ request.query }}&row_id={{ row.hs_id }}">{{ row.name }}</a></td> <td>{{ row.cuisine }}</td> </tr> {% endfor %} </table> {% endif %}

The if statement () determines whether to show the details or skip down to the block to show the listing. It will look something like this:
restaurant-example

5. Determine the visitor's location

You can also ask for the visitor's location, so you can show them how far away each restaurant is. Change your code to the following.

{% if request.query_dict['row_id'] %} {% set row = hubdb_table_row(table_id, request.query_dict['row_id']) %} <h1>{{ row.name }}</h1> <h3>{{ row.cuisine }}</h3> <p>{{ row.location['lat'] }}, {{ row.location['lon'] }}</p> {% elif request.query_dict['lat'] %} <table> {% for row in hubdb_table_rows(table_id) %} <tr> <td><a href="?{{ request.query }}&row_id={{ row.hs_id }}">{{ row.name }}</a></td> <td>{{ row.cuisine }}</td> <td>{{ row.location|geo_distance(request.query_dict['lat'], request.query_dict['lon'], "mi")|round(3) }} mi away</td> </tr> {% endfor %} </table> {% else %} Please allow us to read your location so we can show you the closest lunch spots. <script> navigator.geolocation.getCurrentPosition(function(position) { window.location = window.location.href.split('?')[0] + "?lat=" + position.coords.latitude + "&lon=" + position.coords.longitude; }); </script> {% endif %}

This code introduces an if statement. In the default case, it asks the visitor to share their location. If they accept, it redirects the page with lat and lon query parameters. The second time the page loads, it shows the list, now with a third column that is the calculated distance from the provided location.

Since row.location just returns the restaurant's coordinates, HubSpot uses the geo_distance filter to calculate the distance. It takes the visitor's latitude, longitude and the units of the distance. The units default to meters ("M"), but also accept kilometers ("KM"), miles ("MI"), and feet ("FT"). Lastly, HubSpot round the number a bit to make it more readable.

6. Sort the list

If the list got much bigger, it would be helpful to show the closest restaurants first. You can do so by adding sorting options to the hubdb_table_rows function. Change this section as follows:

{% elif request.query_dict['lat'] %} {% set params = "orderBy=geo_distance(location," ~ request.query_dict['lat'] ~ "," ~ request.query_dict['lon'] ~ ")" %} <table> {% for row in hubdb_table_rows(table_id, params) %} <tr>

Now the list will be sorted by the distance between the location column and the visitor's coordinates. The key is building the geo_distance ordering function which ends up looking like orderBy=geo_distance(42.37,-71.076). To sort the list in reverse order, with the restaurants the furthest away first, you can prepend a - (minus sign) to geo_distance.

7. Filter by distance

You can filter the list by distance as well. To find all restaurants less than one mile away, use geo_distance as a query filter. 

{% elif request.query_dict['lat'] %} {% set params = "orderBy=geo_distance(location," ~ request.query_dict['lat'] ~ "," ~ request.query_dict['lon'] ~ ")" %} {% set params = "geo_distance(location," ~ request.query_dict['lat'] ~ "," ~ request.query_dict['lon'] ~ ",mi)__lt=1.0&" ~ params %} <table> {% for row in hubdb_table_rows(table_id, params) %} <tr>

This constructs another parameter to the HubDB query which looks like geo_distance(location,42.37,-71.076,mi)__lt=1.0

The geo_distance query filter takes four arguments. First is the location column that you want to filter by. The next three parameters are latitude, longitude, and distance units. After the geo_distance operator, specify the filter operator, "less than" or "lt". Finally, after the equal sign is the value to compare with the result of the function.

8. Add a map

You can Google Maps APIs to create a visual map of the list. Replace the block of code inside the second if condition (elif request.query_dict['lat']) with this:

<style> #map { width: 100%; height: 1200px; } </style> <div id="map" height="500"></div> <script> var map; function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: {lat: 42.3665171, lng: -71.0820328}, zoom: 16 }); var marker_origin = new google.maps.Marker({ map: map, title: "you are here", icon: { scaledSize: {width:50, height:50}, url: "http://maps.google.com/mapfiles/kml/paddle/blu-blank.png"}, position: {lat: {{ request.query_dict['lat'] }}, lng: {{ request.query_dict['lon'] }}} }); {% for row in hubdb_table_rows(table_id) %} var marker_{{ row.hs_id }} = new google.maps.Marker({ map: map, position: {lat: {{ row.location["lat"] }}, lng: {{ row.location["lon"] }}}, title: '{{ row.name }}', icon: { scaledSize: {width:40, height:40}, url: "http://maps.google.com/mapfiles/kml/shapes/dining.png"} }); marker_{{ row.hs_id }}.addListener('click', function() { new google.maps.InfoWindow({ content: '<div> {{ row.name }} is {{ row.location|geo_distance(request.query_dict['lat'], request.query_dict['lon'], "mi")|round(3) }} miles away</div>' }).open(map, marker_{{ row.hs_id }}); }); {% endfor %} } </script> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_API_KEY&callback=initMap" async defer></script>

Add in your table ID and your Google API key and you should now see an interactive map in place of the listing. Your map should look like this (with your blue origin marker wherever you are).sample-hubdb-map

 

That's it! You've built a page that uses a visitor's location to find a local place to eat. The key is the geo_distance function which can be used to filter, order, and calculate the distance. This simple page could be enhanced by adding a toggle between the listing and map view, a map and more info on the details page, and perhaps a link to each restaurant's website.

If the visitor's browser cannot determine their location, or they want to look for places in a different area, you can allow them to search for a location using the Google Maps Geocoding API.


Was this article helpful?
This form is used for documentation feedback only. Learn how to get help with HubSpot.