This topic covers the following standards and supported browser versions.
European Cookie Law requires websites to notify
customers that cookies are being used and how. The SiteGenesis application
uses an optional content asset, called cookie_hint,
to
contain this notice.
If this asset is... | Then... |
---|---|
Missing or offline | No notice is given. The cookies are set as they always have been. This approach is used in the USA, for example. |
Present and online* | The cookie_hint content appears. Clicking I
ACCEPT sets the cookies and causes the popup to not
appear again. |
SGJC officially supports the following browsers, and one version earlier.
Desktop
Mobile
See Business Manager User Interface.
Supported Browsers Desktop (supporting the latest browser version):
Commerce Cloud Store supports the latest version of the browsers listed above, as well as one version earlier. Refer to documentation for more details. The plus(+) sign signifies support of both major and minor browser releases following the listed browser version. End of Support for Opera As of January 1, 2017, Commerce Cloud will no longer support Opera due to infrequent client use. We continue to evaluate browser usage throughout 2018, and if we see changes with browser adoption, we consider supporting it. Implications of These Changes To ensure optimal performance, we encourage all clients to upgrade to a supported browser prior to January 1, 2017. Commerce Cloud continues to test and fix bugs in all supported browsers. Customers are welcome to use any browser they want, but there can be noticeable performance issues with unsupported browsers. If you encounter any issues with a supported browser, open a ticket with Commerce Cloud Support.
For more information, see http://www.w3schools.com/html/html5_form_input_types.asp.
The Web Content Accessibility Guidelines (WCAG) provide a single shared standard for web content accessibility that meets the needs of individuals, organizations, and governments internationally. WCAG documents explain how to make web content more accessible to people with disabilities. See http://www.w3.org/WAI/intro/wcag.
The SGJC application was changed to better conform to the WCAG guidelines. The list of changes shown here is intended to provide examples of how you can make your storefront application more accessible:
The WCAG guidelines followed were:
The title-related corrections to SiteGenesis use technique H33 (http://www.w3.org/TR/2014/NOTE-WCAG20-TECHS-20140916/H33). The link text is supplemented with the title attribute to add more context, making it easier for people with disabilities to determine the purpose of the link.
Commerce Cloud enables merchants to track personal information about their shoppers, and use this information to improve their shoppers’ overall shopping experience. Some merchants can decide to provide their shoppers a way to deny or grant their consent to such tracking.
This topic describes a sample implementation for consent tracking in SGJC. The purpose of this sample implementation is to suggest how you can implement this capability on a storefront adapted from SGJC. This sample implementation is meant to be informative, but not prescriptive.
This sample implementation uses:
More details about the sample implementation are provided later in this document.
Content Asset for the Consent Request Message
To display a consent message to the shopper, the sample implementation
uses a content asset whose internal ID is consent_tracking_hint
.
This content asset contains meaningless text, which you can replace with your own
message.
Site-Specific Preference (Tracking)
The Tracking site preference determines the default tracking behavior for a site. If set to Opt-in, personal information is not tracked by default for all shoppers visiting the site; otherwise, personal information is tracked.
To set this preference, select Merchant Tools > site > Site Preferences > Privacy.
The sample implementation assumes that the Tracking preference is set to Opt-In.
Session Tracking Flag
The sample implementation presents a consent request message to the shopper, who can choose to allow tracking. If the shopper allows tracking, the sample implementation enables tracking during the shopper’s session.
You can enable tracking on a session by calling the following method:dw.system.Session.setTrackingAllowed(boolean)
-- If you call
this method with a value of true
, the method enables tracking
for the current session; false
, disables tracking.You can determine the current value of the tracking flag by calling the following method:
dw.system.Session.isTrackingAllowed()
-- This method returns
the current state of the session’s tracking flag (true
indicates that tracking is enabled; false
, disabled).Extra Implementation Details
The sample implementation uses a server-side endpoint to set the session tracking flag based on the value of a URL parameter. The shopper’s choice to grant or deny consent determines the value of this parameter.
The server-side endpoint is named
Account-consentTracking
:
function consentTracking() {
var consent = request.httpParameterMap.consentTracking.value == 'true';
session.custom.consentTracking = consent;
session.setTrackingAllowed(consent);
}
The
result of the shopper’s decision is stored in the server-side variable
session.custom.consentTracking
. It is important to communicate
the state of this variable with the client-side code running on your storefront, so
the sample implementation places this information in a global location that is
accessible to all SGJC-based storefront pages
(footer_UI.isml
).
The client-side implementation can check
the state of this variable and store it in a client-side variable
(consent
). The client-side implementation can then use the
value of the variable to determine whether to display the consent request message to
the shopper.
Several other changes to the client side complete the sample implementation.
The following properties are added to the
‘resources
’ object in the Resource.ds
file:
TRACKING_CONSENT: Resource.msg('global.tracking_consent', 'locale', null),
TRACKING_NO_CONSENT: Resource.msg('global.tracking_no_consent', 'locale', null),
The
following properties are added to the ‘urls
’ object in the
Resource.ds
file:
consentTracking: URLUtils.url('Page-Show', 'cid', 'consent_tracking_hint').toString(),
consentTrackingSetSession: URLUtils.url('Account-ConsentTracking').toString(),
The
client-side variable (consent
) is set before
is included in the
app.js
footer_UI.isml
template:
<script>var consent = ${session.custom.consentUser};</script>
<script src="${URLUtils.staticURL('/js/app.js')}"></script>
A
consentTracking
module is required in app.js
:
consentTracking = require('./consentTracking);
...
consentTracking.init();
...
$('.consent-tracking-policy').on('click', function (e) {
e.preventDefault();
consentTracking.show();
});
Lastly,
the consentTracking
module is
implemented:
function getConsent() {
dialog.open({
url: Urls.consentTracking,
options: {
closeOnEscape: false,
dialogClass: 'no-close',
buttons: [{
text: Resources.TRACKING_CONSENT,
click: function () {
$(this).dialog('close');
$.ajax({
type: 'GET',
url: util.appendParamToURL(Urls.consentTrackingSetSession, 'consentTracking', true),
success: function () {
showPrivacyDialog();
},
error: function () {
showPrivacyDialog();
}
})
}
}, {
text: Resources.TRACKING_NO_CONSENT,
click: function () {
$(this).dialog('close');
$.ajax({
type: 'GET',
url: util.appendParamToURL(Urls.consentTrackingSetSession, 'consentTracking', false),
success: function () {
showPrivacyDialog();
},
error: function () {
showPrivacyDialog();
}
})
}
}]
}
});
}
function enablePrivacyCookies() {
if (document.cookie.indexOf('dw=1') < 0) {
document.cookie = 'dw=1; path=/';
}
if (document.cookie.indexOf('dw_cookies_accepted') < 0) {
document.cookie = 'dw_cookies_accepted=1; path=/';
}
}
function showPrivacyDialog(){
if (SitePreferences.COOKIE_HINT === true && document.cookie.indexOf('dw_cookies_accepted') < 0) {
// check for privacy policy page
if ($('.privacy-policy').length === 0) {
dialog.open({
url: Urls.cookieHint,
options: {
closeOnEscape: false,
dialogClass: 'no-close',
buttons: [{
text: Resources.I_AGREE,
click: function () {
$(this).dialog('close');
enablePrivacyCookies();
}
}]
}
});
}
} else {
// Otherwise, we don't need to show the asset, just enable the cookies
enablePrivacyCookies();
}
}
var consentTracking = {
init: function () {
if (consent == null && SitePreferences.CONSENT_TRACKING_HINT) { // eslint-disable-line no-undef
getConsent();
}
if (consent != null && SitePreferences.CONSENT_TRACKING_HINT){ // eslint-disable-line no-undef
showPrivacyDialog();
}
},
show: function () {
getConsent();
}
};
module.exports = consentTracking;
When you implement your SGJC-based storefront, consider providing your shoppers with a mechanism to download their data.
Registered users see a Download my data button on the My Account page. When a shopper clicks this button, SGJC downloads a JSON file to the shopper's browser with the following information:
The JSON file illustrates the type of information to provide to your shoppers. Your business can provide different data in a different format.
Sample JSON file
This sample file shows the type of information you can provide to the shopper.
{
"profile": {
"birthday": "1988-10-21T00:00:00.000Z",
"companyName": "",
"customerNo": "D00000001",
"email": "[email protected]",
"fax": "",
"firstName": "Test1",
"gender": "Female",
"jobTitle": "",
"lastLoginTime": "2018-02-14T20:07:31.074Z",
"lastName": "Doe",
"lastVisitTime": "2018-02-14T20:07:31.074Z",
"phoneBusiness": "",
"phoneHome": "",
"phoneMobile": "",
"preferredLocale": "",
"previousLoginTime": "2015-05-18T20:43:17.000Z",
"previousVisitTime": "2015-05-18T20:43:17.000Z",
"salutation": "",
"secondName": "",
"suffix": "",
"taxID": null,
"taxIDMasked": null,
"taxIDType": null,
"title": "",
"male": false,
"female": true,
"nextBirthday": "2018-10-21T00:00:00.000Z"
},
"addressbook": [
{
"address1": "104 Presidential Way",
"address2": null,
"city": "Woburn",
"companyName": null,
"countryCode": "us",
"firstName": "Test1",
"fullName": "Test1 User1",
"id": "Home",
"jobTitle": null,
"lastName": "User1",
"phone": "781-555-1212",
"postalCode": "01801",
"postBox": null,
"salutation": null,
"secondName": null,
"stateCode": "MA",
"suffix": null,
"suite": null,
"title": null
},
{
"address1": "91 Middlesex Tpke",
"address2": null,
"city": "Burlington",
"companyName": null,
"countryCode": "us",
"firstName": "Jane",
"fullName": "Jane Doe",
"id": "Work",
"jobTitle": null,
"lastName": "Doe",
"phone": "781-555-1212",
"postalCode": "01803",
"postBox": null,
"salutation": null,
"secondName": null,
"stateCode": "MA",
"suffix": null,
"suite": null,
"title": null
}
],
"wallet": [],
"orders": [],
"productList": {
"whishlists": [],
"giftregistries": [],
"shoppinglists": []
},
"thirdpartydata": {}
}
Implementation Details
This example conditionally provides a Download my
data button in the accountoverview.isml
template.
<isif condition="${pdict.downloadAvailable}">
<a class="profile-data-download button"
href="${URLUtils.url('Account-DataDownload')}"> ${Resource.msg('account.landing.databutton','account',null)}</a>
</isif>
When the user clicks the button, the
Account-DataDownload
controller is called. The
Account.js
controller file applies the following guard to
the datadownload()
function, exporting it as
DataDownload
.
/** returns customer data in json format.
* @see {@link module:controllers/Account~datadownload} */
exports.DataDownload = guard.ensure(['get', 'https', 'loggedIn'], datadownload);
The body of the datadownload()
function is implemented in
Account.js
as follows.
/**
* Allows a logged in user to download the data from their profile in a json file.
*/
function datadownload() {
var profile = customer.profile;
var profileDataHelper = require('~/cartridge/scripts/profileDataHelper');
let response = require('~/cartridge/scripts/util/Response');
var site = require('dw/system/Site');
var fileName = site.current.name + '_' + profile.firstName + '_' + profile.lastName + '.json';
response.renderData(profileDataHelper.getProfileData(profile), fileName);
return;
}
This function relies on the helper script
profileDataHelper.js
, which provides several helper
functions, such as getWallet(profile)
,
getWishlists(ProductListMgr)
, and so on. The helper
script exports
, which
calls the helper functions, constructs the JSON string, and returns the
result to the shopper's browser. getProfileData
exports.getProfileData = function (profile) {
var ProductListMgr = require('dw/customer/ProductListMgr');
var downloadJSONObj = {};
downloadJSONObj.profile = getProfile(profile);
downloadJSONObj.addressbook = getAddressBook(profile);
downloadJSONObj.wallet = getWallet(profile);
downloadJSONObj.orders = getOrders(profile);
downloadJSONObj.productList = {
whishlists: getWishLists(ProductListMgr),
giftregistries: getGiftregistries(ProductListMgr),
shoppinglists: getShoppingLists(ProductListMgr)
};
downloadJSONObj.thirdpartydata = {};
return JSON.stringify(downloadJSONObj, null, 2);
};