Implementing location proximity search (for Belgium) with Drupal and Google Maps

This article is outdated. You should probably have a look at this handbook page for up to date information.

Imagine you would want to create a Google Map showing all shops in Belgium, and let your users enter their postal code and a distance range (in kilometers or miles) to filter the results to. This would allow a user to search for shops nearby his location. As you can see in the screenshot below our map shows only shops that are within a 20 kilometer range of Brussels.

To build this functionality you will need to download and install the following modules:

Some of these packages come with multiple modules, so these are the ones you'll need to enable: Location, GMap, GMap Location, Views and Views UI.

1Step 1: First, we will configure the GMap module. Go to admin/settings/gmap to do so.
Here you can configure how you want your Google Map to look and behave. Make sure to enter your Google API key. You might also want to check the autozoom option in the "Map behaviour flags" fieldset. Most of the other settings can be left at their default value for now.

2Step 2: Next we will configure the Location module settings at admin/settings/location.
You can adjust the settings so they match the following:

You can leave the other tabs of the Location settings pages untouched.

3Step 3: Now we have to assign location based data to a content type. You can either use an already existing content type, or create a new one specifically for this purpose. I created a content type "Shop", so we can create a node for each shop we want to show on the map.
To configure our content type to collection location data, go to the content type edit page (at admin/content/node-type/shop) and find the fieldset "Locative information".
Configure the first two included fieldsets as shown in the screenshots below:

We configure our content type to have one location assigned with it.
Next, we will define which location fields a user adding a shop node will be allowed or forced to enter. In my case I made the basic address fields required to make sure to have a complete address.

You can configure the other location settings as you wish, or leave them as they are. Now save your content type and go ahead and create some shop nodes. You will have the ability to enter location data on the node submission form.

4Step 4: Now we're going to make the Location module aware of the Belgian zipcodes and their latitude - longitude coordinates. The Location module already comes with this data, so all we need to do is import the file sites/all/modules/location/database/zipcodes.be.mysql into our database (e.g. use PHPMyAdmin to import this file).

Important: at the moment of writing there is still an issue with this file: latitude and longitude values are switched. You will need to run the following SQL query to fix this:

UPDATE zipcodes SET latitude =(@temp:=latitude), latitude = longitude, longitude = @temp

More information on this issue: http://drupal.org/node/566792

5Step 5: Now we will create a View which will show our shops on the map. I assume you have at least some basic knowledge on how to create and configure a View.

First of all, create a new View, and make sure to create a Page display. Also assign a path to this page, so your users can browse to the map.

A. Add fields

Add at least the following fields to your View, and make sure to exclude them from display (unless you have a reason to show this information in the Gmap marker):

  • Location: Distance / Proximity
    configuration options:
    Exclude from display: checked
    Units: Kilometers
    Origin: Use Distance / Proximity Filter
  • Location: Latitude
    configuration options:
    Label: Latitude
    Exclude from display: checked
    Display style: Decimal degrees
  • Location: Longitude
    configuration options:
    Label: Longitude
    Exclude from display: checked
    Display style: Decimal degrees
  • Any optional fields
    Any optional fields you add and don't exclude from display will show in the marker.
    I suggest adding at least "Node: Title".

B. Save the view

It is probably necessary to save the View now, so the Latitude and Longitude labels are stored, as we need them in the following step.

C. Basic settings

Configure the basic settings in your View as follows:

  • Style: GMap
    • configuration: Data source = Choose latitude and longitude fields
    • Latitude field: select "Latitude" from list
    • Longitude field: select "Longitude" from list
      Note: if the select list shows only blank items, you didn't set a label for the latitude / longitude fields! See A. Add fields.
  • Row style: fields
  • Use pager: No
  • Items to display: 0

D. Add filters

Add at least the following filters:

  • Node: Published = yes
  • Node: Type = [your content type] (e.g. Shop)
  • Location: Distance / Proximity
    • Expose this filter
    • Operator = Proximity (Circular)
    • Form mode = Postal code (assume default country)
    • Optional = checked

E. Save the view (again)

This should give you a basic working map, with proximity search exposted filters. You can come back and tweak your view some more to fit your specific needs.

For an alternate resource on creating this View, check out http://drupal.org/node/359463

6Step 6: This is the point where things are getting a bit dirty, as we're going to have to make changes to a file in the Location module. This is not considered good practice, so you should make sure you document this step properly or create a patch file, so you can reproduce this step if you should update your copy of the Location module.

Browse to sites/[all]/modules/location/supported/location.be.inc and add the function location_latlon_rough_be to this file, as described in this comment (step 2/): http://drupal.org/node/326749#comment-1235822

Finished!

After following the steps above, you should now have a map showing your shops at the URL path you specified in the View we created, with the ability to search for pinpoints in the area near a given postalcode.

If you have suggestions or questions about this tutorial, feel free to add a comment below.

Comments

First of all i would like to say that this is a very clear tutorial. I'm trying to make something simular for a Dutch site. I'm running into some problems tough.

First of all the Dutch postcode db wasn't freely available. You can buy it at www.postcode.nl for an insaine amount of money.

So i googled some more and found this site: http://kvdb.net/projects/6ppdev/

It's a project where ppl make their own database.

My question: would it be possible to convert it so i can be used in Drupal?

Thanks in advance :)

grtz Remco

Hi Remco,

I'm not sure whether this will be possible, since Dutch postal codes are a bit particular with the 2 letter extension. But looking at the CSV/XLS file fields, I guess you could get them into the DB structure the Location module needs (zipcode, name, lat, long & country).

I noticed there is some work being done in the Location issue queue to get this working. You might want to give the attached patch(es) there a try:
http://drupal.org/node/73714

Fist of all.. thank you for your respond.

I managed to convert the db i found with a small python i made. All is in the drupal db now tough i cannot seem to get the search function to work. I guess it still needs some more work. Let's see where things go wrong :)

Thanks , I have just been searching for info about this subject for a while and yours is the best I have found out till now.
However, what concerning the bottom line?
Are you sure about the supply?

Hey Sven,

I tried it over and over for a couple of times now but for some reason i cannot get it working.

I'm using:

Location: 6.x-3.1-rc1
GMap: 6.x-1.x-dev
Views: 6.x-2.7

This is how my settings are:

http://img8.imageshack.us/img8/3980/locator1.jpg

The next picture shows the preview output:

http://img195.imageshack.us/img195/9749/locator2.jpg

What wonders me is this line:

'Unknown' AS location_distance_0,

Im not sure if that is correct.

The last picture i will send you shows the output that i'll see on my page:

http://img195.imageshack.us/img195/8990/locator3.jpg

I hope you can help me sinds this is turning my head up-side-down :P

Thanks in advance

Grtz Remco

Got it working :) Seemed it was an error on my side. Great tutorial and thanks for the info :)

Hi Remco,
Great you solved the problem. Would you mind sharing what was the solution?

I think the admin of this website is really working hard in support of his
site, because here every stuff is quality based information.

Just one last question. Would it be possible that the filtered locations are being displayed right under the map?

I guess you could create an attachment display for that, that inherits the exposed filter values. That should work if I recall correctly.

How did you get this working? I'm getting exactly the same problem as you (i.e. no map or results being shown, if I remove the Location: Distance / Proximity filter I do get a map with all locations pinned).

Not sure what version of Views you are using on this tutorial (mine is 6.x-3.1-rc1), but when I go to the options of the Location: Distance / Proximity filter, underneath 'Form mode' it says FIXME, which leaves with no confidence this will actually work.
Might try a few other versions of Location.

Question for anyone... how do you make it so the map shows before you enter a zipcode? Currently I need to enter a zipcode and then the map shows.

Also, it would be helpful if you included what versions of modules this tutorial is for. I followed this to a 't' but the map would not show after entering a zipcode. I'm using Dupal 6.15, Location 6.x-3.0, GMap 6.x-1.0 and Views 6.x-2.8. I found that for this to work properly, the Data Source of Style: GMap needed to be "Location.module" vs. "Fields Latitude and Longitude".

In any event, thanks for this post... very helpful.

Have you put your "Location: Distance / Proximity" filter as optional (i.e. check the "Optional" checkbox in the filter configuration form)?

I have updated the post with the exact versions of the mentioned modules I used to build this.

Hope that helps

I spent whole day and finnaly your guide really makes my happy day.

Thinking back, I am shocked in the location dev version (currenty dated as 27-May), those 2 bugs ( lat / long ) and (addtional function required in the xx.inc) have not been fixed even it's so obviously.

Once again, I appreciate your good heart as I know you must spend many hrs fixing it too and put the guide together to people like us.

Ben

Thank you for step 6 :)

Any chance you can adapt this to using the city and state to do the proximity search rather than a zip code?

Thank you for this Tutorial, i take all i can get about this Modules!

But what's this fuss all about?

This one you choose fileds for Location: Distance / Proximity, Location: Latitude - Display style: Decimal degrees, Location: Longitude

I simply drop all of this, take Gmap Style and set the except the Data Source: location.module!

Add Filter, expose it and voila it works!

But please explain to me why you use this method with the extra fields, maybe i'am wrong

Hi

You said that you need to implement the pre_view hook to make the view 'dynamic'. I'm not sure I get that: are you referring to the fact that Views won't accept a zip code for its distance filter, so you need to have an up-to-date location? If so, do you think an alternative implementation could use a computed_field that generates the location from the zip code?

Thanks for the article,

Thank you so much for this tutorial.
I have spent many hours working on this and following other tutorials but I always ended up stuck or lost. Then, someone on a Drupal forum linked to this tutorial. You really laid it out well in a way that worked for me.

There were a couple of places where I would add a bit to your doc, perhaps due to me using new versions of the modules than you did.

Step 4: I was implementing for US postal codes and the file was too big to import using phpMyAdmin. I used an editor to break the file into chunks. For each chunk I kept the header data and had to scroll to the bottom to delete the last comma.

Step 5: When creating the view, one has to define what kind of data the view is for. I wasn't sure if I should choose 'Location' or 'Node'. I chose 'Node' and that turned out to be correct.

Step 5d: There was no Form Mode choice, but that didn't seem to matter. I also found the 'Remember user's last choice' to be quite a nice option.

After I got it working, I found it quite easy to go back and tweak the size of the map, the style of the flags, the data to appear in the pop-up bubbles, etc.

If anyone wants to see my results, they're at http://asiam.fm/counselors_zipcode.

Thanks again.

I don't know if you will get this, but your search does not appear to be working.

I think I will pray for a quick death after trying to implement any sort of drupal proximity.

Location - seems easy, have no idea the cause of the problem, have spent maybe 30 - 40 hours

Openlayers - may possibly avoid the need for a zip code table but can find no tutorials so not sure

Geo - think it causes an error message upon installation.

If you get this and have any ideas I would so appreciate it. I thought Views was hard but there are books on that.

Take care.

Hi,

Thanks to your tutorial I managed to implement this for a site I'm doing in Sweden. I first had to compile a zipcodes.se.mysql file for sweden since this wasn't included in the location module.

I even edited the code in your fix for location.xx.inc in order to search by city. The LIMIT 0,30 came from the fact that there were too many results for Stockholm which was corrupting the results array.

Cheers again

Sam

<?php
function location_latlon_rough_se($location = array()) {
  if (!isset($location['postal_code'])) {
    return NULL;
  }

  $result = db_query("SELECT latitude, longitude FROM {zipcodes} WHERE country = '%s' AND zip = '%s' OR city LIKE '%s' LIMIT 0,30 ", $location['country'], $location['postal_code'],$location['postal_code']);
 
  if ($row = db_fetch_object($result)) {
    return array('lat' => $row->latitude, 'lon' => $row->longitude);
  }
  else {
    return NULL;
  }
}
?>

Everyone loves what you guys are usually up too.

Such clever work and exposure! Keep up the very good works guys I've included you guys to blogroll.

Maybe it is just me, but the comments dont seem readable to me? (except for the last one bij allecthomson)
I just see a (small portion of) the title. See below for an example.
These aren't linking to the complete comment (but to e.g. http://www.svendecabooter.be/comment/47#comment-47 )
Using ff 3.6.13

----- example (permalink and avatar deleted)
Remco - 5 November, 2009 - 15:24
Dutch postcode database

Sven - 8 November, 2009 - 15:18
Hi Remco, I'm not sure

Remco - 9 November, 2009 - 08:48
Thanks Sven :)

Hi,

There was indeed a problem with the comments that were on the site before I did a recent migration.
I have restored the contents of those comments now.

The implementation of Drupal and Google map through this location proximity is cool.I think this proximity will elaborate the system in various ways which will help them in many respects.

Hi Sven,

This is very close to something I need to implement on a Drupal site, but I unfortunately can't get it to work.
I followed your instructions, but for some reason the results page only shows the "No results found" text, and no filters are visible (although I did expose them in the view).

I think the solution might be in one of the comments left, but I have the same issue as Mark noted in comment # 1595; only part of the title is visible for most comments.

Any help is truly appreciated.

Best,

Oussama

Hi,

There was indeed a problem with the comments that were on the site before I did a recent migration.
I have restored the contents of those comments now.

Hi Sven,

Thank you for putting the comments back in.

I found a great patch for the location module which adds a proximity filter of type address/country which allows the user to input the address in a textfield to be geocoded. The resulting lat/lon is used to filter the view's results.

The advantage of such a filter is that it no longer requires the data of the zipcodes table, and thus easily works for worldwide addresses.

The patch can be found at http://drupal.org/node/431912#comment-4074874

Best,

Oussama

After long searching why the longitude and latitude stays empty, i discoverde I have to set the Belgium option in :
admin/settings/location/geocoding
Thanks a lot Sven for this clear tutorial !

Thanks for this great tutorial! But there is one thing that I can't find out:
I made it all work but can't get all nodes to show up in 1 map.
At the moment all nodes show up in different maps underneath each other. I've been trying to solve this problem for a long time now but I can't find the solution.

Is there anybody here who can help me with this?

You can try it at: www.hopp-health.com/dealers
and for example fill in postcode 2312.

Thanks very much!

Tulipboy

Think this tutorial http://code.google.com/intl/da/apis/maps/articles/phpsqlsearch_v3.html will interest some of you.

I'm surprised that you HAVE to upload diff. zipcode databases and that it's not included in Drupal modules. Maybe some of you can figure out how to use some of the code and include it so people don't have to upload diff. zipcode databases?

I made this without using ANY drupal map module http://www.tinemuller.dk/new_new_test_drupal/node/1394 but with the code from this tutorial but would love to get this to work with drupal map modules but not beeing a programmer I can't figure out to make such a module myself.

/Tine

Fantastic! Actually I was looking at Google map today and heck, it's nice.

Videos for you to learn from http://torontowebsitedeveloper.com/drupal-video-tutorials

Maybe also this video http://chicago2011.drupal.org/sessions/making-beautiful-maps will interest some of you.

On http://beta.findtoilet.dk/ I use module Gmap and Locations and a private module called toilet_map.module but the reason why this map looks so great are because we link to javascript files which use Google Maps API v3 code like this:

// add the map interface javascript files and inline code
drupal_add_js($path .'/js/FindToiletMap.js');
drupal_add_js($path .'/js/init_v3.js');
drupal_add_js(_toilet_map_js_event(), 'inline');

/Tine

Then your face looks brighter to reduce the appearance of
wrinkles, as a result, and you will look younger. Acai's Health Benefits-- A Natural
Weight Loss Answer. In addition, the acai berry contains a considerable amount of fiber, which helps to
feel fuller faster and reduce sudden cravings for food and the need
to endlessly snack.

This would be a great idea specially if the owner wants to collect more information about how customers finds his shop, or a business can develop this then probably use the data for further enhancement.

I don't think I would have figured this out on my own. Many thanks for posting this tutorial!!! MORE please :)))

Hello, thanks for the excellent tutorial. I got everything partially working. For some reason, the map doesn't show until I enter a zip code and click apply.

I followed all the steps and made sure I set Location: Distance / Proximity filter to optional

Any ideas?

Thanks again!

cool!

Hello! Do you use Twitter? I'd like to follow you if that would be ok. I'm
definitely enjoying your blog and look forward to new updates.

The software has a Outlook-similar interface and previews messages
in 3-panes. The Industrial Revolution was another of
those extraordinary jumps forward in the story of civilization.
What this means is that no matter how much the cleaner fills up, there is no loss of suction power.

Maybe some of you can figure out how to use some of the code and include it so people don't have to upload diff. zipcode databases?

Hello every body,

Im in Drupal 7 and followed the tuto but not able to get it working

Is there a specific setting for view to get it working with D7

thank you in advance for your help

This post was written in the Drupal 6 era, so it's somewhat outdated.
I propose you have a look at the following drupal.org docs page: http://drupal.org/node/1714680

you mean that it is not possible with D7?

i would like using Gmap but not openLayer

Perhaps it's possible, but i've only focussed on OpenLayers in Drupal 7, so I can't really give any advice on the status of the GMap module in D7.