Add a Free Shipping Indicator as a Child View

If there's one thing that comes up time and time again that online shoppers say that they want, it's free shipping.

From personal experience, it can be particularly frustrating to make it all the way through the checkout process and find a large shipping fee tacked on, especially when it represents 20% of the order total. Shoppers are much more inclined to purchase, and make larger orders, if they know that there's free shipping.

Indeed, there are numerous case studies on this subject. Practical Ecommerce collated a few, which say that it can:

  • Increase order totals
  • Increase revenue
  • Increase conversions
  • Increase new customer acquisition

The list goes on. Time and time again customers are clear in both their words and their actions: free shipping is a major incentive.

Coming up, I'm going to take you through a tutorial that shows you how to implement a widget on the shopping cart page, which acts as an indicator for how close the shopper is to qualifying for free shipping. The idea is that there's a $50 minimum threshold and when the shopper looks at the shopping cart page, there is something that incentivizes them to increase their order total to qualify for free shipping.

The point of this article is twofold:

  1. To get you to think about whether free shipping is something you want to offer
  2. To create a tutorial that covers topics such as creating a new module, adding a child view to an existing one, and doing some scripting and styling

In short, I think this is going to be a fun little tutorial suitable for beginners.

Considerations Before You Offer Free Shipping

However, free shipping can be a massive money blackhole for you — the site administrator — if you offer it carte blanche. Indeed, even massive retailers, such as Amazon, have slowly been increasing the threshold over the years, no doubt because of the cost.

Kissmetrics say that while there is no doubt that it can perform wonderful things to your sales, it can dampen your profit margins if you're not careful. So how do you get it right? It's hard to say whether it'll work for your site, but they reckon you should run a trial and perform some tests. Set clear baselines and thresholds, so both you and your customers know what to expect. Consider raising prices slightly to offset any losses.

In truth, there are lots of things you need to consider before doing this. There's a lot of reading to be done around the topic. You'll also need to take a look at your financials to see where it would work and if there's anything you need to do before you try it.

In short: work out if this is right for you. Even if it's not, this tutorial can still be done on your site local and sandbox site and then removed later. So, with that out of the way, let's move on to the main point of this article.

Prepare the Module Structure

As always, let's get the structure in place before we do any coding.

In your customizations directory, create FreeShippingBar@1.0.0. In it, create the following:

  • Configuration
  • JavaScript
  • Sass
  • Templates
  • ns.package.json

In ns.package.json, put the following:

{
  "gulp": {
    "javascript": [
      "JavaScript/*.js"
    ],
    "templates": [
      "Templates/*.tpl"
    ],
    "sass": [
        "Sass/*.scss"
    ],
    "configuration": [
        "Configuration/*.json"
    ]
  }
}

Then, we need to update distro.json to:

  • Register the module
  • Include the module in the shopping application's JavaScript
  • Include the module in the shopping application's CSS

After that, we need to create the entry point file. In your JavaScript folder, create FreeShippingBar.js and put the following in it:

define('FreeShippingBar'
, [
  ]
, function (
  )
{
  'use strict';

  return {

  }
});

That's right, we put a whole load of nothing in this file so far but that's fine because all we need is the define statement — without it, Gulp will throw a tantrum and complain that you didn't define the module.

Anyway, that's the skeleton put in place for now. Run gulp deploy to get up to NetSuite, and let's begin local development.

Add a Child View to a Composite View

So the plan is to add a widget to the shopping cart page that indicates how close the shopper is to achieving free shipping. What I want to do is add it below the estimated total in the cart summary container, like this:

When I inspect the code in my browser for this container, I can see that it is controlled by cart_summary.tpl, which gets is served by Cart.Summary.View.js. In order get my widget to appear in this container, I'll need to add an element that the widget can be added to, and add a child view to the view.

Firstly, let's create a template and put some text in it. In Templates, create free_shipping_bar.tpl. In it, put the following:

<div class="free-shipping-bar-container">I'm going to be a widget! YAY ME!</div>

Now, from here, there are two ways to get this template to appear in the other:

  1. As a plugin — this is something we covered in the testimonials module tutorial. We include a number of tools in SCA that allow you to inject code into views at various stages of rendering, so you could do that with this.
  2. By extending the childViews object — this is the documented method. You set up your module and then simply use the tried-and-tested way of prototyping the existing object to add another value.

I've covered the first option in the other tutorial, so I figure we can try the documented method here.

This way relies on you having to override the template you want the new child view to appear in, so we'll need to do that. As a best practice, you shouldn't include the overridden template as part of the module that is adding the functionality. This is because, over time, you will likely add numerous customizations to a template: thus you should have one 'master' override template in which you put all of your customizations.

If you don't already have a customizations module for Cart then create one now. You need to go through the same process for creating a new module and creating a skeleton:

  1. Create a new module in your Customizations directory, eg Cart.Extended@1.0.0
  2. Create sub-directories for JavaScript and Templates
  3. Create an entry point file (Cart.Extended.js), and define the module
  4. Create a template (cart_summary.tpl) and copy and paste the contents of the original file into this one
  5. Create an ns.package.json that includes the JavaScript and templates, but also adds an override for the template
  6. Update distro.json to include your new module in the distribution — remember to include the JavaScript in shopping.js

If you don't remember how to do an override, it looks like this:

{
    "gulp": {
        "javascript": [
            "JavaScript/*.js"
        ],
        "templates": [
            "Templates/*"
        ]
    },
    "overrides": {
        "suitecommerce/Cart@3.0.0/Templates/cart_summary.tpl": "Templates/cart_summary.tpl"
    }
}

As you can see, we're telling it to replace one template with another. Overriding is really only useful with templates because things like JavaScript files can simply be extended instead.

So, now, we need to add in an element in our template for the free shipping bar to be loaded into. As I stated in my earlier mockup, I'm going to add it below the estimated total. In the overriding template, do a search for #if showActions and paste this above:

<div data-view="FreeShippingBar"></div>

The the fact that this element has the data-view parameter on it indicates that it's going to be used to bring in a child view. By specifying FreeShippingBar, it's telling the code to look for a value with this name in the (parent) view's childViews function. But it doesn't exist... yet.

We need a new view to include. It's not enough to simply say to the parent view, "show this template" — we need to say "render this view", which will then show the template we want.

In JavaScript, create FreeShippingBar.View.js and in it put the following:

define('FreeShippingBar.View'
, [
    'Backbone'
  , 'free_shipping_bar.tpl'
  ]
, function (
    Backbone
  , free_shipping_bar_tpl
  )
{
  'use strict';

  return Backbone.View.extend({

    template: free_shipping_bar_tpl

  });
});

So: we're defining the module and adding dependencies for Backbone and the template we want to use. Then we're extending the boilerplate Backbone view and returning a single value: the template. All we're saying is that when this view is rendered is, "show the template". We can add more to this later, but for now we just want to show the template.

Let's head back to FreeShippingBar.js. This file is a complete skeleton, containing nothing. Let's start by adding two dependencies: Cart.Summary.View and FreeShippingBar.View. In other words, we're including the view we want to extend and the view we want to extend it with.

Next we need to add some code to be executed when the module is loaded. In the return statement, put the following:

mountToApp: function(application)
{
  CartSummaryView.prototype.childViews.FreeShippingBar = function()
  {
    return new FreeShippingBarView
  }
}

"When you load the module, extend the view and add a new value to the childViews property" is what we're saying here. As we know, that child view then loads the template for the shipping bar, which is what we want.

Save everything and run gulp local. Visit your local site and add something to your cart. When that's done, head over to the shopping cart page and take a look at the summary box. You should see the template rendered in all its beauty:

And with that, we have the framework in which we can work: we have added in a mechanism to get an additional view and template to render on the shopping cart page. We can now move on to the scripting part.

Calculate Order Difference

The next important part of this work is showing the difference between the order amount and the threshold that the shopper needs to make up before they qualify.

I think there are three important parts to this:

  1. The threshold figure must be stored and then pulled in from somewhere
  2. The order total must be pulled in
  3. There must be some JavaScript that calculates the difference and returns the result

Configuration

For the purposes of this tutorial, I'm assuming that you have your shipping configured to already allow free shipping over a certain amount. The point of this exercise is to emphasize it.

I'm also assuming that you only operate one currency on your site (and that is USD). If you operate multiple currencies, you'll need to add in some additional values and code to ensure that you it works and responds for all currencies.

What we're going to do in this tutorial is store the threshold amount in the backend as a value, and then pull it in from the frontend. To do this, we're going to create some entries in the backend configuration to store this value.

If you're running Vinson or later, you add new configuration values by using the configuration tool. It works in two parts:

  1. You define the module's configuration options in JSON configuration files. These are then uploaded to the server.
  2. The server takes the configuration files and generates an interface to set these values. You set these values in Setup > SuiteCommerce Advanced > Configuration.

In the ns.package.json file for this module, we already included code to make it pull in any JSON files it finds in the Configuration directory so that's done. What we need to do now is create the file.

In Configuration, create FreeShippingBar.json and put the following in it:

{
  "type": "object"

, "subtab": {
    "id": "freeshippingbar"
  , "group": "shoppingApplication"
  , "title": "Free Shipping Bar"
  }

, "properties" : {
    "freeshippingbar.isEnabled": {
      "group": "shoppingApplication"
    , "subtab": "freeshippingbar"
    , "type": "boolean"
    , "default": false
    , "title": "Enable Free Shipping Bar"
    }
  , "freeshippingbar.threshold.usd": {
      "group": "shoppingApplication"
    , "subtab": "freeshippingbar"
    , "type": "integer"
    , "default": 50
    , "title": "Free Shipping Threshold (USD)"
    }
  }
}

What we're doing here is creating two new options and adding it to the subtab for the free shipping bar (which will be created if it doesn't already exist). We're storing two values: one to enable/disable the functionality and another for the actual threshold value. Note that I've specified a currency (USD) as if you operate your site with multiple currencies, you're going to want to have values for different currencies.

In order to set and access this value, we need to deploy it to the site as configuration changes cannot be made locally. We've made changes to the templates, so if you're uploading to a live site, I would strongly recommend clearing free_shipping_bar.tpl of all content so your customers don't see the dummy message appearing on the shopping cart page. Once you've done that, run gulp deploy.

When it's finished, the settings will be pushed up to the site and the configuration UI generated. Head to Setup > SuiteCommerce Advanced > Configuration in the backend, select your site, then look for the settings in Shopping > Free Shipping Bar. You'll see that the switch to enable it is unchecked (this is fine, it does nothing right now) and the threshold has been set to 50 already (we set the default to 50) — this is also fine.

Get the Order Total

Great! So now we have the threshold value on the backend, we now need the order value on the frontend to compare it to. Take a look in Cart > Cart.Summary.View.js. In the context, we set a value for summary — this is, well, a summary of some key values of the cart. Useful for us, it contains numerous values to do with the cart's value. To test this out, head back to the initialize function and put in the following code:

console.log(this.model);

Head back to your local site and open the developer console on the cart page. You'll see an object returned — click on attributes and then you'll see a whole bunch of values. Take a look at the summary object.

Now here's where you need to think about things from a business point of view: do you want to offer the discount before any discounts or afterwards? In other words, if someone has something worth $55 in their cart and then applies a 10% discount, should free shipping still apply even though the order value is $49.50? This is something you need to work out with your promotion and test it to see how the rules work. For the sake of this tutorial I'm keeping it simple and going with the standard sub-total, which is the value of the items and nothing else.

We know what we need, so what we need to do is ensure that the model is made available to the view when we invoke it. Open FreeShippingBar.js and where we return the view, set the model value:

return new FreeShippingBarView({
  model: this.model
})

Super! Now we just need to do some math.

Calculate the Difference

OK, so here's what we want to do:

  1. Get the cart subtotal
  2. Get the threshold
  3. Calculate the difference
  4. Return a helpful message to the context based on this value

To do this:

  1. Add the configuration as a dependency
  2. Create a getContext function
  3. Create variables for the cart summary and configuration, and then create ones for the subtotal, threshold and difference
  4. Create a variable that checks the difference that either encourages the shopper to add more to their cart, or congratulates them on already doing so

You can take a stab at this yourself, if you like, or you can use the following:

define('FreeShippingBar.View'
, [
    'Backbone'
  , 'SC.Configuration'
  , 'free_shipping_bar.tpl'
  ]
, function (
    Backbone
  , Configuration
  , free_shipping_bar_tpl
  )
{
  'use strict';

  return Backbone.View.extend({

    template: free_shipping_bar_tpl

  , getContext: function getContext()
    {
      var summary = this.model.get('summary')
      , config = Configuration.get('freeshippingbar')

      , subtotal = summary.subtotal
      , threshold = config.threshold.usd
      , difference = +(threshold - subtotal).toFixed(2)

      , message = function message() {
          if (difference > 0) {
            return 'Add \$' + difference + ' more to your cart to get free shipping!'
          } else {
            return 'Congratulations, you qualify for free shipping!'
          }
        };

      return {
        message: message
      }
    }
  });
});

As I said previously, if you run multiple currencies on your site, you'll need to be a lot more dynamic in your approach to this code. Take a look at GlobalViews > JavaScript > GlobalViews.CurrencySelector.View.js for an idea on how to approach pulling in currency information.

Anyway, you should see what's happening here: we're building up what we need in the context that culminates in a message that we can surface on the frontend.

Save this file, then head over free_shipping_bar.tpl and replace the dummy text with:

<div class="free-shipping-bar-container">
    <p class="free-shipping-bar-message">{{message}}</p>
</div>

Save this and then refresh the shopping cart on your local site. Depending on the contents of your shopping cart, you'll see one of these messages:

And that's the basics of getting this functionality to work. Now we can move on to making it pretty.

Styling

Now if you're not being flashy about this, you can add some basic styling to make sure that it looks presentable and fits. To start, create _free-shipping-bar.scss under Sass and put the following in it:

.free-shipping-bar-container {
    padding-bottom: $sc-base-padding * 3;
}

.free-shipping-bar-message {
    padding: $sc-base-padding * 2;
    text-align: center;
}

That's enough to fix the issues with it rubbing up against the sides of the container element and to make it look decent. You can go from there if you want to add something a little nicer, or other things to make it suit your style. Whatever you do, stop and restart your local server to see your changes as you've added a new file.

There are, however, alternative approaches that you can make if you want to get fancy. One thing you could do is create a progress bar of sorts, which fills in as the cart subtotal closes in on the threshold.

Progress Bar

Why not encourage people by showing them how close they are with a graphic?

We know what the threshold is and what the order total is, so it's easy to work out what percentage the order total is of the threshold.

Back in FreeShippingBar.View.js, add in a new variable to the getContext function:

, diffpc = (subtotal / threshold * 100) + '%'

Then return this as diffpc to the context. As you can see, what we are doing is simply converting this to a percentage.

Back in free_shipping_bar.tpl, add in the following markup:

<div class="free-shipping-bar-progress" style="width: {{diffpc}};"></div>

As you can see, we're setting an inline style for this element based on the value passed to it via the context. So far so good.

Finally, we need to set some CSS. In _free-shipping-bar.scss, add in:

.free-shipping-bar-progress {
    max-width: 100%;
    background: red;
    height: 25px;
}

What you choose is largely up to you but note that setting the maximum width to 100% is important: without this, the element will continue to grow and grow once it goes over 100% of the threshold, which we don't want. The max-width property always overrides the value of the width property if the width value exceeds it. You could modify the JavaScript so that once it goes over 100, it always sets in to 100, but this is a more native and simpler way of doing it.

Save your files and refresh your local cart page. You should see something like this:

This isn't particularly attractive as is, and I wouldn't push it live like this, but you get the idea. You can certainly be very creative with this, such as changing the color of the bar so that it goes to a more 'approving' color the closer it gets to 100%. For example, red is a very prohibitive color, so turning it green would be a good start.

Tooltips and Notes

You'll notice that next to the expanders for the promo code and tax/shipping estimator, there's little question marks. If you're going to offer free shipping, along with a little widget that responds to the user's total, then I'd certainly recommend adding in a link (or at least some guidance) on the terms and conditions that apply.

For example, linking off to a page which lists the legal stuff surrounding the promotion is certainly a good idea. It's worth emphasizing that the widget is approximate (ie for illustration purposes only) and that the final calculation is made at checkout.

Implementing a tooltip is quite simple, you can take a look at the code we use for the other tooltips. For my purposes, I'm adding the following next to {{message}} in my template:

<i data-toggle="tooltip" class="free-shipping-bar-message-tooltip" title="{{translate '<b>Free Shipping Estimator</b><br>Please note that the free shipping indicator is an estimation and used for illustration purposes only. The final qualification check is made at checkout.'}}" ></i>

Then, in my Sass file, I just need to add the following styling:

.free-shipping-bar-message-tooltip {
    @extend .sc-tooltip;
    @extend .icon-question-sign;
}

Save the files and refresh. You should see the following:

Final Thoughts

This article has two uses:

  1. It teaches you a simple project that you can do yourself
  2. It should make you think about whether free shipping is something you want to entertain

On the first part, there is no doubt that this a tutorial aimed at beginners. It takes you through the process of adding a new module and, perhaps most specifically, about how to add a child view to an existing view using the documented best practice.

It also covers things like overriding templates, decision making in terms of JavaScript and CSS, and how to make use of existing features of SCA code so that you don't end up reinventing the wheel. I also hope that it spurs you on to being creative.

As for free shipping itself: allow me to reiterate that this is part of a wider organizational decision that needs to be made. While the code itself is adaptable for other scenarios, the decision to offer free shipping is a big step. It is a big step in deciding how to implement this, as well as what logistical changes you need to make to your supply chain in order to make it a reality.

There are a lot of resources online that you can take a look at that discuss the pros and cons of this approach, and it's certainly worth investigating if it could be used to boost your revenue. Taking a small hit in terms of free shipping may end up boosting order value, order size, conversions and overall customer happiness. Whether that's true for you is up to you to decide.

More Information