I could not find a snippet to do this, so I made one. This is a proof of concept and very simple. It might not be a solution for "picky" clients. But It does a pretty good job.
To make things fast I use a local database of zipcodes (I sure it could be adapted for your local country). I found a free source of zips and coordinates that was good enough for what I needed.
http://www.thedigitalmapstore.com/Free_Stuff/ZIP_Code_Database/
I used phpMyAdmin to create a table (zipcodes) to import the data into. I then created another table for the list of stores with the longitude and latitudes. I manually put them in for testing, but in the real world I will probably find some tutorial on scraping using some geocoding service.
Here is my snippet. Basically uses pulls in a chunk for the search form then passes the info to the loopDbChunk snippet.
<?php
// Title: StoreLocator
// Description: a quick store finder script
// Author: Brian Wente
$zip = $modx->db->escape($_POST['zip']);
function fetch($tpl){
// based on version by Doze at http://modxcms.com/forums/index.php/topic,5344.msg41096.html#msg41096
global $modx;
$template = "";
if ($modx->getChunk($tpl) != "") {
$template = $modx->getChunk($tpl);
} else if(substr($tpl, 0, 6) == "@FILE:") {
$template = $this->get_file_contents(substr($tpl, 6));
} else if(substr($tpl, 0, 6) == "@CODE:") {
$template = substr($tpl, 6);
} else {
$template = FALSE;
}
return $template;
}
if(isset($_POST['submitted'])){
if(isset($zip)){
$modx->setPlaceholder('zip', $zip);
}
$output .= fetch($results);
$zipLookup = $modx->db->select( '`lat`,`long`', 'zipcodes', 'zip=' . $zip . '', '', '0, 1');
$row = $modx->db->getRow( $zipLookup );
$lookupLat = $row['lat'] ;
$lookupLong = $row['long'] ;
$output .= "<div id='map-side-bar'>";
// Call loopDbChunk Snippet
$output .= $modx->runSnippet('loopDbChunk', array(
'sql' => 'SELECT *, round(sqrt(power(69.1 * (latitude - ' . $lookupLat . ') , 2 ) + power( 69.1 * (longitude - ' . $lookupLong . ') * cos(latitude / 57.3 ) , 2 )),2) AS distance FROM stores ORDER BY distance ASC',
'chunkName' => 'displayZips',
'perPage' => '5',
'orderby' => 'distance',
));
$output .= "</div>";
} else {
$output .= fetch($form);
}
return $output;
?>
I used Doze’s bit of code to call the chunk. Then devtrench’s
http://www.devtrench.com/tools/modx-snippet-call2php/ to convert Amir’s loopDbChunk call into something that I could run in my snippet.
Here is the call on the page.
[!storeLocator? &form=`searchstore_form` &results=`search_results`!]
searchstore_form
<form method="POST" name="locator">
<input type="hidden" value="true" name="submitted" />
<dl>
<dt>ZIP code</dt><dd><input type="text" name="zip" /></dd>
<dd><input type="submit" value="Search" /></dd>
</dl>
</form>
search_results
<strong>Searched for: </strong>[+zip+]
Here is the loopDbChunk
<div class="map-location" data="{id: [+lo_ord+], point: {lat: [+latitude+], lng: [+longitude+]}, category: 'store'}">
<a href="#" class="map-link">[+name+] [+distance+] miles</a>
<div class="info-box">
<p class="info">[+name+]</p>
<p class="info">[+address+]</p>
<p class="info">[+city+], [+state+]</p>
</div>
</div>
Then to make it easier on me I used Brian Landau’s jQuery plugin for creating Google Maps from semantic markup --
http://vigetlabs.github.com/jmapping/
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Store Locator</title>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key=your-google-api-key" type="text/javascript"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="assets/js/mapiconmaker.js" type="text/javascript"></script>
<script src="assets/js/markermanager.js" type="text/javascript"></script>
<script src="assets/js/jquery.metadata.js" type="text/javascript"></script>
<script src="assets/js/jquery.jmapping.js" type="text/javascript"></script>
</head>
<body>
[*#content*]
<div id="map" style="width:360px;height:280px"></div>
<script type="text/javascript">
$(document).ready(function(){
$('#map').jMapping({
category_icon_options: {
'store': {primaryColor: '#7CDF65', cornerColor: '#FFFFFF', shape: 'roundrect'},
'default': {primaryColor: '#7CDF65'}
}
});
});
</script>
</body>
</html>
I installed dbEdit to manage the store list.
Items used:
loopDbChunk -
http://modxcms.com/forums/index.php?topic=14654.0
MODx Snippet Call2PHP -
http://www.devtrench.com/tools/modx-snippet-call2php/
zipcodes -
http://www.thedigitalmapstore.com/Free_Stuff/ZIP_Code_Database/
jMapping -
http://vigetlabs.github.com/jmapping/
dbEdit -
http://modxcms.com/forums/index.php/topic,32720.0.html
Sorry I do not have a public demo. I just developed it on my local box.
Please feel free to improve upon the code and or logic. I also added this to the wiki.
http://wiki.modxcms.com/index.php/Store_Locator