Post Featured Image

Get Started with SuiteCommerce Themes

This blog post applies to the concept of themes that was added in the Aconcagua release, and is therefore only applicable to SuiteCommerce sites and SuiteCommerce Advanced sites that support them.

We've talked about themes before: for example in Kilimanjaro and Elbrus, but with the release of Aconcagua, there's a been a paradigm shift in what this means.

This shift has been ushered in by the maturity of the commerce extension framework. If you're not already familiar with what I'm talking about, I strongly recommend that you get to grips with it before proceeding. There is a lot of background and changes to the way you'll think and work.

In short, however, let me say this: after the initial creation of a theme by a developer, control and customization is moved into the hands of site administrators. To achieve this, we provide a superhero combo of new architecture for devs and a powerful UI for site admins. The new UI comes in the form of the double-act of the extension manager and the theme customizer, which complement the array of tools already available in the site management tools.

What this means is that the developer puts in the hard work to set up a theme: defining the layout of the templates, and setting some initial Sass default values, and then the site administrator can tinker with them to produce the best fit for their vision of what their site should look like.

Furthermore, developers can go further than defining one set of defaults for a theme: they can also include what we call skins. Skins are like a abstraction layer above the theme containing a pre-defined list of values. The idea is that if you like your site's layout, but only want to change the colors and font sizes, then you can save these to a file and allow administrators to easily switch between them. This'll prove useful if you like to refresh your site's appearance for different seasons, or if you have a promotional event on.

In this post, I want quickly reiterate what we've said before about themes while adding a bit more depth and color to the picture, look at some of the unique features of this reconception of themes, and then build a simple theme forked from the base theme we include with Aconcagua. In other words, I'm going to show you all the pieces of themes and theme development, and then I'm going to show you how to fit them together.

We have a lot of documentation on the subject of theming, which I strongly suggest reading, and I'll make reference to specific pages as we go.

What is a Theme?

A theme is a special type of extension. Extensions were introduced for Aconcagua and the release of the new SuiteCommerce product: they allow modification to the functionality and/or the look-and-feel of a site without modifying the source code files of a site. Both are enabled or disabled, and then recompiled into the site's final source code, via the extensions manager.

Here are some of their similarities:

  • All files are versioned, and the appropriate files (including images) can be referenced on a version-by-version basis (eg for easy updates and rollbacks)
  • They use similar (but different) development tools
  • Can be easily packaged up for sharing
  • Give a reasonable level of certainty that they'll work regardless of the site and domain they're activated on
  • Activated through the Extension Management page in the UI
  • Neither enable the modification of source code files
  • Recommended for all new (post-Aconcagua) SCA sites; mandatory for all SuiteCommerce sites

For the purposes of this article, we won't refer to themes as extensions again — it's best to think of them as distinct things. The following table summarizes the differences between a theme and an extension.

ThemesExtensions
Alter the design, look, and feel of a specified domainIntroduce new functionality or features to a specified domain
Can include HTML, Sass, fonts and images onlyCan include SuiteScript, JavaScript, configuration files, HTML, Sass, fonts and images
Existing HTML and Sass files are modified directlyExisting HTML and Sass files are overridden; new files can be added for new functionality areas
Only one can be active per domain at any timeAny number can be active on a domain at any time

To get a sense of things, it's good to look at the base theme included with the release.

The Base Theme and its Anatomy

As with every previous version of SuiteCommerce Advanced, we include a set of templates and Sass files with the release.

We strongly recommend using the base theme as the foundation for all new themes. Not only will it save you time but it's also our example of the best practices you should use.

If you have access to the SCA source code, you'll see that it omits all of the Sass, template and asset (image and font) folders that you may be accustomed to — they are now kept separate, in a managed bundle called the SuiteCommerce Base Theme, and must be installed and downloaded during setup.

After you've installed the bundle and local theme development tools, you start by fetching the current theme from your site. This is done with gulp theme:fetch.

When it completes, you'll be furnished with a workspace that contains all of the folders and files that constitute your theme. As our docs say, you'll see something like this:

Workspace/
  Extras/
    Extensions/
      application_manifest.json
  SuiteCommerceBaseTheme/
    assets/
    Modules/
    Overrides/
    Skins/
    manifest.json

The Extras folder contains anything related to any extensions that are currently active on your site. For the timebeing, we're going to ignore that folder and instead focus on the contents of SuiteCommerceBaseTheme. Note that this name is dependent on the active theme.

assets

One key change is that we now store fonts and images under a single parent directory away from the modules that depend on them. By default we include two sub-directories: font-awesome and img — one is the only custom font we use, and the other is a catch-all for all the site's base imagery (eg for credit card icons, favicon, etc).

Note, however, you are free to organize your assets as you need to within the assets parent directory. So, if you're going to add a custom font, then create a folder with its name on it; if you want to separate your images into separate folders that make sense to you, do it! They'll be included in your theme's package.

Modules

This is the meat of the theme. This is where all of the templates and Sass files that you're familiar will live.

If you're already familiar with SCA development, there isn't much to say about these files and folders. However, one important thing to note is that in theme development we do allow you to edit the source files directly. Go wild.

Overrides

This isn't a directory for the files within your theme. It is for theme-specific overrides of any extensions your site has.

Picture this scenario: you've got a fancy extension that adds some new functionality to your site, but its layout and styling doesn't conform to the rest of your site. What do you do? Edit the files of that extension? Yuck. No. You put in theme-specific overrides.

This post won't go into the details of this, but if you need this, we have docs on how to do it.

Skins

Remember: while you'll build a number of default values into your theme, you can additional sets of default values into skins. A site administrator can swap between skins using theme customizer. But how do we determine what a skin is? The answer is in this folder and let's take a closer look.

If you look at the contents of one of the skins in the base theme, eg skin1.json, you'll see that it's an object of key-value pairs.

{
"$sc-color-body-background": "white",
"$sc-button-primary-text-color": "white",
"$sc-button-primary-hover-text-color": "white",
"$sc-button-primary-active-text-color": "white",
"$sc-button-primary-text-transform": "none",
...
}

The keys are a number of 'editable' Sass variables that are present throughout the theme and the values are the values we want to change them to.

What happens is that when a user enters the SMTs and selects a skin, it loads the JSON blob, substitutes the values in the theme, and then recompiles on-the-fly. This allows for rapid switching and previewing of a color scheme (plus any other style changes to fonts, spacing, etc).

Creating your own skin can be as simple as copying an existing JSON blob in a theme and putting in your own values. Any JSON file within the Skins folder will be caught by Gulp when you deploy, and will be automatically added to the manifest file. It will automatically take the name of the JSON file (eg, a file called skin9000.json will be named skin9000) but you can change this in the manifest. If you want, you can compile just the manifest file and then change the name of it to whatever you want before you deploy.

However, if you're working on a new skin that includes previously unreferenced variables then you should know that it's not enough to simply include your variables in your skin to make them configurable in the SMTs — you must also mark up your code too. We'll look at this later.

manifest.json

I've mentioned this a couple of times already, so let's take a look.

As I said in my post on the commerce extension framework, extensions and themes don't use ns.package.json and distro.json files anymore (well, distro files are still present, but you don't need to worry about them). Instead, we now use manifest files.

Manifests work like the two of them combined, with the added benefit of them being automatically updated when the compilation process runs. You will need to manually edit them to specify some things, such as the metadata of the themes and skins, but generally it means you don't have to manually include every file that you want to be included in your project.

You can prevent manifests from being updated automatically by using a flag when you deploy.

Versioning and Activation

I've talked about this in the introductory blog post on extensibility, so I won't reiterate it here in great detail. Suffice to say, themes (like extensions) are not automatically applied to a site when you deploy the code to NetSuite: they must be activated first. Activation recombines the site's source code to create the final output. Only one theme can be active on a site at a time.

Also, when I say 'site' I mean, strictly speaking, 'domain'. Themes and extensions are activated on a per-domain basis. This means that if you want to set up a secondary SSP on which to do development work, or to simply create other façades for your inventory.

Referencing Assets

One thing I do want to reiterate and go into greater detail about are how we handle paths to assets across versions.

Consider this scenario: your theme contains imagery. That imagery changes across different versions, so what happens? Do images gets overwritten? No. They're stored in separate folders, just like all the other files in a theme.

So, how do you generate links to them when they have same names? New helpers! In total, there are four new Handlebars helpers for your HTML and two new Sass helpers for your styles.

These helpers provide and maintain dynamic paths to the assets. Our documentation goes into detail about the what, how and when of these helpers, but here's a summary:

Helper TypeCustomization TypeName
HandlebarsExtensionsgetExtensionsAssetsPath(default_value)
HandlebarsExtensionsgetExtensionsAssetsPathWithDefault(config_value, default_value)
HandlebarsThemegetThemeAssetsPath(default_value)
HandlebarsThemegetThemeAssetsPathWithDefault(config_value, default_value)
SassExtensionsgetExtensionsAssetsPath($asset)
SassThemegetThemeAssetsPath($asset)

The primary use in templates is when you would call an image whose full relative path hasn't been defined by the view. For example, in the homepage template we have fallbacks for when no images are defined in the site configuration that look like this:

<!-- Example code -->
<img src="{{getThemeAssetsPath (resizeImage 'img/carousel-home-1.png' ../imageHomeSize)}}" alt="" />

<!-- Translated output -->
<img src="/c.123456789/scs/extensions/SuiteCommerce/Suite_Commerce_Base_Theme/18.1.1/img/carousel-home-1.png" alt="">

So you're saying that the image is the one in the images folder with this file name, now provide the path required to access it on the frontend.

To use a Sass example, let's say we wanted to add a background image to an element — an image that could change depending on the version of the theme, you would mark up your file as follows:

// Example code
.myClass {
    background-image: url(getThemeAssetsPath('img/flowers1.jpg'))
}

// Translated output
.myClass {
    background-image: url(/c.123456789/scs/extensions/SuiteCommerce/Suite_Commerce_Base_Theme/18.1.1/img/flowers.jpg)
}

Thus, they work the same way.

If you're wondering what the difference between a normal helper and one 'with default' — essentially, you use them in cases where a user may specify a value in the site's configuration record, but you want to include a fallback value in case. A good example of this is in creditcard_edit_form_securitycode_tooltip.tpl:

<p><img src="{{getThemeAssetsPathWithDefault imageCvvAmericanCardURL 'img/cvv_american_card.jpg'}}" alt=""></p>

This appears on the credit card form when we ask a shopper for their CVV code. We want to show an image of where to find this on Amex cards. The location for this image is a configurable option — a site administrator can easily change the image and location of it in NetSuite — but, what if the value is cleared? Well, we can show a fallback image that we include in the theme.

Working Locally

Themes and extensions have separate working environments from each other and from SCA. Depending on what you're working on, you will need to spin up a local server that is contextual to that. However, when you work on an extension you'll always start by grabbing the site's active theme, and when you work on a theme, you'll grab the site's active extensions. This, therefore, means that you'll never be working on something in complete isolation.

You can read more on testing a theme on a local server in our documentation.

There are three key Gulp commands for working locally:

  1. gulp theme:local — spins up the standard local server
  2. gulp theme:local --preserve-manifest — spins up the local server without updating the manifest
  3. gulp theme:local styleguide — spins up the local server, and a second local server for viewing the live style guide

As always, the URL of your local server is dependent on your site's configuration and whether you're running SC or SCA.

Preserving the manifest with the flag can be useful if you're tinkering around with your file structure and only want specific files included, for example with debugging. If you want to exclude a file without manually editing the manifest, then you'd need to move it out of your workspace, which could be a bit of a hassle.

Finally, the style guide is something I've talked about before and it hasn't changed that much since then. If you're unfamiliar with it, consider it a resource that can aid you and your team make design decisions when creating or modifying the features of your site. It shows, live in realtime, things like your colors, typography, and even bigger bits of functionality such as forms.

Prepare for a New Theme

Let's get started.

For the purposes of this, I'm going to work with the NetSuite base theme. If you already have a custom theme that you want to modify, then you can follow along with that but some things may be different.

Fetch the Active Theme

OK, so at this point you've done all the basic install steps, like installing the bundles, grabbed the developer tools and unzipped them, installed Gulp and Node. The first thing you need to do is navigate to the parent folder for the theme developer tools in your CLI and run gulp theme:fetch. This command will pull down a site's active theme. Note that this will overwrite any files you have in your workspace, so I strongly recommend that, in future, you only run this when you're happy to lose what you're currently working with.

Create the New Theme in NetSuite

If this is a brand new theme (which in this example it is) then we need to begin by creating a record of it in NetSuite. To do this, we run gulp theme:deploy --create. From there you will be asked a series of questions about the metadata of your new theme.

Once it has been deployed, you'll be given some feedback about next steps; ie, how to activate it on your site so that it takes effect. However, at this point, seeing as your theme is just a copy of the existing theme with no modifications, we can skip that.

You will notice, however, that your local files have been renamed and updated to match the name that you specified. For example, my theme's directory is now called My_Super_Cool_Theme and the metadata at the top of the manifest file looks like this:

"name": "My_Super_Cool_Theme",
"fantasyName": "My Super Cool Theme",
"vendor": "Dave Smith",
"type": "theme",
"target": "SCA,SCS",
"version": "1.0.0",
"description": "This is my first theme and it's super cool",

Great stuff!

Versioning with VCS

Now that you have the theme, this might be a good time to start versioning it locally. I've talked about it loads of times before but if you're not already using something like Git to version your code, I strongly suggest you get started with version control. It could save you some serious headaches.

If you've got Git installed and ready to go, let's proceed; if you're not going to version your code, you can skip this section.

So, one question I've been asked is how much of an extension or theme's code you should version. For example, should you include the distribution folders? What about the node_modules folder? Including those would certainly make your repo more 'complete' but you may end up with quite noisy commits.

Look, my suggestion is that you only version the source code that compiles into the theme and nothing else. Therefore, you need the contents of your theme's directory only; eg, for me, that would be SCA-THEME > Workspace > My_Super_Cool_Theme.

In order to do this, we'll need to make use of gitignore, a way of telling Git to intentionally ignore certain folders and files.

In your parent directory (which I've called SCA-THEME), create a file called .gitignore and in it put:

# exclude everything except for Workspace/<theme>
/*
!/Workspace
/Workspace/*
!/Workspace/My_Super_Cool_Theme

For details on what's going on here, take a look at their documentation but I'll summarize:

  1. (The first line is just a comment to us)
  2. Ignore everything!
  3. Except the Workspace directory
  4. But then ignore everything in there!
  5. Except the My_Super_Cool_Theme directory

Then, in your command line, run git init; when that's done, run git status — you should see this:

$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Workspace/

nothing added to commit but untracked files present (use "git add" to track)

Running git add . and then git status will give you a long list of green text, itemizing all of the goodness we're going to be saving. Crucially, they should be within the Workspace/My_Super_Cool_Theme directory. If they are, and you're happy, go ahead and do git commit -a -m "Super Cool Theme -- initial commit".

Great! That's it. If you have a remote repository, such as GitHub or Bitbucket, then you'll need to do the extra steps for push it up to there, but for now we can move on!

Create a Theme

OK, let's make our first changes. For the purposes of this tutorial, I'm not going to create an entirely new theme — that would be a lot of work! — but what I am going to do is a number of small changes to illustrate the beginnings of a new theme. You could take it from there if you like.

Add an Image

I'm going to start with something simple: I want to show a big banner image on my homepage. How do I do that?

First, I've prepared my image, it looks like this:

I'm going to go ahead and add it to assets > img.

Now, I need to edit my homepage template.

In Home > Templates > home.tpl, add the following near the top (eg above the slider):

<div class="home-banner-prices">
    <img class="home-banner-prices-image" src="{{getThemeAssetsPath (resizeImage 'img/themepricesoutofthisworld.jpg' homeslider)}}">
</div>

After saving, run gulp theme:local.

Gulp automatically adds the file to the manifest and spins up the server. When it's up, visit your local homepage and you should see something like this:

Great stuff. But, it looks a little cluttered: the banner top message is right on top of it, and we need a little margin to space it out nicely.

Add Styling

In Home > _home.scss, add in:

.home-banner-prices {
  margin-top: $sc-margin-lv4;
  font-size: 0;
}

As the local server is still running, it will recompile the site's files when you save. When it's done, refresh the homepage and revel in how well spaced out your new banner is!

Add a Customizable Color

You know, this banner image looks great but I think it would look even better if it had a luminescent glow around it. You know, really make it look eye-catching. Furthermore, I don't want to dictate what this color is: I want my site administrator to be able to decide. How do I do this?

If we want to expose a variable for customization, we need to add (or find) the variable in the Sass file and then put a special comment next to it. The comment must contain a properly configured editable() function to get picked up the preprocessor.

Let's do this properly and add a new module for our customization.

In Modules, create a folder called Glowy@custom-1.0.0 and then another below it called Sass.

In that child folder, create _glowy.scss and in it put:

$color-glowy: #3bfbfd; /* editable({
    "type": "color",
    "label": "Glowy Color",
    "description": "For when you want extra glowy stuff"
})*/

@keyframes glowy {
  0% {box-shadow: 0 0 -10px $color-glowy;}
  20% {box-shadow: 0 0 100px $color-glowy;}
  40% {box-shadow: 0 0 200px $color-glowy;}
  60% {box-shadow: 0 0 200px $color-glowy;}
  80% {box-shadow: 0 0 100px $color-glowy;}
  100% {box-shadow: 0 0 -10px $color-glowy;}
}

.glowy {
  animation: glowy 1500ms infinite;
}

So, the first bit is the editable color. Note I've set an initial value and then put a comment with an editable() state function in it, where I set some metadata around this variable.

The next bit is just a bit of fun, I'm going to make the image glow and I want it to be animated, so these are the 'keyframes' of the animation.

Finally, the .glowy class is what we will use to attach the animation to an element.

Now we have that set up, we need to add it to the entry point Sass files for the applications we want to use it in.

Open Shopping > shopping.scss and add in the following:

@import "../Glowy@custom-1.0.0/Sass/glowy";

This is how we will tell the developer tools to combine it into the final CSS files for each application.

Finally, we need to modify our homepage Sass so our element uses our new styles. Tab back to _home.scss and add in:

.home-banner-prices-image {
  @extend .glowy;
  width: 90%;
  margin: 5%;
}

Great! Save and then stop and start your local server (you've added new files, so they need to be tracked). When it's up again, refresh your homepage and take a look. It should look like this:

Glowy.

Add a Custom Variable to a Skin

Now that we have this, we can add it to a skin so that it can be manipulated by a site admin. If you want, you can also use this opportunity to create an entirely new skin (starting by duplicating an existing one), but for now we can just tinker with the existing ones.

In your theme's folder, open up skin1.json, scroll down and add:

"$color-glowy": "red"

Don't forget to add in a comma on the end of the previous line.

Open up skin2.json and do the same, this time replacing red for green.

So, remember what we're doing here: the theme default color is what we originally set $color-glowy to; in the skins, we have new values (red and green) that are only activated if the administrator selects them in theme customizer.

Update Manifest and Deploy

Great! We're now ready to test this out. First, you should update the version in the manifest — we're going to create a new version of our theme!

Open manifest.json, and change the value of version to 1.0.1.

After saving everything, run gulp theme:deploy.

When that's done, activate the new version of your theme.

Finally, head over to your homepage and load up the site management tools. Once it's fully loaded, click the cog icon and select themes.

Theme Customizer

The theme customizer allows any administrator to change the values of any exposed Sass variable. Take a look at the options.

You'll notice that there's a Palette section, which lets you change the master groups of colors associated with your site. Then, as you scroll down, the options will get more granular. For example, you could change the primary color of the theme, but then override that for headings.

You'll also notice that some of the options are grouped up, and that some have pre-defined options: these are additional features that you can build into your Sass stylesheets if you like.

To get an idea of groupings, open BaseSassStlyes > Sass > reference-theme > _groupings.scss and take a look. For example:

/*
group({
    "id": "typography-h1",
    "label": "Heading 1",
    "description": "",
    "children": [
        "$sc-color-h1",
        "$sc-h1-font-family",
        "$sc-h1-font-size",
        "$sc-h1-desktop-font-size",
        "$sc-h1-line-height",
        "$sc-h1-text-transform"
    ]
})
*/

Which translates into:

If you're interested in creating your own marketable themes, you should definitely consider putting in the work to create neat little groupings. You could also create a custom area in the styleguide too.

Anyway, we're here to test our new glowy banner. You should see that the glowy banner is in a light blue color, which is the default we set in the theme. Now, if you scroll down to the bottom of the customizer, you can see our new option available.

Feel free to change the value; try red, green, pink, whatever you want. The cool thing is that it will change it realtime before your very eyes.

Finally, while we're here: you can change the skin. Remember, we put in new variables for each skin, so you can change them and watch it take effect.

If you want to keep one, you can save the changes and it'll take effect on your site straight away.

Troubleshooting

There aren't many problems specific to themes, but here are some you may encounter.

Cannot Access Theme Customizer in the Site Management Tools

When logged into the SMTs, you can access the theme customizer by clicking on the cog icon and selecting Themes from the dropdown. If the theme customizer is not detecting customizable themes or skins, it won't be available and clicking the cog will take you straight to a list of your site's content types (without showing you the option for the theme customizer).

At this point, we're not entirely sure why the link doesn't show up when it should but we have found a workaround.

  1. In NetSuite, search for the skins associated with your theme (eg, search for skin1.json, skin2.json, etc)
  2. Edit and save each record
  3. Edit and save each JSON file for each skin
  4. Invalidate the cache for the domain

The link to the theme customizer should now appear in the SMTs when you refresh your browser.

Exposed Variable Metadata Doesn't Load

This is something I discovered while tinkering: you've configured your new Sass variable to be configurable via the theme customizer, but when you get there, it doesn't look right, eg:

If you open up the developer console, you might see something like this:

In my early iteration, I realized that I had not put commas in my JSON object and so it couldn't parse each of the key-value pairs. So! Check your JSON, make sure that you've coded it correctly.

Final Thoughts

And that's the basics of creating a theme for a SuiteCommerce site. What we've seen is how a developer can enable a site administrator by providing the structure for a theme — through template and Sass changes — and how the admin can then go on and make changes for themselves. It's can obviously get a lot more intricate than the examples we laid out here, but that's just a start. Think more about the defaults you offer, plus what you can then expose to the theme customizer.

If you wanted to, you could create a complimentary extension to go along with your theme. Remember, we don't allow JS in themes, but there may be sometimes when you want to, for example, expose more information to the template context, or perhaps add in an event — in these cases, you'll need to create an extension to go with it.

Oh, and don't forget to commit your changes to Git!

One final thing: I thought about including a list of best practices; however, we have a list of them covering the various sections in our documentation.