7/6/2018 - #development #ecommerce #magento
by: Régis Grutter

Dear web surfer, powerful waves have brought you here, pushed by curiosity and a hunger for eCommerce wisdom. Your hands move quickly over the keyboard as a surfer does on his surfboard. Your soul is seeking for knowledge, and here is the outcome of your exhausting adventure. This article will, I hope, become a rewarding and enriching stop of your journey. I introduce you to the “Store Locator” illustrated by its implementation for Bananamoon.   

What is a Store Locator?

First of all, it is recommended to slow down your adventurous pulsations, sadly it is not a secret map leading to a legendary treasure. It is a service that allows you to locate brick and mortar stores on a map. Suddenly our world becomes small and accessible with such exploration tools. Nowadays, it is considered as an essential tool for plenty of online stores, specially for brands like Bananamoon having a big selling network.

Store Locator favours drive-to-store, in other words, transforms great online surfers like you into physical visitors. In this framework, mobile adaptation is very important because the real utility for users is being able to generate an itinerary from their own location to the nearest store. Not to mention all information you can collect with it: telephone number, opening hours, etc.

Time to pack !

To successfully complete this journey on the ocean and remake Bananamoon’s Store Locator for Magento 1 a few tools were very much needed. A bathing suit, a surfboard and sun cream? Exactly. But also, Advanced Content Manager extension for structuring and managing data and Google Maps API to handle and display the map.

 

  • First step: structuring and managing data

What better way than having a real swiss-knife for Magento content management, also known as Advanced Content Management, to help us around on this journey? Nothing, not even a Mojito. First, our Content TypeStore Locator” must be created.

 

 
It is going to determine your future Content’s data structure, corresponding to the stores placed on the map. Information such as the name of the store, a phone number, opening hours or the address can be displayed. But most important GPS coordinates (longitude and latitude).

 

 

To better optimize natural referencing for each store on research results, we ensure that a relevant default URL pattern is provided. Each store will then have an optimized access road for referencing. As an example, for Bananamoon we used : City + Country + Store Name.

  

 

The registration of each country’s data for each store it’s done under the norm ISO 3166-1, a two characters alphabet (France: FR, Germany: DE, United States: US, etc.). To display the full name of the country on our default URL pattern and manage its translation, we had to override the helper module: Blackbird_ContentManager_Helper_Data.

 


**
* Replace {{.*}} patterns in data
* @param string $data
* @param Content $content
* @return string
*/
public function applyPattern($data, $content)
{
      $matches = array();
      preg_match_all('/{{([a-zA-Z0-9_\|]*)}}/', (string) $data, $matches);

      if(!empty($matches[1]))
      {
        foreach($matches[1] as $key => $replacement)
        {
           [...]

           if(preg_match('/\|country/', $replacement))
          {
            $replacement = str_replace('|country', '', $replacement);
            $attributeContent = $this->_getCountryValue($content->getData($replacement));
          }

           [...]
        }
      }
}

/**
* Get plain country value for a content
*/
private function _getCountryValue($str)
{
    $countryTranslation = Mage::app()->getLocale()->getCountryTranslationList();
    return strtolower($countryTranslation[$str]);
}

 

  •  Second step: import of data

Once data structure is implemented, we gotta feed the beast! We are going to chase a big .CSV file regrouping all data with the help of an import php script.   

 

 

In the shell file of our project tree we created our import script import_store_locator.php. It is going to search all data from the file .CSV to create the Content on ACM. The first line of the .CSV file corresponds to data type. To start the import, simply execute the order: php -f import_store_locator.php -- -f import_store_locator.csv

 

 
<?php

require_once 'abstract.php';

/**
 * Script for automatic store locator import
 */
class Mage_Shell_ImportStoreLocator extends Mage_Shell_Abstract
{
      const STORE_LOCATOR_CONTENT_TYPE_ID = 1;

      /**
      * Displays critical message and exit.
      */
      protected function _fault($msg)
      {
           exit(PHP_EOL . $msg . PHP_EOL);
      }

/**
   * Main script method that imports all store from specified CSV file.
   */
   public function run()
   {
     $start = microtime(true);

     if (!$file = $this->getArg('f')) {
       echo $this->usageHelp();
     } else {
       $delimiter = $this->getArg('d') ? $this->getArg('d') : ',';
       $enclosure = $this->getArg('e') ? $this->getArg('e') : '"';

       $fh = fopen($file, 'r');
       if (!$fh) {
         $this->_fault("An error occured opening file $file.");
       }
       try {

         $i = 0;

           // each row
         while ($data = fgetcsv($fh, null, $delimiter, $enclosure)) {
           $i++;
           if ($i > 1) {
             if ($data[0] != '') {
               $store = Mage::getModel('contentmanager/content');
               $store->setData('ct_id', self::STORE_LOCATOR_CONTENT_TYPE_ID); // Store locator
               $store->setData('storelocator_latitude', $data[1]); // Latitude
               $store->setData('storelocator_longitude', $data[2]); // Longitude

                              [...]

               $store->save();
              }
            }
          }

         } catch (Exception $e) {
            Mage::logException($e);
            $this->_fault($e->getMessage());
         }
       }

       $end = microtime(true);
       $time = $end - $start;
       echo PHP_EOL;
       echo 'Script Start: ' . date('H:i:s', $start) . PHP_EOL;
       echo 'Script End: ' . date('H:i:s', $end) . PHP_EOL;
       echo 'Duration: ' . number_format($time, 3) . ' sec' . PHP_EOL;
     }

     /**
     * List of available script options.
     *
     * @return string
     */
     public function usageHelp()
     {
       return <<< USAGE
    Usage: php -f import_store_locator.php -- [options]

     -f File to import
     -d Delimiter (default is ,)
     -e Enclosure (default is ")
     -h Short alias for help
     help This help

     ex : php -f import_store_locator.php -- -f import_store_locator.csv
    USAGE;
      }
    }

 

  • Third step: Handling and displaying the map


To take store data from an .phtml template, simply generate a Content collection with a block method: 

 

$storeCollection = Mage::getModel('contentmanager/content')
       ->getCollection('store_locator')
       ->addAttributeToSelect(array(
         'storelocator_name',
         'storelocator_longitude',
         'storelocator_latitude',
      [...]
       ))
       ->addAttributeToFilter('status', 1)
       ->setOrder('storelocator_ville', 'ASC');

   

Map managing and data display are entirely managed by javascript: Maps Javascript API. However, we still have to note that Google Maps has changed its pricing this month and generalized a paid service. It is then essential to minimize geo-tracking requests, or simply opt for a free geo-tracking service such as Open Street Map.   

 

 

  • Fourth step: measuring distances 

We take coordinates from a research place and have all coordinates from all stores to display on the map. From here, you are able to filter stores’ display according to an X km radius around the research point. Distance measuring can be done the following way:

 
/**
   * Calcul de distance entre deux points en fonction de la latitude et longitude
   * @param $point1_lat
   * @param $point1_long
   * @param $point2_lat
   * @param $point2_long
   * @param string $unit
   * @param int $decimals
   * @return float
   */
public function distanceCalculation($point1_lat, $point1_long, $point2_lat, $point2_long, $unit = 'km', $decimals = 2) {
   // Calcul de la distance en degrés
      $degrees = rad2deg(acos((sin(deg2rad($point1_lat))*sin(deg2rad($point2_lat)))
+
(cos(deg2rad($point1_lat))*cos(deg2rad($point2_lat))*cos(deg2rad($point1_long-$point2_long)))));

   // Conversion de la distance en degrés à l'unité choisie
   switch($unit) {
     case 'km':
       $distance = $degrees * 111.13384; // kilomètres
      break;
     case 'mi':
       $distance = $degrees * 69.05482; // milles
      break;
     case 'nmi':
       $distance = $degrees * 59.97662; // milles nautiques
    break;
   }
   return round($distance, $decimals);
}

End of the journey

Your stop has come to an end, more waves for you to catch are coming and it is time for you to take your surfboard again, and explore new wisdom horizons. Your computer’s quiet noise blends with the sea waves calling you on your digital trip. Far on the horizon, you see a sunlight landing on the nearest beach coloring our Store Locator with summer gold light. Just like a travel memory, keep in mind that such a tool contributes to breaking borders between the web world and the physical world.

Write your comment

Ready
for take-off?

Blackbird is a web agency specialized in the development of eCommerce websites. We are Magento Experts and we offer our services and advice for e-marketing, strategy, branding, deployment and methodology.

Contact
+339 50 66 21 38


Legal terms
Agency 30, Avenue du Rhin
67100 Strasbourg
France
SEE MAP
FR - EN