Magento 2 is a powerful ecommerce platform that offers extensive customization capabilities. Integrating it with the Google Maps API allows you to leverage the vast location data provided by Google to offer enhanced features to your customers. Providing a seamless and convenient shopping experience is crucial. One way to enhance customer satisfaction is by helping them locate the nearest store locations quickly and efficiently. 

In this blog post,  In this tutorial, we’ll show you how to create an Ajax-based functionality that returns the nearest store locations based on the user’s zip code. We’ll also learn more about Magento 2 implementation that uses the Google Maps API to find the nearest stores based on a user’s zip code. 

Why Implement a Nearest Store Locator?

Implementing the nearest store locator offers several benefits:

  • Improved Customer Experience: Helps customers find the nearest physical stores easily.
  • Increased Foot Traffic: Encourages online shoppers to visit physical stores.
  • Brand Trust: Provides transparency and convenience, enhancing customer trust in your brand.

10 Steps to Implement Magento 2 with the Google Maps API

Step 1: Create a Google Maps API Key

  1. Google Maps API Key: You need a Google Maps API key to access Google Maps services. You can obtain it from the Google Cloud Platform.
  2. Magento 2 Setup: Ensure you have a Magento 2 installation running.
  3. Visit the Google Cloud Console.
  4. Create a new project or select an existing one.
  5. Navigate to the “API & Services” section.
  6. Enable the following APIs:
  1. Maps JavaScript API
  2. Places API
  3. Geocoding API

      7. Generate an API key and restrict its usage to your domain for security purposes.

Step 2: Create a “registration.php”

app/code/DCKAP/NearInstallationStore/registration.php

<?php

<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(ComponentRegistrar::MODULE, DCKAP_NearInstallationStore, __DIR__);

Step 3: Create a “Module.xml”

app/code/DCKAP/NearInstallationStore/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="DCKAP_NearInstallationStore" setup_version="1.0.7">  
    </module>
</config>

Step 4: Create a “routes.xml”

app/code/DCKAP/NearInstallationStore/etc/frontend/routes.xml

<?xml version="1.0"?>
<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd">
   <router id="standard">
        <route id="dckap_nearinstallationstore" frontName="dckap_nearinstallationstore">
            <module name="DCKAP_NearInstallationStore" />
        </route>
    </router>

   </router>
</config>

Step 5: Setup Google Map API Credentials

First, configure your Google Map API credentials in Magento 2, and here’s how you can do it:

app/code/DCKAP/NearInstallationStore/etc/adminhtml/system.xml

<?xml
Copy code
<?xml version="1.0" ?>
<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>  
        <section id="dckap_nearinstallationstore" translate="label" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
            <label>Google Map Services</label>
            <tab>dckap</tab>
            <resource>DCKAP_NearInstallationStore::config_nearinstallationstore</resource>
            <group id="api_credentials" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Google Map API Credentials</label> 
                <field id="google_map_key" translate="label" type="text" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Google Map Key</label>
                </field> 
            </group> 
        </section>  
    </system>
</config>

Step 6: Create the Helper Class

Create a helper class to fetch the Google Map API key from the configuration:

app/code/DCKAP/NearInstallationStore/Helper/Data.php

<?php

<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->


namespace DCKAP\NearInstallationStore\Helper;

use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Store\Model\ScopeInterface;

class Data extends AbstractHelper
{
    const XML_PATH_GOOGLE_MAP_KEY = dckap_nearinstallationstore/api_credentials/google_map_key';

    /**
     * @param null $store
     * @return mixed
     */
    public function getGoogleMapKey($store = null)
    {
        return $this->scopeConfig->getValue(self::XML_PATH_GOOGLE_MAP_KEY, ScopeInterface::SCOPE_STORE, $store);
    }
}

Step 7: Controller for Ajax Request

Create a controller to handle the Ajax request and fetch the nearest store locations:

app/code/DCKAP/NearInstallationStore/Controller/Ajax/GetNearestStoresLocations.php

<?php

<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->

<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->

namespace DCKAP\NearInstallationStore\Controller\Ajax;
use Magento\Framework\App\Action\Action; 
use Magento\Framework\Controller\Result\JsonFactory;
use DCKAP\NearInstallationStore\Model\StoreFactory;
use DCKAP\NearInstallationStore\Helper\Data;

class GetNearestStoresLocations extends Action
{
    protected $resultJsonFactory;
    protected $storeFactory;
    protected $helperData;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        JsonFactory $resultJsonFactory,
        StoreFactory $storeFactory,
        Data $helperData
    ) {
        $this->resultJsonFactory = $resultJsonFactory;
        $this->storeFactory = $storeFactory;
        $this->helperData = $helperData; 
        parent::__construct($context);
    }

    public function execute()
    {
        if ($this->getRequest()->isAjax()) {
            $id = $this->getRequest()->getParams('q'); 
            $zipCode = $id['q'];
            $googleMapKey = $this->helperData->getGoogleMapKey(); 
            $result = $this->resultJsonFactory->create();  
            $installationStore = $this->storeFactory->create();   
            $installationStoreDet = $installationStore->getCollection();
 
            $array = [];

            foreach ($installationStoreDet as $installationStore) { 
                $locDet = [];    
                $locDet = $installationStore->getAddress();  
                array_push($array, $locDet); 
            }  

            $List = implode('|', $array); 
                
            $distanceDurationUrl = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=".$zipCode."&destinations=".urlencode($List)."&units=imperial&key=".$googleMapKey;
            $response_a = $this->curlDetails($distanceDurationUrl); 
            
            $status =$response_a['status'];
            $origin_addresses =$response_a['origin_addresses'];
            $destination_addresses =$response_a['destination_addresses'];

            if (isset($origin_addresses[0]) && !empty($origin_addresses[0])){
                $element = $response_a['rows'][0]['elements'];
                $storeDistanceArray = [];

                foreach($element as $key => $ele){
                    if($ele['status'] == 'ZERO_RESULTS'){
                        $dataMessage = ['message' => 'No Distance Found'];
                        $result->setData($dataMessage);
                        return $result;
                    } else {
                        $durArray = [];
                        $durArray['distance_text'] = $ele['distance']['text'];
                        $durArray['distance_value'] = $ele['distance']['value'];
                        $durArray['duration_text'] = $ele['duration']['text'];
                        $durArray['duration_value'] = $ele['duration']['value'];
                        $durArray['i_key'] = ['key' => $key, 'dest_addr' => $response_a['destination_addresses'][$key]];  
                        array_push($storeDistanceArray, $durArray);
                    } 
                }  

                $key_values = array_column($storeDistanceArray, 'distance_value'); 
                array_multisort($key_values, SORT_ASC, $storeDistanceArray);

                $destinationStoreArray = [];
                foreach($storeDistanceArray as $storeDistanceAr){
                    $destaddrArray = [];
                    $destaddrArray['dest_addr'] = $storeDistanceAr['i_key']['dest_addr']; 
                    $destaddrArray['distance_text'] = $storeDistanceAr['distance_text']; 
                    $destaddrArray['duration_text'] = $storeDistanceAr['duration_text']; 
                    array_push($destinationStoreArray, $destaddrArray);
                }

                $firstThreeShortDistance = array_slice($destinationStoreArray, 0, 5);
                $firstThreeShortDistanceStoreArray = [];
                foreach($firstThreeShortDistance as $firstThreeShortDist){ 
                    $collectionData = $this->installationStoreDetailsByAddress($firstThreeShortDist); 
                    array_push($firstThreeShortDistanceStoreArray, $collectionData);
                }  

                $firstThreeShortData = [];
                foreach($firstThreeShortDistanceStoreArray as $firstThreeShortDistanceStoreA){ 
                    $firstThreeShortDataStore = [];
                    $firstThreeShortDataStore['getaddress'] = $firstThreeShortDistanceStoreA['getaddress'][0];
                    $firstThreeShortDataStore['installation_name'] = $firstThreeShortDistanceStoreA['getaddress'][0]['installation_name'];
                    $firstThreeShortDataStore['location_number'] = $firstThreeShortDistanceStoreA['getaddress'][0]['location_number'];
                    $firstThreeShortDataStore['address'] = $firstThreeShortDistanceStoreA['getaddress'][0]['address'];
                    $firstThreeShortDataStore['getdistancetext'] = $firstThreeShortDistanceStoreA['getdistancetext'];
                    $firstThreeShortDataStore['getdurationtext'] = $firstThreeShortDistanceStoreA['getdurationtext'];

                    $response_b = $this->getPlaceId($firstThreeShortDataStore);
                    $firstThreeShortDataStore['responseB'] = $response_b;

                    foreach($firstThreeShortDataStore['responseB']['results'] as $firstThreeShortDatas){
                        $response_c = $this->getPlaceOpenCloseHours($firstThreeShortDatas);
                        $firstThreeShortDataStore['openinghours'] = $response_c['result']['opening_hours']['weekday_text'];
                    } 

                    array_push($firstThreeShortData, $firstThreeShortDataStore);
                }
                 
                $result->setData($firstThreeShortData);
                return $result;
            } else {
                $data = ['message' => 'No Zipcode Found'];
                $result->setData($data);
                return $result;
            }
        }
    }

    public function curlDetails($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_PROXYPORT, 3128);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        $response = curl_exec($ch);
        curl_close($ch);
        return json_decode($response, true);
    }

    public function getPlaceId($firstThreeShortDataStore){
        $addressString = $firstThreeShortDataStore['address'];
        $encodedAddressString = urlencode($addressString);
        $googleMapKey = $this->helperData->getGoogleMapKey(); 
        $getPlaceIdUrl = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input=".$encodedAddressString."&inputtype=textquery&fields=place_id,name,geometry&key=".$googleMapKey;
        return $this->curlDetails($getPlaceIdUrl);
    }

    public function getPlaceOpenCloseHours($firstThreeShortDatas){
        $placeId = $firstThreeShortDatas['place_id'];
        $googleMapKey = $this->helperData->getGoogleMapKey();
        $getPlaceOpenCloseHoursUrl = "https://maps.googleapis.com/maps/api/place/details/json?place_id=".$placeId."&fields=name,opening_hours&key=".$googleMapKey;
        return $this->curlDetails($getPlaceOpenCloseHoursUrl);
    }

    public function installationStoreDetailsByAddress($firstThreeShortDist){
        $installationStore = $this->storeFactory->create(); 
        $collection = $installationStore->getCollection();
        $collection->addFieldToFilter('address', $firstThreeShortDist['dest_addr']);
        $dataArray = [];
        $dataArray['getaddress'] = $collection->getData();
        $dataArray['getdistancetext'] = $firstThreeShortDist['distance_text'];
        $dataArray['getdurationtext'] = $firstThreeShortDist['duration_text'];
        return $dataArray;
    }
}

Step 8: Creating the Model

Create a model to manage the stored data:

app/code/DCKAP/NearInstallationStore/Model/Store.php

<?php

<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->

namespace DCKAP\NearInstallationStore\Model;

use Magento\Framework\Model\AbstractModel;

class Store extends AbstractModel
{
    protected function _construct()
    {
        $this->_init('DCKAP\NearInstallationStore\Model\ResourceModel\Store');
    }
}

Step 9: Create a resource model for the store:

app/code/DCKAP/NearInstallationStore/Model/ResourceModel/Store.php

<?php
<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->


namespace DCKAP\NearInstallationStore\Model\ResourceModel;

use Magento\Framework\Model\ResourceModel\Db\AbstractDb;

class Store extends AbstractDb
{
    protected function _construct()
    {
        $this->_init('dckap_store', 'entity_id');
    }
}

And create a collection class for the resource model:

app/code/DCKAP/NearInstallationStore/Model/ResourceModel/Store/Collection.php

<?php

<!--
 * @package    DCKAP_NearInstallationStore
 * @copyright  Copyright (c) 2023 DCKAP Inc (http://www.dckap.com)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 -->

namespace DCKAP\NearInstallationStore\Model\ResourceModel\Store;

use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
use DCKAP\NearInstallationStore\Model\Store as Model;
use DCKAP\NearInstallationStore\Model\ResourceModel\Store as ResourceModel;

class Collection extends AbstractCollection
{
    protected function _construct()
    {
        $this->_init(Model::class, ResourceModel::class);
    }
}

Step 10: Frontend Implementation

Once we enter the zip code in the input text box and submit it, this will call the AJAX controller to fetch all the nearest stores available for the customer. Implement the frontend part to make the AJAX call and display the results. Now, create the necessary JavaScript and HTML files to complete this part.

Enhanced User Experience Magento 2 and Google Maps API

1. Quick and Accurate Store Locator

Customers no longer need to manually browse through a list of addresses to find the closest stores. To deliver the most precise and current information, this feature takes advantage of real-time data

2. Real-time Distance and Duration

Customers can see the nearest stores and also get real-time distance and travel duration, open, and closing times of the store to help them make informed decisions about which store to visit.

Find the Nearest Stores using Magento 2 and Google Maps API with Klizer

Integrating Google Maps API with Magento 2 can significantly enhance your ecommerce store’s functionality by providing real-time location-based services. By following the steps outlined in this blog post, you can offer your customers a seamless experience in finding the nearest store locations.

If you are looking to integrate Google Maps API with Magento 2 and need an expert consultation, get in touch with our team at Klizer.

Sharath Kumar V

Sharath Kumar V, Software Engineer II at Klizer, has over six years of ecommerce website development experience, he's specialized in Magento (1.5 years) and BigCommerce (1.5 years), with a BigCommerce certification. He has 2 years of expertise in Laravel, focusing on custom applications and RESTful APIs. Sharath is dedicated to leveraging his skills by writing informative blogs and driving innovative ecommerce solutions.

Get in Touch

Get Expert Advice

At Klizer, we bring over 18 years of specialized expertise in ecommerce website development and design.

© Copyright 2024 Klizer. All Rights Reserved