Skip to main content

How to: Dealer Locator extension for Magento


In this article I will try to explain how to build a “Dealer Locator” extension for Magento. This article is all about extension concepts, structure and planing and not the code itself.
First we will start with scoping the feature. What functionality should it have? In our example, let’s imagine a client that wants a dealer locator to have “Search by nearest dealer based on ZIP/Postcode”, “Search by State”, “Search by dealer company name”. Search results should be displayed primarily on Google Map, plus it would be nice to have a table listing for those disliking the map visual style.
If we extend this a bit further, we soon come to realisation that “dealers” themselves should be a customers in our Magento system. Justification for this lies in a fact that dealers should be able to do a regular purchases on our Magento store like any other customer just with special prices applied to products. Since customer in Magento has to have a customer group assigned to it, and products special pricing can be applied for each customer group. Thus all we need to do in order to “convert” dealers to customers is to create a customer group “Dealer” or even use “Wholesale” for these types of customers. Then on each product set a special price for that customer group, that is if the dealers will have special prices.
Now, since dealers are just customers in our system then customer address(es) can be used for dealer locations. And this realization is the basis of our “Dealer locator” extension. Now that we have the general picture set, lets make a wireframe of the “Dealer locator” functionality.

Once the wireframe is approved by the client we can start with the preparations for development. Now, if we look back at the original requirement: “Search by nearest dealer based on ZIP/Postcode”, “Search by State”, “Search by dealer company name” we can easily see that “Search by nearest dealer based on ZIP/Postcode” part will be the most challenging one. “Search by State”, “Search by dealer company name” are straightforward as this is the direct property of each customer address. “Search by nearest dealer based on ZIP/Postcode” is something we will need to use certain calculations that involve geocode data.
General approach we will take towards “Search by nearest dealer based on ZIP/Postcode”:
- We will create an install script, for example app/code/community/Inchoo/Dealerlocator/sql/inchoo_dealerlocator_setup/install-1.0.0.0.php that adds two additional attributes to the customer address entity: inchoo_geo_latitude, inchoo_geo_longitude
- We will observe “customer_address_save_before” event and trigger a Inchoo_Dealerlocator_Model_Observer->injectLatLongIntoAddress() method once the event is fired. Note, injectLatLongIntoAddress is freely taken/chosen method name
- Within injectLatLongIntoAddress() we will execute a code that “contacts” the Google Maps API maps.google.com/maps/geo sending it the customer address information (namely street, postcode, city, country) then parses the response into the inchoo_geo_latitude, inchoo_geo_longitude properties of an address. Since we are observing customer_address_save_before event this data is then simply saved to customer address
- Once we have geo latitude and longitude data saved on each address we can now query the address collection for this information
- We still lack one important ingredient in this “Search by nearest dealer based on ZIP/Postcode” request, thats the “nearest”. We need to come up with a way to calculate the distance between two geo coordinates. There is a nice MySQL code snippet for this http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe#MySQL. All we need to do is to transform to Magento collection :)
- Finally, the same way we did a geo mapping in the “customer_address_save_before” event for each address save, we will do a live geo mapping of the provided “referencing ZIP/Postcode”, the one that is provided on the frontend input text field. This way we have two geo location coordinates between which we calculate the distance: the referencing ZIP/Postcode geo coordinates vs. specific customer address geo coordinates
- Now we should have all pre-requirements for building the “Search by nearest dealer based on ZIP/Postcode”, we have latitude and longitude, we have distance.
I’m gonna be kind enough to provide you with my example of code for injectLatLongIntoAddress():


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$coordinates = array();$saveCoordinatesToAddress = 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->setInchooGeoLongitude($coordinates[0]);                $address->setInchooGeoLatitude($coordinates[1]);                $address->save();            } catch (Exception $e) {                Mage::logException($e);            }        }    }}
Please note the $saveCoordinatesToAddress variable. If we pack the code above into a separate method we can reuse it for live geo mapping of the provided “referencing ZIP/Postcode” as well.
And here is the Magento customer collection object with included addresses and “distance” value calculation:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function getNearbyDealersLocations($radius, $centerLat, $centerLng)
{
    $customerGroup = Mage::getModel('customer/group');
    $customerGroup->load('Dealer', 'customer_group_code');
    if (!$customerGroup->getId()) {
        throw new Exception($this->__('Unable to load the customer group.'));
    }
    $collection = Mage::getResourceModel('customer/customer_collection')
                        ->addNameToSelect()
                        ->addAttributeToFilter('group_id', array('eq'=>$customerGroup->getId()))
                        ->joinAttribute('billing_company', 'customer_address/company', 'default_billing', null, 'left')
                        ->joinAttribute('inchoo_geo_latitude', 'customer_address/inchoo_geo_latitude', 'default_billing', null, 'left')
                        ->joinAttribute('inchoo_geo_longitude', 'customer_address/inchoo_geo_longitude', 'default_billing', null, 'left')
                        ->addAttributeToFilter('inchoo_geo_latitude', array('notnull'=>true))
                        ->addAttributeToFilter('inchoo_geo_longitude', array('notnull'=>true))
                        ->addExpressionAttributeToSelect('distance', sprintf("(3959 * acos(cos(radians('%s')) * cos(radians(at_inchoo_geo_latitude.value)) * cos(radians(at_inchoo_geo_longitude.value) - radians('%s')) + sin(radians('%s')) * sin( radians(at_inchoo_geo_latitude.value))))",   $centerLat, $centerLng, $centerLat, $radius), array('entity_id'));
    if ($radius !== 0) {
        $collection->getSelect()->having('distance < ?', $radius);
    }
    $collection->getSelect()->order('distance ' . Varien_Db_Select::SQL_ASC);
    //echo (string)$collection->getSelect(); exit;
    return $collection;
}


With the above in place you all that remains is to output the search results into the table or into the Google Map. There are plenty of example codes out there that show how to embed google maps with marker so I’m not going to cover this here. As mentioned at the beginning, the purpose of article is not to give a code ready solution but to give you an overview of the process that latter can then be given to developer so he can develop the feature.

courtsy: Branko Ajzele

Comments

Popular posts from this blog

Financial Engineering

Financial Engineering: Key Concepts Financial engineering is a multidisciplinary field that combines financial theory, mathematics, and computer science to design and develop innovative financial products and solutions. Here's an in-depth look at the key concepts you mentioned: 1. Statistical Analysis Statistical analysis is a crucial component of financial engineering. It involves using statistical techniques to analyze and interpret financial data, such as: Hypothesis testing : to validate assumptions about financial data Regression analysis : to model relationships between variables Time series analysis : to forecast future values based on historical data Probability distributions : to model and analyze risk Statistical analysis helps financial engineers to identify trends, patterns, and correlations in financial data, which informs decision-making and risk management. 2. Machine Learning Machine learning is a subset of artificial intelligence that involves training algorithms t...

Wholesale Customer Solution with Magento Commerce

The client want to have a shop where regular customers to be able to see products with their retail price, while Wholesale partners to see the prices with ? discount. The extra condition: retail and wholesale prices hasn’t mathematical dependency. So, a product could be $100 for retail and $50 for whole sale and another one could be $60 retail and $50 wholesale. And of course retail users should not be able to see wholesale prices at all. Basically, I will explain what I did step-by-step, but in order to understand what I mean, you should be familiar with the basics of Magento. 1. Creating two magento websites, stores and views (Magento meaning of website of course) It’s done from from System->Manage Stores. The result is: Website | Store | View ———————————————— Retail->Retail->Default Wholesale->Wholesale->Default Both sites using the same category/product tree 2. Setting the price scope in System->Configuration->Catalog->Catalog->Price set drop-down to...

How to Prepare for AI Driven Career

  Introduction We are all living in our "ChatGPT moment" now. It happened when I asked ChatGPT to plan a 10-day holiday in rural India. Within seconds, I had a detailed list of activities and places to explore. The speed and usefulness of the response left me stunned, and I realized instantly that life would never be the same again. ChatGPT felt like a bombshell—years of hype about Artificial Intelligence had finally materialized into something tangible and accessible. Suddenly, AI wasn’t just theoretical; it was writing limericks, crafting decent marketing content, and even generating code. The world is still adjusting to this rapid shift. We’re in the middle of a technological revolution—one so fast and transformative that it’s hard to fully comprehend. This revolution brings both exciting opportunities and inevitable challenges. On the one hand, AI is enabling remarkable breakthroughs. It can detect anomalies in MRI scans that even seasoned doctors might miss. It can trans...