I am working on a local business directory site that will use custom post types for the business entries. One of the fields will be “Zip Code.” How can I set up a location based search?
I’d like visitors to be able to enter their zip code and choose a category and show all the businesses withing a certain radius, or all the businesses ordered by distance. I saw a couple plugins that claim to do this but they don’t support WordPress 3.0. Any suggestions?
I would modify the answer from gabrielk and the linked blog post by using database indexes and minimizing the number of actual distance calculations.
If you know the coordinates of the user and you know the maximum distance (say 10km), you can draw a bounding box that is 20km by 20km with the current location in the middle. Get these bounding coordinates and query only stores between these latitudes and longitudes. Do not yet use trigonometry functions in your database query, as this will prevent indexes from being used. (So you might get a store that is 12km away from you if it is in the north-east corner of the bounding box, but we throw it out in the next step.)
Only calculate the distance (as the bird flies or with actual driving directions, as you prefer) for the few stores that are returned. This will drastically improve processing time if you have a large number of stores.
For the related lookup (“give the ten nearest stores”) you can do a similar lookup, but with an initial distance guess (so you start with a 10km by 10km area, and if you don’t have enough stores you expand it to 20km by 20km and so on). For this initial distance guess you once calculate the number of stores over the total area and use that. Or log the number of queries needed and adapt over time.
I added a full code example at Mike’s related question, and here is an extension that gives you closest X locations (quick and barely tested):
First you need a table that looks something like this:
…populated for each zip code. You can expand on this by adding city and state fields if you want to look up that way.
Then each store can be given a zip code, and when you need to calculate distance you can join the lat/long table to the store data.
Then you’ll query that table to get the latitude and longitude for the store and user’s zip codes. Once you get it you can populate your array and pass it to a “get distance” function:
This is meant as a proof-of-concept, not code that I would actually recommend implementing. If you have 10,000 stores, for example, it would be a pretty expensive operation to query them all and loop through and sort them on every request.
The MySQL documentation also includes information on spatial extensions. Oddly, the standard distance() function isn’t available, but check this page:
http://dev.mysql.com/tech-resources/articles/4.1/gis-with-mysql.html
for details on how to “convert the two POINT values to a LINESTRING and then compute the length of that.”
Note that every vendor is likely to offer different latitudes and longitudes representing the “centroid” of a zip code. It’s also worth knowing that there are no real defined zip code “boundary” files. Each vendor will have its own set of boundaries that roughly match the specific lists of addresses that make up a USPS zip code. (For instance, in some “boundaries” you would need to include both sides of the street, in others, just one.) ZIP Code Tabulation Areas (ZCTAs), widely used by vendors, “do not precisely depict ZIP Code delivery areas, and do not include all ZIP Codes used for mail delivery” http://www.census.gov/geo/www/cob/zt_metadata.html
Many downtown businesses will have their own zip code. You’ll want as complete a dataset as possible, so be sure that you find a list of zipcodes that includes both “point” zip codes (usually businesses), and “boundary” zip codes.
I have experience working with the zipcode data from http://www.semaphorecorp.com/. Even that wasn’t 100% accurate. For instance, when my campus took on a new mailing address and new zip code, the zip was misplaced. That said, it was the only data source I found that even HAD the new zip code at all, so soon after it was created.
I had a recipe in my book for exactly how to meet your request… in Drupal. It relied on the Google Maps Tools module ( http://drupal.org/project/gmaps, not to be confused with http://drupal.org/project/gmap, also a worthy module.) You might find some helpful sample code in those modules, though of course, they won’t work out of the box in WordPress.