Display the operating hours of physical stores dynamically when building a Magento 2 store. Using the Google Maps API, specifically the Places API, you can fetch this information.
This guide will show you how to integrate this functionality using PHP in Magento 2 to enhance the user experience.
ON THIS PAGE
Steps to Implement Magento 2 with the Google Maps API
Step 1: Create a Google Maps API Key
- Google Maps API Key: Get the Google Maps API key to access Google Maps services [Get it from the Google Cloud Platform].
- Magento 2 Setup: Ensure you have a Magento 2 installation running.
- Visit the Google Cloud Console.
- Create a new project or select an existing one.
- Navigate to the “API & Services” section.
- Enable the following APIs:
- Maps JavaScript API
- Places API
- 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/KLIZER/StoreHours/registration.php
<?php
<!--
* @package KLIZER_StoreHours
* @copyright Copyright (c) 2023 KLIZER Inc (http://www.klizer.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, KLIZER_StoreHours, __DIR__);
Step 3: Create a “Module.xml”
app/code/KLIZER/StoreHours/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="KLIZER_StoreHours" setup_version="1.0.7">
</module>
</config>
Step 4: Create a “routes.xml”
app/code/KLIZER/StoreHours/etc/frontend/routes.xml
<?xml version="1.0"?>
<!--
* @package KLIZER_StoreHours
* @copyright Copyright (c) 2023 KLIZER Inc (http://www.klizer.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="klizer_storehours" frontName="klizer_storehours">
<module name="KLIZER_StoreHours" />
</route>
</router>
</router>
</config>
Step 5: Set up Google Map API Credentials
First, configure your Google Map API credentials in Magento 2, and here’s how you can do it:
app/code/KLIZER/StoreHours/etc/adminhtml/system.xml
<?xml
Copy code
<?xml version="1.0" ?>
<!--
* @package KLIZER_StoreHours
* @copyright Copyright (c) 2023 KLIZER Inc (http://www.klizer.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="klizer_storehours" translate="label" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Google Map Services</label>
<tab>klizer</tab>
<resource>KLIZER_StoreHours::config_storehours</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/KLIZER/StoreHours/Helper/Data.php
<?php
/**
* @package KLIZER_StoreHours
* @copyright Copyright (c) 2024 KLIZER Inc (http://www.klizer.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
**/
namespace KLIZER\StoreHours\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Store\Model\ScopeInterface;
class Data extends AbstractHelper
{
const XML_PATH_GOOGLE_MAP_KEY = klizer_storehours/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 store locations’ hours:
app/code/KLIZER/StoreHours/Controller/Ajax/GetStorePickupHours.php
<?php
/**
* @package KLIZER_StoreHours
* @copyright Copyright (c) 2024 KLIZER Inc (http://www.klizer.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
**/
namespace KLIZER\StoreHours\Controller\Ajax;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\ActionInterface;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultFactory;
use Magento\Checkout\Model\Session;
class GetStorePickupHours extends \Magento\Framework\App\Action\Action
{
protected $_pageFactory;
protected $storeFactoryFactory;
protected $atdlocationFactory;
protected $helperData;
private $resultJsonFactory;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
\KLIZER\StoreHours\Model\StoreFactory $storeFactory,
\KLIZER\ATDProduct\Model\AtdlocationFactory $atdlocationFactory,
\KLIZER\StoreHours\Helper\Data $helperData
) {
$this->resultJsonFactory = $resultJsonFactory;
$this->storeFactoryFactory = $storeFactory;
$this->atdlocationFactory = $atdlocationFactory;
$this->helperData = $helperData;
return parent::__construct($context);
}
/**
* Execute the AJAX request to fetch store pickup opening hours
*
* @return \Magento\Framework\Controller\Result\Json
*/
public function execute()
{
// Check if the request is AJAX
if (!$this->getRequest()->isAjax()) {
return $this->resultJsonFactory->create()->setData([
'success' => false,
'message' => __('Invalid request.'),
]);
}
// Retrieve the zip code from the request
$zipCode = $this->getRequest()->getParam('zipcode');
if (empty($zipCode)) {
return $this->resultJsonFactory->create()->setData([
'success' => false,
'message' => __('Zipcode is required.'),
]);
}
try {
// Fetch collection data using the given zip code
$collectionData = $this->getStorePickupOpeningHours($zipCode);
if (empty($collectionData)) {
return $this->resultJsonFactory->create()->setData([
'success' => false,
'message' => __('No data found for the given zipcode.'),
]);
}
$storeData = $collectionData[0];
// Fetch place ID details
$placeIdDetails = $this->getPlaceId($storeData);
if (empty($placeIdDetails['status']) || empty($placeIdDetails['results'][0])) {
return $this->resultJsonFactory->create()->setData([
'success' => false,
'message' => __('Failed to retrieve place ID.'),
]);
}
$placeId = $placeIdDetails['results'][0]['place_id'];
// Fetch open/close hours using the place ID
$openCloseHoursDetails = $this->getPlaceOpenCloseHours($placeId);
if (empty($openCloseHoursDetails['status']) || empty($openCloseHoursDetails['result']['current_opening_hours']['weekday_text'])) {
return $this->resultJsonFactory->create()->setData([
'success' => false,
'message' => __('Failed to retrieve opening and closing hours.'),
]);
}
$openCloseHours = $openCloseHoursDetails['result']['current_opening_hours']['weekday_text'];
if ($quoteId && !empty($openCloseHours)) {
$openCloseHoursObject = [];
foreach ($openCloseHours as $dayHours) {
$dayParts = explode(':', $dayHours, 2);
if (count($dayParts) === 2) {
$openCloseHoursObject[trim($dayParts[0])] = trim($dayParts[1]);
}
}
}
// Return the final store hours response
return $this->resultJsonFactory->create()->setData([
'success' => true,
'data' => [
'store_data' => $storeData,
'open_close_hours' => $openCloseHoursObject,
],
]);
} catch (\Exception $e) {
return $this->resultJsonFactory->create()->setData([
'success' => false,
'message' => __('Unable to fetch store pickup details.'),
]);
}
}
/**
* Fetch store pickup opening hours for a given zipcode
*
* @param string $zipcode
* @return array
*/
private function getStorePickupOpeningHours($zipcode)
{
try {
// Fetch the collection and apply the filter to get the data from the table of store pickup based on zipcode
$storepickupCollection = $this->atdlocationFactory->create()->getCollection();
$storepickupCollection->addFieldToFilter('zip', $zipcode);
// Get the data from the collection
$filteredData = $storepickupCollection->getData();
return $filteredData;
} catch (\Exception $e) {
return [];
}
}
/**
* Get store pickup Google Map place Id
* @param string $zipcode
*/
public function getPlaceId($responseData){
$googleMapKey = $this->helperData->getGoogleMapKey();
$placeIdUrl = "https://maps.googleapis.com/maps/api/place/textsearch/json?query=".urlencode($responseData['location_name']).",".urlencode($responseData['address'])."&key=".$googleMapKey;
$responseGetIdData = $this->curlDetails($placeIdUrl);
return $responseGetIdData;
}
/**
* Get Store Pickup open and close hours
* @param $responseData
*/
public function getPlaceOpenCloseHours($responseData){
$googleMapKey = $this->helperData->getGoogleMapKey();
$placeTimeDetailsUrl = "https://maps.googleapis.com/maps/api/place/details/json?place_id=".$responseData."&key=".$googleMapKey;
$responseGetPlaceOpenCloseHoursData = $this->curlDetails($placeTimeDetailsUrl);
return $responseGetPlaceOpenCloseHoursData;
}
/**
* Perform a CURL request and return the response
*
* @param string $url The URL to fetch
* @return array|null The JSON-decoded response, or null if an error occurs
*/
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);
$response = json_decode($response,true);
return $response;
}
}
Step 8: Frontend Implementation
Once we enter the ZIP code in the input text box and submit it, an AJAX controller will be called to fetch all the available stores along with their store hours 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.

Implement Magento 2 with the Google Maps API with Klizer
Integrating the Google Maps API into Magento 2 stores allows you to dynamically display store operating hours, providing a seamless and informative experience for customers. By following this guide, you can easily set up and customize this functionality to meet your business needs.
This feature not only improves customer engagement but also ensures that accurate and up-to-date information is readily available, enhancing overall satisfaction. With Magento 2’s flexibility and the powerful capabilities of the Google Maps API, you can take your online store to the next level.Get in touch with our Magento development team at Klizer, If you are looking for a consultation to integrate Google Maps APO with Magento 2.