Generate Google Maps Platform API Key

To get the coordinates of the customer's shipping address, we will be using the Google Maps API. They require an account with billing account connected for access there though, so you'll need to sign up and create an account if you haven't already. They provide a $200 free allowance per month, which should allow for 40,000 requests per month before any billing would kick in.

  1. Head to the Google Maps Platform site at https://cloud.google.com/maps-platform, and log in or create an account if needed.
  2. Click the “Get Started” button.
  3. In the popup that appears, select the “Places” product option and continue
  4. On the next panel you'll be prompted to either select an existing project or create a new one. Make a selection there and continue.
  5. If prompted to create a billing account, complete that. Google has a $200 free allowance per month, but requires you assign a billing account in case you go over that allowance.
  6. Once you've created your new project, you'll be redirected to the Google Maps Platform portal.
  7. Select the hamburger menu in the top left, and select “APIs & Services” and “Credentials”
  8. Click “Create Credentials” on the Credentials page, and select “API Key”.
  9. Copy the resulting API key into a text file to use later
  10. If given the option to restrict your API key - currently you won't be able to use Application restrictions, but you can set an API restriction to only allow the Geocoding API.

Create allowed address area polygon

In order to dictate what the supported address zone is, we need to generate a polygon, where each point of the polygon is a set of coordinates. We can use Google's My Maps functionality to build out that polygon visually, and export it to get the coordinates.

  1. Head to https://www.google.com/mymaps, and log in, or create an account if you don't have one already.
  2. Create a new map
  3. In the editor, zoom to the area that you want to create your allowed shipping area.
  4. Click the “Draw a line” button (the icon with three dots and lines joined together) and select “Add line or shape”
  5. Click on the map to create an area, completing the area by clicking back on the first point you made. Once you complete the shape, it should become a shaded area on the map - this is the area that you will allow shipping to.
  6. Click the 3 vertical dot menu icon in the map panel in the top left, and select “Export to KML/KMZ”
  7. In the dropdown of the export panel, select the layer that your polygon is on - unless you specifically named it, it will probably be called “Untitled layer”
  8. Check the box labelled “Export as KML instead of KMZ. Does not support all icons.”
  9. Click Download to download the file to your computer.
  10. Open the downloaded file in a code or text editor on your computer, and look for the coordinates section of the XML, it'll look like this:
    <Polygon>
      <outerBoundaryIs>
        <LinearRing>
          <tessellate>1</tessellate>
          <coordinates>
            -73.9546793,40.8478817,0
            -74.0205973,40.741837,0
            -74.0549296,40.6304119,0
            -74.0247172,40.5647194,0
            -73.9230936,40.5699355,0
            -73.8297098,40.6481274,0
            -73.8599223,40.799039,0
            -73.9546793,40.8478817,0
          </coordinates>
        </LinearRing>
      </outerBoundaryIs>
    </Polygon>
  11. Copy the values within the coordinates node (of your file, not the example code above), and paste it into a new file.
  12. Wrap each line in square brackes, and add a comma at the end, so it looks something like this:
    [-73.9546793,40.8478817,0],
    [-74.0205973,40.741837,0],
    [-74.0549296,40.6304119,0],
    [-74.0247172,40.5647194,0],
    [-73.9230936,40.5699355,0],
    [-73.8297098,40.6481274,0],
    [-73.8599223,40.799039,0],
    [-73.9546793,40.8478817,0]
  13. We'll come back to this code in the next step

Build custom shipping code

Now for the fun part - adding the custom shipping code to your store!

  1. Open your store's Foxy administration and head to the “shipping” section
  2. If it's not already enabled, enable the “use custom code” option at the bottom of the page.
  3. Copy and paste the following code into the code editor that appears:
    // Google Maps API key
    const google_maps_api_key = '';
    // Shipping area polygon
    const shipping_polygon = [
     
    ];
     
    // Get address details
    const country = cart['_embedded']['fx:shipment']['country'];
    const region = cart['_embedded']['fx:shipment']['region'];
    const city = cart['_embedded']['fx:shipment']['city'];
    const postal_code = cart['_embedded']['fx:shipment']['postal_code'];
    let address1 = "";
    for (let c in cart['_embedded']['fx:custom_fields']) {
        if (cart['_embedded']['fx:custom_fields'][c]['name'] == "shipping_address1") {
            address1 = cart['_embedded']['fx:custom_fields'][c]['value'];
            break;
        }
    }
     
    // Get address coordinates from Google Maps
    const maps_url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' + address1 + ', ' + city + ', ' + region + ', ' + country + ', ' + postal_code + '&key=' + google_maps_api_key;
    let coordinates = [];
    await request(maps_url, function (error, response, body) {
        let payload = JSON.parse(body);
        if (response && response.statusCode == 200 && payload.status == "OK") {
            let location = payload.results[0].geometry.location;
            coordinates = [location.lng, location.lat];
        }
    });
     
    if (coordinates.length == 2 && checkGeoFence(coordinates, shipping_polygon)) {
        // Shipping is allowed!
        rates.add(10000, 15, '', 'Standard Delivery');
    } else {
        // Shipping is not allowed
        rates.error("Sorry, we're unable to deliver to your address");
    }
     
    function checkGeoFence(point, polygon)
    {
        if(polygon[0] != polygon[polygon.length-1])
            polygon[polygon.length] = polygon[0];
        let j = 0;
        let oddNodes = false;
        let x = point[1];
        let y = point[0];
        let n = polygon.length;
        for (let i = 0; i < n; i++)
        {
            j++;
            if (j == n)
            {
                j = 0;
            }
            if (((polygon[i][0] < y) && (polygon[j][0] >= y)) || ((polygon[j][0] < y) && (polygon[i][0] >=
                y)))
            {
                if (polygon[i][1] + (y - polygon[i][0]) / (polygon[j][0] - polygon[i][0]) * (polygon[j][1] -
                    polygon[i][1]) < x)
                {
                    oddNodes = !oddNodes;
                }
            }
        }
        return oddNodes;
    }
  4. Update the line of code const google_maps_api_key = ''; to use your Google Maps API key you generated above, pasting it within the quotations.
  5. Next you'll update the shipping_polygon array. On the blank line in this code, paste in the coordinates array you generated in the last section:
    const shipping_polygon = [
     
    ];
  6. The beginning of the snippet should now look something like this:
    // Google Maps API key
    const google_maps_api_key = 'abCd12eFGh__zyXw34vUT';
    // Shipping area polygon
    const shipping_polygon = [
        [-73.9546793,40.8478817,0],
        [-74.0205973,40.741837,0],
        [-74.0549296,40.6304119,0],
        [-74.0247172,40.5647194,0],
        [-73.9230936,40.5699355,0],
        [-73.8297098,40.6481274,0],
        [-73.8599223,40.799039,0],
        [-73.9546793,40.8478817,0],
    ];
  7. Next, you'll need to set the shipping rates and error that is displayed to customers. The snippet above sets a $15 “Standard Delivery” rate, but you'll obviously want to customise that to show your own rates. Check out the documentation here on interacting with our rates.

    Specifically you'll be editing this section:
    if (coordinates.length == 2 && checkGeoFence(coordinates, shipping_polygon)) {
        // Shipping is allowed!
        rates.add(10000, 15, '', 'Standard Delivery');
    } else {
        // Shipping is not allowed
        rates.error("Sorry, we're unable to deliver to your address");
    }
  8. Save your custom shipping code
  9. Wait 15-20 seconds and refresh the page to ensure the shipping code has saved (it's a separate system so takes a moment to initialize)
  10. If you haven't already, you'll also need to update any categories that will use this shipping rate code to have a delivery type of “Shipped using live shipping rates”.

Add custom template code

As a last step, you'll just need to add in some custom code to your store. The lookup relies on the customers address line 1, which isn't currently sent to the shipping rate endpoint natively. We'll add some custom code to make it pass over, and also hide the shipping estimate on the cart, so it's only calculated after the customer has entered their full address.

  1. In the Foxy administration, head to the “configuration” section
  2. If not already, enable the “Add custom header and footer code to your templates”
  3. In the “custom header” section, paste this code after any existing code you have in that field:
    <style type="text/css">
    #fc .fc-sidebar--cart .fc-address-entry {
        display: none;
    }
    </style>
  4. In the “custom footer” section, paste this code after any existing code you have in that field:
    {% if context == "checkout" %}
    <script>
    FC.client.on("render.done", function() {
        $("[name^='shipping_address1']").attr("data-fc-shipping-custom-field", true);
    });
     
    FC.client.on("checkout-shipping-options-update", function() { 
        return $('[data-fc-shipping-custom-field]:visible').filter(function() {
            return this.value == "";
        }).length == 0;
    });
    </script>
    {% endif %}
  5. Save the configuration

Test it out!

At this stage - you've completed all the configuration! You should now be able to add a product to your cart, proceed to the checkout, and enter shipping addresses that are inside and outside of your shippable zone to test it out.

Site Tools