Look Inside the Store Locator

An addition in the Vinson release of SuiteCommerce Advanced is the store locator. It lets shoppers search for physical locations on your site. Shoppers can enter a particular location, such as a zip code or city, or use the auto-locate feature to find stores near their current location.

As well as how useful the functionality is, there is some interesting code and technology at play to make the store locator — so I'm looking forward to showing you.

Why Store Locator?

While many users like the convenience and ease of shopping online, it is impossible to replicate the experience of shopping instore. Particularly in fashion retail, many shoppers want to know how items will look and feel before they buy it. Some just want to simply browse through your collection and see if anything catches their eye.

Implementing a store locator provides a simple way to encourage shoppers to come and visit your physical locations. It's a reciprocal arrangement: while you may advertise your online store while instore (eg on your receipts or bags), you can equally use your online store to push physical locations for your shoppers to visit you at.

Also, given that the store locator solution is responsive, it's invaluable to shoppers who are on-the-go, as they can use their mobile to track down stores near them. Not only can they use the search functionality based on a city or address, but it supports the HTML5 geolocation API. This technology, available in all modern browsers, returns the coordinates of the user by connecting their browser to their device's location service. Fun fact: you can write some very simple code and test this yourself!

Write Some HTML5 Geolocation Code

There are two prerequisites here: use a modern browser and be on a secure (HTTPS) domain. If you're reading this on the developer portal, then the domain is already secure. Now let's test to see if your browser can support geolocation.

Open your developer console and type in:

if (navigator.geolocation) {
  console.log('Great success!');
} else {
  console.log('Unfortunate failure!');
}

You should see one of the two messages, indicating success or failure. Seeing as you should be using a modern web browser, you should see the first message.

Next all we need to do is write some simple code to return your coordinates. In the browser console, put the following:

function location(p) {
  var latitude = p.coords.latitude
  , longitude = p.coords.longitude;
  return console.log(latitude + ', ' + longitude);
}
navigator.geolocation.getCurrentPosition(location);

You'll be prompted to allow the browser to access this information and, if you agree, a set of coordinates should be returned. Go to your favorite maps site or app and type them in, they should be a pretty good approximation of where you are. If your device has GPS then they should be nearly exactly right; if you're using a PC then it'll be more abstract. How this information is worked out is based on your software and hardware vendors. The point is that the web browser has access to it, via a very simple interface: navigator.geolocation.

In fact, the same method that offers the latitude and longitude also offers another property called accuracy. While it isn't particularly useful in our uses, you can modify the function to return this value:

function location(p) {
  var latitude = p.coords.latitude
  , longitude = p.coords.longitude
  , accuracy = p.coords.accuracy
  console.log(latitude + ', ' + longitude + ' (within ' + accuracy + ' meters)');
}
navigator.geolocation.getCurrentPosition(location);

You get the idea. If you're interested, take a look at Mozilla's documentation on coordinates for more information, as well as the related pages.

When we have those coordinates, we can then plug it into a map service right? Well, yeah but let's take a look at JavaScript facades first.

JavaScript Facade

Facades aren't specific to JavaScript, they come up in other programming languages too. The concept is borrowed from architecture and works in the same way. Like a building, the underlying code for something may be very complex with a number of systems that have a wide range of purposes. What a facade does is provide a simple, clean interface for it all.

With the store locator and maps code, we have an issue in that while we include Google Maps by default, you may not want to use it. We could write our code just for Google Maps, but then it becomes a particularly difficult for you to build a store locator with a different maps engine. This is where the facade comes in.

With the facade, we produce a standard set of methods that specify exactly what functionality is required to get the store locator to work, and to plot the results on the map. What this means is that when the store locator calls methods, it is always the same ones regardless of the maps provider.

In short, you can think of the facade as an API. By doing this, we decouple the application from the map engine, which makes it easy to swap out the engine. Facades are all about picking out the specifics thing we need in order to do a job, and ignoring the rest; making it look unified to the user and easy to use.

To better understand facades, you can take a look at an example that I am borrowing from dofactory. Open your console, then copy and paste in the following:

var Mortgage = function(name) {
  this.name = name;
}

Mortgage.prototype = {

  applyFor: function(amount) {
    // access multiple subsystems...
    var result = "approved";
    if (!new Bank().verify(this.name, amount)) {
      result = "denied";
    } else if (!new Credit().get(this.name)) {
      result = "denied";
    } else if (!new Background().check(this.name)) {
      result = "denied";
    }
    return this.name + " has been " + result +
         " for a " + amount + " mortgage";
  }
}

var Bank = function() {
  this.verify = function(name, amount) {
    // complex logic ...
    return true;
  }
}

var Credit = function() {
  this.get = function(name) {
    // complex logic ...
    return true;
  }
}

var Background = function() {
  this.check = function(name) {
    // complex logic ...
    return true;
  }
}

function run() {
  var mortgage = new Mortgage("Joan Templeton");
  var result = mortgage.applyFor("$100,000");

  console.log(result);
}

For an explanation of the thinking behind this, let me quote the author:

The Mortgage object is the Facade in the sample code. It presents a simple interface to the client with only a single method: applyFor. [But] underneath this simple API lies considerable complexity.

The applicant's name is passed into the Mortgage constructor function. Then the applyFor method is called with the requested loan amount. Internally, this method uses services from 3 separate subsystems that are complex and possibly take some time to process; they are Bank, Credit, and Background.

Based on several criteria (bank statements, credit reports, and criminal background) the applicant is either accepted or denied for the requested loan.

If you replace the times they used // complex logic and return true; with actual complex logic and something that determines a result, then the picture becomes clearer. The applyFor method is the simplest part of the code, and this is similar to what the store locator code looks like. It is the code specific to the map engine that would replaces all of the 'complex logic' mentioned in the comments.

We talk about how the store locator uses the facade in the Google Maps implementation documentation — it's well worth the read. If you want to look at the code, see the JS files in StoreLocatorReferenceMapImplementation and StoreLocatorGoogleMapsImplementation.

Secure Domain and Elevated Permissions

You'll note that in the first demo — the one with the geolocation code — you're required to do this on a page that's secured with HTTPS. Try it on an insecure page and you'll see something like the following (in Chrome):

If you follow the link, it'll take you to a post by the Chrome devs who explain their decision to deprecate powerful features in insecure places. The geolocation features is quite clearly a powerful feature: it can be used to share the user's location with the web service, and if that isn't sent over an encrypted and authenticated connection, then this information is put at risk and so, potentially, is the user. Thus, we operate the locator in a secure domain.

There was also another problem for store locator, which was more difficult to address. The location records — the records in NetSuite that contain information about stores, warehouses, offices, etc — are not available to shoppers. As they don't have permission to run the SuiteScript to access this data, store locator couldn't function.

For this, we implemented a mechanism that allows for an elevation of priveleges. As part of the setup for store locator, you're required to modify the record for StoreLocator.Service.ss and in that enable some options so that it runs as if it were being run by a role with the permission to do so.

In the Vinson release, we introduced the Advanced Customer Center role. This role is almost identical to the Shopper except that it allows for the viewing of location records. Therefore, when we run the SuiteScript for store locator, we're effectively telling the system to run it as a shopper, but with an additional permission to access location records.

As a developer, if you're writing SuiteScript that uses elevated permissions, it's important to understand the ramifications of this. You can create potential security problems by elevating permissions beyond what the user is typically allowed to do. The advice is that you should always try to write scripts that can operate within the confines of the user's permissions; if it's not possible, then you escalate the bare minimum required to achieve your goal, while assessing the impact of doing so.

Final Thoughts

One last thing I wanted to point out: the store locator functionality is treated as somewhat of an add-on to the site. A good example of what I mean lies in StoreLocatorAccessPoints > StoreLocatorAccessPoints.js. This module adds the links to header so that users can access the store locator.

The mountToApp function has two interesting parts. The first is some code that operates as a switch, like the one we discussed previously. Only this one takes a rather novel approach to it: in my example I tell the application to run some code when it has been enabled; here we simplify it by telling it to do nothing if it's false. The following code then doesn't need to be wrapped in the conditional statement because it won't run anyway.

The other thing of note is that rather than modify the view for the header to accommodate the functionality, we are using the addExtraChildrenViews method. This is something we covered in the testimonials tutorial and is a great way to easily inject an extra view into an existing one. We do this with some other items of functionality, such as the newsletter and RFQ functionality.

Overall, I find this functionality to be a good, clean example of how to add a customization to a site.

Summary

The store locator functionality provides you with a way to make it easy for your shoppers to find your physical stores.

Part of what makes it useful is the use of geolocation, which connects the site to the user's device, allowing the user's coordinates to be used in store location search queries. This mechanism not only makes it easier for all users to find stores near them, it is particularly useful for mobile users as their devices will likely have GPS (for more precise location data) and be more difficult to input address information via text.

As part of the implementation we use the HTML5 geolocation API and we looked at how only a few lines of code can be used to generate coordinates. We also looked at the facade design pattern, which aims to make writing code that relies on complex services a lot easier. The store locator's JS facade means that not only should the functionality be easier to understand, it should also be easier to implement a custom maps engine as we have decoupled the engine from the application code.

An important part of getting this functionality to work is the focus on security. Firstly, we operate through a secure domain so that geolocation data from the user is encrypted via HTTPS. Another part of that is that we have to escalate permissions when running the module's SuiteScript. To minimize the risk of exposure, we created a brand new role which is barely above the level of a shopper. It has the additional ability to read location records, which is what we use for data related to stores.

Finally, I think the store locator is really useful to sites who have physical stores (or maybe you have another creative use for it, like dealerships?) and want to direct shoppers to them. In terms of the implementation, I think it's done really quite well. Take a look at the code and see for yourself.

More Information

Have you implemented the store locator? What do you think?