Template Files
Templates Directory
Custom Templates
Customize Stencil Checkout
Handlebars Syntax and Helpers
Handlebars.js
Handlebars Helpers
Stencil Object Model
Stencil Objects

stencil-utils API Reference

These functions help you set up asynchronous requests to modify the customer’s cart or storefront view. By using this abstraction library, you can gain more-granular control over themes’ presentation.

Example Code

Examples on this page are from Stencil’s Cornerstone base theme. The base path for all listed examples is: /cornerstone/assets/js/theme/.

API [api.js]

The api.getPage() function allows you to add Ajax functionality to your themes.

getPage Signature

The following statement passes url and options arguments to the api.getPage() function:

utils.api.getPage(url, options, callback)

Argument Type Description/Usage
url String URL to which you want to send a request (for example: localhost:4000/cart.php)
options Object Can contain template, FormData (for POST methods), params (for GET methods), and/or config. The template option allows you to select a particular template, or an array of templates, for rendering one page. Each value must correspond to a file present in the theme's templates/components/ subdirectory. The `config` option can be used to pass extra resources, corresponding to attributes that are valid in a page's front matter, as an object.
callback Function Asynchronous function call to handle the results

The config argument works like front matter: it encapsulates JSON. For a usage example of config, see the Remote API Example.

getPage Example

In the following example (from common/faceted-search.js), api.getPage() is called to help execute an updateView() function:

getPage Example
updateView() {
        $(this.options.blockerSelector).show();

        api.getPage(urlUtils.getUrl(), this.requestOptions, (err, content) => {
            $(this.options.blockerSelector).hide();

            if (err) {
                throw new Error(err);
            }

            // Refresh view with new content
            this.refreshView(content);
        });
    }

Cart API

The following functions allow your theme to work with cart contents in customized ways.

itemAdd Signature

The itemAddfunction allows your code to add an item to the cart, with options:

utils.api.cart.itemAdd(FormData, callback)

Argument Type Description/Usage
formData FormData object Contains all details about the added item and its product options
callback Function Asynchronous function call to handle the results

itemAdd Example

itemAdd is called at the head of the following example (from common/product-details.js) to populate the cart:

// Add item to cart
        utils.api.cart.itemAdd(new FormData(form), (err, response) => {
            const errorMessage = err || response.data.error;

            $addToCartBtn
                .val(originalBtnVal)
                .prop('disabled', false);

            this.$overlay.hide();

            // Guard statement
            if (errorMessage) {
                // Strip the HTML from the error message
                const tmp = document.createElement('DIV');
                tmp.innerHTML = errorMessage;

                return alert(tmp.textContent || tmp.innerText);
            }

            // Open preview modal and update content
            if (this.previewModal) {
                this.previewModal.open();

                this.updateCartContent(this.previewModal, response.data.cart_item.hash);
            } else {
                this.$overlay.show();
                // if no modal, redirect to the cart page
                this.redirectTo(response.data.cart_item.cart_url || this.context.urls.cart);
            }
        }); 

itemUpdate Signature

The itemUpdate function allows your code to update a specified cart item’s quantity:

utils.api.cart.itemUpdate(itemId, qty, callback)

Argument Type Description/Usage
itemId String The item’s ID
qty Integer The item’s quantity in the cart
callback Function Asynchronous function call to handle the results

itemUpdate Example

In the following example (from cart.js), itemUpdate is called just before the final if/else test for an empty cart:

				cartUpdate($target) {
        const itemId = $target.data('cartItemid');
        const $el = $(`#qty-${itemId}`);
        const oldQty = parseInt($el.val(), 10);
        const maxQty = parseInt($el.data('quantityMax'), 10);
        const minQty = parseInt($el.data('quantityMin'), 10);
        const minError = $el.data('quantityMinError');
        const maxError = $el.data('quantityMaxError');
        const newQty = $target.data('action') === 'inc' ? oldQty + 1 : oldQty - 1;

        // Does not quality for min/max quantity
        if (newQty < minQty) {
            return swal({
                text: minError,
                type: 'error',
            });
        } else if (maxQty > 0 && newQty > maxQty) {
            return swal({
                text: maxError,
                type: 'error',
            });
        }

        this.$overlay.show();

        utils.api.cart.itemUpdate(itemId, newQty, (err, response) => {
            this.$overlay.hide();

            if (response.data.status === 'succeed') {
                // if the quantity is changed "1" from "0", we have to remove the row.
                const remove = (newQty === 0);

                this.refreshContent(remove);
            } else {
                $el.val(oldQty);
                swal({
                    text: response.data.errors.join('\n'),
                    type: 'error',
                });
            }
        });
    } 

itemRemove Signature

The itemRemove function allows your code to remove items from the cart:

utils.api.cart.itemRemove(itemId, callback)

Argument Type Description/Usage
itemId String The item’s ID
callback Function Asynchronous function call to handle the results

itemRemove Example

In the following example (from cart.js), itemRemove is called before the if/else test:

				cartRemoveItem(itemId) {
        this.$overlay.show();
        utils.api.cart.itemRemove(itemId, (err, response) => {
            if (response.data.status === 'succeed') {
                this.refreshContent(true);
            } else {
                alert(response.data.errors.join('\n'));
            }
        });
    } 

update Signature

The update function allows your code to update the set of items in the cart:

utils.api.cart.update(itemId, qty, callback)

Argument Type Description/Usage
items Array The items in the cart
callback Function Asynchronous function call to handle the results

update Example

The following example shows a call to update within the itemUpdate function:

/**
    itemUpdate(itemId, qty, callback) {
        let callbackArg = callback;
        let items;

        if (Array.isArray(itemId) && typeof qty === 'function') {
            callbackArg = qty;
            items = itemId;
        } else {
            items = [
                {
                    id: itemId,
                    quantity: qty,
                },
            ];
        }

        this.update(items, (err, response) => {
            const emitData = {
                items,
                err,
                response,
            };

            Hooks.emit('cart-item-update-remote', emitData);
            callbackArg(err, response);
        });
    } 

getItemGiftWrappingOptions Signature

The getItemGiftWrappingOptions function allows your code to retrieve gift-wrapping options for the current cart item, in customized ways:

utils.api.cart.getItemGiftWrappingOptions(itemId, callback)

Argument Type Description/Usage
itemId String The cart item
callback Function Asynchronous function call to handle the results

getItemGiftWrappingOptions Example

The following example (from cart.js) calls getItemGiftWrappingOptions to display gift-wrapping options in a modal:

	bindGiftWrappingEvents() {
        const modal = defaultModal();

        $('[data-item-giftwrap]').on('click', (event) => {
            const itemId = $(event.currentTarget).data('item-giftwrap');
            const options = {
                template: 'cart/modals/gift-wrapping-form',
            };

            event.preventDefault();

            modal.open();

            utils.api.cart.getItemGiftWrappingOptions(itemId, options, (err, response) => {
                modal.updateContent(response.content);

                this.bindGiftWrappingForm();
            });
        });
    }

submitItemGiftWrappingOption Signature

The submitItemGiftWrappingOption function allows your code to handle the customer’s gift-wrapping selection for the current cart item:

utils.api.cart.submitItemGiftWrappingOption(itemId, qty, callback)

Argument Type Description/Usage
itemId String The cart item
callback Function Asynchronous function call to handle the results

submitItemGiftWrappingOption Example

This commented example shows a simple call to submitItemGiftWrappingOption:

/**
     * Submit giftwrapping options
     *
     * @param {String} itemId
     * @param {Function} callback
     */
    submitItemGiftWrappingOption(itemId, qty, callback) {
        this.remoteRequest(`/gift-wrapping/${itemId}`, 'POST', { params }, callback);
    } 

getContent Signature

The getContent function allows your code to display the cart contents in customized ways:

utils.api.cart.getContent(options, callback)

Argument Type Description/Usage
options Object Template containing content and totals children
callback Function Asynchronous function call to handle the results

getContent Examples

The following example from common/product-details.js a call to getContent, set up by a prior call to getCartContent:

    /**
     * Get cart contents
     *
     * @param {String} cartItemHash
     * @param {Function} onComplete
     */
    getCartContent(cartItemHash, onComplete) {
        const options = {
            template: 'cart/preview',
            params: {
                suggest: cartItemHash,
            },
            config: {
                cart: {
                    suggestions: {
                        limit: 4,
                    },
                },
            },
        };

        utils.api.cart.getContent(options, onComplete);
    } 

This example (from cart.js) shows a call to getContent within the refreshContent function:

refreshContent(remove) {
        const $cartItemsRows = $('[data-item-row]', this.$cartContent);
        const $cartPageTitle = $('[data-cart-page-title]');
        const options = {
            template: {
                content: 'cart/content',
                totals: 'cart/totals',
                pageTitle: 'cart/page-title',
                statusMessages: 'cart/status-messages',
            },
        };

        this.$overlay.show();

        // Remove last item from cart? Reload
        if (remove && $cartItemsRows.length === 1) {
            return window.location.reload();
        }

        utils.api.cart.getContent(options, (err, response) => {
            this.$cartContent.html(response.content);
            this.$cartTotals.html(response.totals);
            this.$cartMessages.html(response.statusMessages);

            $cartPageTitle.replaceWith(response.pageTitle);
            this.bindEvents();
            this.$overlay.hide();

            const quantity = $('[data-cart-quantity]', this.$cartContent).data('cart-quantity') || 0;

            $('body').trigger('cart-quantity-update', quantity);
        });
    } 

Here is a final example of a call to getContent, from global/cart-preview.js:

$cart.on('click', (event) => {
        const options = {
            template: 'common/cart-preview',
        };

        // Redirect to full cart page
        //
        // https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent
        // In summary, we recommend looking for the string 'Mobi' anywhere in the User Agent to detect a mobile device.
        if (/Mobi/i.test(navigator.userAgent)) {
            return event.stopPropagation();
        }

        event.preventDefault();

        $cartDropdown
            .addClass(loadingClass)
            .html($cartLoading);
        $cartLoading
            .show();

        utils.api.cart.getContent(options, (err, response) => {
            $cartDropdown
                .removeClass(loadingClass)
                .html(response);
            $cartLoading
                .hide();
        });
    });

getShippingQuotes Signature

The getShippingQuotes function allows your code to retrieve shipping-cost quotes for the cart’s contents. It returns shippingQuote objects that contain IDs. You must follow getShippingQuotes by calling submitShippingQuote on a quoteId:

utils.api.cart.getShippingQuotes(params, renderWith, callback)

Argument Type Description/Usage
params Object Contains country_id, state_id, and zip_code
template String/Array/Object The template to use for rendering
callback Function Asynchronous function call to handle the results

getShippingQuotes and submitShippingQuote Example

The following example from cart/shipping-estimator.js shows calls to both getShippingQuotes and submitShippingQuote:

getShippingQuotes and SubmitShippingQuote Example
cart/shipping-estimator.js
bindEstimatorEvents() {
        const $estimatorContainer = $('.shipping-estimator');
        const $estimatorForm = $('.estimator-form');

        $estimatorForm.on('submit', (event) => {
            const params = {
                country_id: $('[name="shipping-country"]', $estimatorForm).val(),
                state_id: $('[name="shipping-state"]', $estimatorForm).val(),
                city: $('[name="shipping-city"]', $estimatorForm).val(),
                zip_code: $('[name="shipping-zip"]', $estimatorForm).val(),
            };

            event.preventDefault();

            utils.api.cart.getShippingQuotes(params, 'cart/shipping-quotes', (err, response) => {
                $('.shipping-quotes').html(response.content);

                // bind the select button
                $('.select-shipping-quote').on('click', (clickEvent) => {
                    const quoteId = $('.shipping-quote:checked').val();

                    clickEvent.preventDefault();

                    utils.api.cart.submitShippingQuote(quoteId, () => {
                        location.reload();
                    });
                });
            });
        }); 
	

submitShippingQuote Signature

The submitShippingQuote function must be called after getShippingQuote, which returns shippingQuote objects that contain IDs. The cart page renders the shipping quotes. When the user selects one of the quotes, this function sends that quoteId to the backend:

utils.api.cart.submitShippingQuote(quoteId, callback)

Argument Type Description/Usage
quoteId Number ID for a shipping quote returned by getShippingQuotes
callback Function Asynchronous function call to handle the results

(For sample code, see getShippingQuotes and submitShippingQuote examples above.)

applyCode Signature

The applyCode function applies a coupon code or gift certificate to the cart:

utils.api.cart.applyCode(code, callback)

Argument Type Description/Usage
code String Alphanumeric representation of the coupon or gift-certificate code
callback Function Asynchronous function call to handle the results

In the following example from cart.js, applyCode is called before the final if/else test to apply a coupon code:

applyCode
cart.js
bindPromoCodeEvents() {
        const $couponContainer = $('.coupon-code');
        const $couponForm = $('.coupon-form');
        const $codeInput = $('[name="couponcode"]', $couponForm);

        $('.coupon-code-add').on('click', (event) => {
            event.preventDefault();

            $(event.currentTarget).hide();
            $couponContainer.show();
            $('.coupon-code-cancel').show();
            $codeInput.focus();
        });

        $('.coupon-code-cancel').on('click', (event) => {
            event.preventDefault();

            $couponContainer.hide();
            $('.coupon-code-cancel').hide();
            $('.coupon-code-add').show();
        });

        $couponForm.on('submit', (event) => {
            const code = $codeInput.val();

            event.preventDefault();

            // Empty code
            if (!code) {
                return alert($codeInput.data('error'));
            }

            utils.api.cart.applyCode(code, (err, response) => {
                if (response.data.status === 'success') {
                    this.refreshContent();
                } else {
                    alert(response.data.errors.join('\n'));
                }
            });
        });
    }

Cookie Resource

This resource allows you to override a browser’s default alert box for cookie notifications.

Argument Description/Usage
privacyMessage Merchant-defined message informing customers of storefront’s cookie usage (e.g., to comply with E.U. notification requirement)

Cookie Example:

The following example (fromglobal/cookieNotification.js) shows a call to utils.hooks.on('cookie-privacy-notification', (event, privacyMessage) to help comply with European Union privacy requirements:

Cookie Example
global/cookieNotification.js
/**
 * European websites must notify users of cookies to comply with European Union law.
 * This will alert shoppers that this website uses cookies.
 */
export default function () {
  
    /*
    // Here you can override the default browser alert box by hooking to the 'cookie-privacy-notification' hook.
    utils.hooks.on('cookie-privacy-notification', (event, privacyMessage) => {
        // You can make your own custom modal or alert box appear in your theme using the privacyMessage provided
        myCustomAlert(privacyMessage);

        // Call event.preventDefault() to prevent the default browser alert from occurring in stencil-utils
        event.preventDefault();
    });
    */

    utils.hooks.on('cookie-privacy-notification', (event) => {
        event.preventDefault();

        const $privacyDialog = $('.cookieMessage');
        $privacyDialog.show();

        $('body').on('click', '[data-privacy-accept]', () => {
            utils.hooks.emit('cookie-privacy-accepted');
            $privacyDialog.hide();
        });
    });
} 

Countries Resources

These functions allow your theme or app to retrieve standardized country names, by numeric ID or by string.

getById Signature

The getById function retrieves standardized country names by numeric ID:

utils.api.countries.getById(countryId, callback)

Argument Type Description/Usage
countryId Number Country code
callback Function Asynchronous function call to handle the results

The following example a call to getById, followed by a call to the getByName function (described below):

getById Example
/*   
	*Get country data by id wrapper
     * @param {Number} id
     * @param {Function} callback
*/

    getById(id, callback) {
        const url = this.endpoint + id;

        this.remoteRequest(url, 'GET', {}, callback);
    }

/*
     * Get country data by country name
     * @param name
     * @param callback
*/
    getByName(name, callback) {
        const url = this.endpoint + name;

        this.remoteRequest(url, 'GET', {}, callback);
    }
}

getByName Signature

The getByName function retrieves states by country name, and returns an array of states that can be used in the callback:

utils.api.countries.getByName(countryName, callback)

Argument Type Description/Usage
countryName String Country name
callback Function Asynchronous function call to handle the results

In the following example from common/state-country.js, getByName is called after the initial if test:

getByName Example
common/state-country.js
$('select[data-field-type="Country"]').on('change', (event) => {
        const countryName = $(event.currentTarget).val();

        if (countryName === '') {
            return;
        }

        utils.api.country.getByName(countryName, (err, response) => {
            if (err) {
                alert(context.state_error);

                return callback(err);
            }

            const $currentInput = $('[data-field-type="State"]');

            if (!_.isEmpty(response.data.states)) {
                // The element may have been replaced with a select, reselect it
                const $selectElement = makeStateRequired($currentInput, context);

                addOptions(response.data, $selectElement, options);
                callback(null, $selectElement);
            } else {
                const newElement = makeStateOptional($currentInput, context);

                callback(null, newElement);
            }
        });
    }); 

Product Attributes Resource

The optionChange function is fired when the customer selects a product option for the current cart item (for example, changing a shirt’s color from a default “yellow” to “green”):

optionChange Signature

utils.api.productAttributes.optionChange(productId, params, callback)

Argument Type Description/Usage
params Object Contains a collection of IDs that map to product properties (color, size, etc.)
productId Number ID for this product
callback Function Asynchronous function call to handle the results

optionChange Examples

In this example (from common/product-details.js), optionChange is called to update options in a Quick View modal:

optionChange Example #1
common/product-details.js
// Update product attributes. If we're in quick view and the product has options, then also update the initial view in case items are oos
        if (_.isEmpty(productAttributesData) && hasOptions) {
            const $productId = $('[name="product_id"]', $form).val();

            utils.api.productAttributes.optionChange($productId, $form.serialize(), (err, response) => {
                const attributesData = response.data || {};

                this.updateProductAttributes(attributesData);
                this.updateView(attributesData);
            });
        } else {
            this.updateProductAttributes(productAttributesData);
        } 

In this example from cart.js, optionChange is called before the final if test:

optionChange Example #2
cart.js
cartEditOptions(itemId) {
        const modal = defaultModal();
        const options = {
            template: 'cart/modals/configure-product',
        };

        modal.open();

        utils.api.productAttributes.configureInCart(itemId, options, (err, response) => {
            modal.updateContent(response.content);

            this.bindGiftWrappingForm();
        });

        utils.hooks.on('product-option-change', (event, option) => {
            const $changedOption = $(option);
            const $form = $changedOption.parents('form');
            const $submit = $('input.button', $form);
            const $messageBox = $('.alertMessageBox');
            const item = $('[name="item_id"]', $form).attr('value');

            utils.api.productAttributes.optionChange(item, $form.serialize(), (err, result) => {
                const data = result.data || {};

                if (err) {
                    alert(err);
                    return false;
                }

Product Resource

The product.getById function allows your code to retrieve, and to present, detailed product information by product ID.

getById Signature

utils.api.product.getById(productId, params, callback)

Argument Type Description/Usage
productId Number ID for this product
params Object Contains request options and/or presentation template
callback Function Asynchronous function call to handle the results

The following example (from global/quick-view.js) calls product.getById to populate the Quick View modal:

getById Example
global/quick-view.js
	$('body').on('click', '.quickview', (event) => {
        event.preventDefault();

        const productId = $(event.currentTarget).data('product-id');

        modal.open({ size: 'large' });

        utils.api.product.getById(productId, { template: 'products/quick-view' }, (err, response) => {
            modal.updateContent(response);

            modal.$content.find('.productView').addClass('productView--quickView');

            return new ProductDetails(modal.$content.find('.quickView'), context);
        });
    }); 

Search Resource

The search function allows you to present a customized user interface for search results.

search Signature

utils.api.search.search(query, params, callback)

Argument Type Description/Usage
query String Contains the customer’s search query
params Object Contains request options and/or presentation template
callback Function Asynchronous function call to handle the results