Geocoding Customer Addresses in Magento via Google Maps

Geocoding Customer Addresses in Magento via Google Maps

Geocoding is the process of finding associated geographic coordinates (often expressed as latitude and longitude) from other geographic data, such as street addresses, or zip codes (postal codes)… so says Wikipedia. Geocoding an address is pretty simple if you are using Google Maps API. Since all we do here is Magento, let me show you how easily you can geocode customer address.

We will start with adding the Gmap.php helper to our extension:

<?php
/**
* @author Branko Ajzele <ajzele@gmail.com>
*/
class Inchoo_Extension_Helper_Gmap extends Mage_Core_Helper_Abstract
{
const GOOGLE_MAPS_HOST = 'maps.google.com';
const CONFIG_PATH_GOOGLE_MAPS_API_KEY = 'inchoo_google/maps/api_key';
 
public function getGoogleMapsApiKey()
{
return Mage::getStoreConfig(self::CONFIG_PATH_GOOGLE_MAPS_API_KEY);
}
 
/**
*
* @param Mage_Customer_Model_Address $address
* @param boolean $saveCoordinatesToAddress
* @param boolean $forceLookup
* @return array Returns the array of float values like {[0] => float(18.4438156) [1] => float(45.5013644)}
*/
public function fetchAddressGeoCoordinates(Mage_Customer_Model_Address $address, $saveCoordinatesToAddress = true, $forceLookup = false)
{
/**
* USAGE EXAMPLE
 
$customer = Mage::getModel('customer/customer');
$customer->setWebsiteId(Mage::app()->getWebsite()->getId());
$customer->loadByEmail('some-email@domain.com');
 
Mage::helper('inchoo/gmap')->fetchAddressGeoCoordinates($customer->getDefaultBillingAddress())
 
*/
 
$coordinates = array();
 
if ($address->getId() && $address->getGmapCoordinatePointX() && $address->getGmapCoordinatePointY() && $forceLookup == false) {
$coordinates = array($address->getGmapCoordinatePointX(), $address->getGmapCoordinatePointY());
} else if (!$address->getGmapCoordinatePointX() && !$address->getGmapCoordinatePointY())
OR ($address->getId() && $address->getGmapCoordinatePointX() && $address->getGmapCoordinatePointY() && $forceLookup == true)) {
 
$lineAddress = $address->getStreet1(). ', '.$address->getPostcode().' '.$address->getCity().', '.$address->getCountry();
 
$client = new Zend_Http_Client();
$client->setUri('http://'.self::GOOGLE_MAPS_HOST.'/maps/geo');
$client->setMethod(Zend_Http_Client::GET);
$client->setParameterGet('output', 'json');
$client->setParameterGet('key', $this->getGoogleMapsApiKey());
$client->setParameterGet('q', $lineAddress);
 
$response = $client->request();
 
if ($response->isSuccessful() && $response->getStatus() == 200) {
$_response = json_decode($response->getBody());
$_coordinates = @$_response->Placemark[0]->Point->coordinates;
 
if (is_array($_coordinates) && count($_coordinates) >= 2) {
 
$coordinates = array_slice($_coordinates, 0, 2);
 
if ($saveCoordinatesToAddress) {
try {
$address->setGmapLng($coordinates[0]);
$address->setGmapLat($coordinates[1]);
 
$address->save();
} catch (Exception $e) {
Mage::logException($e);
}
}
}
}
}
 
return $coordinates;
}
}

As you can see above in the code, function getGoogleMapsApiKey() pulls the API key info from my system configuration. I will not show you that part here. So for the sake of simplicity if you do not know how to code a configuration for your module you can just return a raw API key string here (surely this approach is then just for testing/playing not on production).

Since this helper references the two non-defualt-existing attributes on the address we will need to add those attributes. We do so trough install/upgrade scripts (you know, the files under app/code/{codePool}/Company/Extension/sql/extension_setup/ folder). I will not give you the full example of the file and it’s corresponding config.xml entry, as you should know how to do it yourself already, rather just the partial code that goes into the install/upgrade script in order to add the two missing customer address attributes:

//Add attribute that will be used for Google Maps as a coordinate lng
$installer->addAttribute('customer_address', 'gmap_lng', array(
'type' => 'varchar',
'input' => 'hidden',
'visible' => false,
'required' => false
));
//Add attribute that will be used for Google Maps as a coordinate lat
$installer->addAttribute('customer_address', 'gmap_lat', array(
'type' => 'varchar',
'input' => 'hidden',
'visible' => false,
'required' => false
));

Next, we will add the observer to the proper _beforeSave() dispatched event of the Mage_Customer_Model_Address model class. Since Mage_Customer_Model_Address extends the Mage_Customer_Model_Address_Abstract which defines the “protected $_eventPrefix = ‘customer_address’;” we can easily conclude the all it takes is to create observer for “customer_address_save_before” event (Mage_Core_Model_Abstract::_beforeSave() … we have Mage::dispatchEvent($this->_eventPrefix.’_save_before’, $this->_getEventData());).

So we add something like this to the config.xml file of our extension:

<global>
 
<events>
<customer_address_save_before>
<observers>
<inchoo_observer_customer_address_save_before>
<type>singleton</type>
<class>Inchoo_Extension_Model_Observer</class>
<method>geocodeAddress</method>
</inchoo_observer_customer_address_save_before>
</observers>
</customer_address_save_before>
</events>
 
</global>

Then we create the observer Inchoo_Extension_Model_Observer with something like:

Within that observer we simply need to call something like:

<?php
class Inchoo_Extension_Model_Observer
{
public function geocodeAddress()
{
Mage::helper('inchoo/gmap')
->fetchAddressGeoCoordinates($observer->getEvent()->getCustomerAddress());
 
return $this;
}
}

Basically that’s it. Now each time an address is saved in Magento, there should be a lookup on Google Maps API in order to fetch the longitude and latitude coordinates. Please note, that all of this is just to fetch the coordinates and save them under the address. Showing the actual map somewhere on the frontend or backend requires a bit more input.

To show the Google Map on the frontend with the proper location marker shown on the map you need two things. First we need to add the script like shown below to the head part of the page:

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=<?php echo Mage::helper('inchoo/gmap')->getGoogleMapsApiKey() ?>&sensor=false"></script>

Then finally we need to add something like:

<div id="address<?php echo $_address->getId() ?>-gmap" style="width:480px; height:480px;"></div>
 
<script type="text/javascript">
//<![CDATA[
 
Event.observe(window, 'load', function() {
 
var myLatlng = new google.maps.LatLng(<?php echo $_address->getGmapLat() ?>,<?php echo $_address->getGmapLng() ?>);
var myOptions = {
zoom: 4,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("address<?php echo $_address->getId() ?>-gmap"), myOptions);
 
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title:"Address Location"
});
 
});
//]]>
</script>

And that’s it. Please note, the code above might not be fully copy paste, check the JavaScript when you implement it, and test if your customer address attributes are installed correctly. This article is not for Magento beginners so if you experience some difficulties implementing this approach, please consult the Magento Knowledge Base first.

P.S. I was playing with this on Magento CE 1.6.1.0.

Hope this was helpful. Cheers.

You made it all the way down here so you must have enjoyed this post! You may also like:

How To Connect Google Analytics 4 To Magento 2 Bojan Mareljic
Bojan Mareljic, | 36

How To Connect Google Analytics 4 To Magento 2

Magento 2 Product Quick View Tomas Novoselic
, | 6

Magento 2 Product Quick View

Optimize Elasticsearch autocomplete URL for Google Analytics Matej Djakovic
Matej Djakovic, | 2

Optimize Elasticsearch autocomplete URL for Google Analytics

7 comments

  1. is there a way to use this for setting locations? i have different gym locations that i want to geolocate after a user scans a qr code. I know how this pertains to address geolocation so im assuming that i could take the lat and long then write it directly to the database. THe problem is how do i take the geolocation and tie it directly to that user? O_O im stumped there

  2. Hello. You save customer’s lat/lng as hidden attributes, but what if customer has more than one billing/shipping addresses? You can use native google maps api to find out lat/lng by address and show location on the fly.

    <script type="text/javascript">
    //<![CDATA[
        var map = null;
        var geocoder = null;
    
        function initialize() {
            if (GBrowserIsCompatible()) {
                map = new GMap2(document.getElementById("map_canvas"));
                map.setCenter(new GLatLng(0, 0), 13);
                geocoder = new GClientGeocoder();
            }
        }
    
        function showAddress(address) {
            initialize();
            if (geocoder) {
                geocoder.getLatLng(
                address,
                function(point) {
                    if (!point) {
                        alert(address + " not found");
                    } else {
                        map.enableScrollWheelZoom();
                        map.setCenter(point, 13);
                        var marker = new GMarker(point);
                        map.addOverlay(marker);
                    }
                })
            }
        }
        Event.observe(window, 'load', function() {
            showAddress('<?php echo $this->getAddress() ?>');
        });
    //]]>    
    </script>
    <div id="map_canvas"></div>

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.

Tell us about your project

Drop us a line. We'd love to know more about your project.