BigCommerce Wishlist
Easy-to-use Wishlist functionality for BigCommerce themes.
This package provides simple JavaScript methods to:
- Check if a product has already been added to a wishlist.
- Add or remove a product from a wishlist.
- Create, update or remove wishlists.
- Get wishlists details.
- Event listeners for changes on wishlists.
In this document:
Info
- URL: https://github.com/brandlabs/bigcommerce-wishlist
- Platform: BigCommerce
Setup
Install package
Install the package as a dependency of your Stencil theme:
npm install brandlabs-bigcommerce-wishlist --save-dev
Required template
The post install script will create a Handlebars template file named json-this.html
in your Stencil theme at templates/components/custom
folder.
This template file is required for the package to work
Use it in theme
- Import the package and you'll get a
WishlistManager
instance. - Provide
context
to theinit
method. (optional) - Use the available methods.
; { // ... this; } async { // Initialize await wishlistManager; const productId = ; // Check if product belongs to one of the customer's wishlists const isAddedToWishlist = await wishlistManager; if isAddedToWishlist ; else ; }
Try it yourself
To quickly try it from browser, simply add these two lines to assets/js/theme/global.js
:
// Append this line to the imports:; { // Add this line so you can use the wishlistManager as "wm" from console: windowwm = wishlistManager; }
Perform login as a customer into the store, and the wm
(wishlist manager) functionality will be available from Dev Tools console to create, update and remove wishlists, add and remove products from wishlists, etc.
Use console.log
as argument to Promise's then
, to see the results:
wm
ECMAScript 6
The source code from this package is written using ES6 features.
Default Webpack configuration from Cornerstone theme uses Babel to transpile ES6 code within assets/js
folder. It does not transpile ES6 code from node_modules
.
To get the transpiled code for this package in your theme bundle, there are three options.
Choose one of them:
- Import the transpiled version from
dist
folder:
;
- Include
brandlabs-bigcommerce-wishlist
in the paths to transpile. Atwebpack.common.js
, update theinclude
regular expression:
moduleexports = module: rules: test: /\.js$/ include: //
- Use an alias for the
dist
version. Atwebpack.common.js
, add one entry for the wishlist package:
moduleexports = resolve: alias: 'brandlabs-bigcommerce-wishlist': path
API Reference
The main functionality mimics the BigCommerce Wishlist API:
Most methods are asynchronous, returning a Promise which will resolve into the expected result, or reject upon an error.
METHODS
- getAllWishlists - Get all wishlists for the current customer.
- getWishlist - Get specified wishlist details for the current customer.
- createWishlist - Create a new wishlist for the current customer.
- deleteWishlist - Remove a wishlist from the current customer.
- updateWishlist - Update a wishlist for the current customer.
- addWishlistItem - Add a product to a customer wishlist.
- deleteWishlistItem - Remove a product from a customer wishlist.
- getAllWishlistsDetails - Get all wishlists for the current customer, including the list of items for each one of them.
- isProductInAnyWishlist - Verify if a specific product belongs to any of the customer's wishlists.
- on - Register an event listener.
- off - Remove an event listener.
- init - Initialize the instance with optional context data.
PROPERTIES
- useCache - Whether to use the cache or not.
- cacheDuration - Time to expire cached data, in minutes.
- urls - Paths to the remote AJAX requests.
- events - Event names.
- wishlists - Wishlists data.
⚠️ Note: In the examples below, we provide both one then
callback and one event listener, to illustrate how to use them. It is not necessary to use both in real applications. Please choose the option which fits better to your use case.
# async getAllWishlists(forceFetch = false)
Get all wishlists for the current customer.
Arguments:
{boolean} forceFetch
- True to ignore the cache, False otherwise. Defaults tofalse
.
Returns:
{Promise<array>} wishlists
Usage:
Each object in the returned array shall contain the following properties:
id
name
is_public
num_items
token
view_url
edit_url
delete_url
share_url
add_url
wm;
# async getWishlist(wishlistid, forceFetch = false)
Get specified wishlist details for the current customer.
Arguments:
{integer} wishlistid
- Wishlist ID.{boolean} forceFetch
- True to ignore the cache, False otherwise. Defaults tofalse
.
Returns:
{Promise<object>} wishlist
Usage:
The returned object shall contain the following properties:
id
name
is_public
is_editable
items
token
share_url
Note that the properties returned from getWishlist
differ from the properties returned from getAllWishlists
.
This is not a "feature" of the package. This reflects what is actually returned from BigCommerce server.
While the wishlist objects returned from getAllWishlists
provide the number of items as num_items
, the object returned from getWishlist
contains an items
array with the actual items.
wm;
# async createWishlist({ name, is_public, product_id })
Create a new wishlist for the current customer.
Arguments:
{Object} params
- The wishlist attributes.{string} name
- Wishlist name (required).{boolean} is_public
- Indicates if wishlist is public. Defaults tofalse
.{integer} product_id
- ID of a product to be added to the wishlist (optional).
Returns:
{Promise<object>} wishlist
Fires:
createWishlist({ wishlist })
event
Usage:
The returned wishlist object varies:
- If no
product_id
is provided, then it will contain the same properties returned bygetAllWishlists
- If a
product_id
is provided, then it will contain the same properties returned bygetWishlist
The createWishlist
event is triggered. The event handler function is called immediately before the Promise is resolved.
wm; wm;
# async deleteWishlist(wishlistid)
Remove a wishlist from the current customer.
Arguments:
{integer} wishlistid
- Wishlist ID.
Returns:
{Promise<undefined>}
Fires:
deleteWishlist({ wishlistid })
event
Usage:
The deleteWishlist
event is triggered. The event handler function is called immediately before the Promise is resolved.
wm; wm;
# async updateWishlist(wishlistid, { name, is_public })
Update a wishlist for the current customer.
Arguments:
{integer} wishlistid
- Wishlist ID.{Object} params
- The wishlist attributes.{string} name
- Wishlist name (required).{boolean} is_public
- Indicates if wishlist is public (required).
Returns:
{Promise<object>} wishlist
Fires:
updateWishlist({ wishlist })
event
Usage:
Both arguments (name
and is_public
) will always be updated. Even if you want to change only one of them, and keep the other, you need to provide values for both name
and is_public
. Otherwise, the name
will be set to an empty string, and is_public
will be set to false.
The returned wishlist object contains the same properties returned in getAllWishlists
The updateWishlist
event is triggered. The event handler function is called immediately before the Promise is resolved.
wm; wm;
# async addWishlistItem(wishlistid, product_id)
Add a product to a customer wishlist.
Arguments:
{integer} wishlistid
- Wishlist ID.{integer} product_id
- ID of a product to be added to the wishlist.
Returns:
{Promise<item>}
Fires:
addWishlistItem({ wishlist, item })
event
Usage:
The addWishlistItem
event is triggered. The event handler function is called immediately before the Promise is resolved.
The returned item
object contains several product properties, including product_id
, name
and sku
. It contains also its own id
.
wm; wm;
# async deleteWishlistItem(wishlistid, item_id)
Remove a product from a customer wishlist.
Arguments:
{integer} wishlistid
- Wishlist ID.{integer} item_id
- Wishlist item ID.
Returns:
{Promise<undefined>}
Fires:
deleteWishlistItem({ wishlistid, item_id })
event
Usage:
The deleteWishlistItem
event is triggered. The event handler function is called immediately before the Promise is resolved.
wm; wm;
# async getAllWishlistsDetails()
Get all wishlists for the current customer, including the list of items for each one of them.
Returns:
{Promise<array>} wishlists
Usage:
Each object in the returned array shall contain the following properties:
id
name
is_public
is_editable
items
num_items
token
view_url
edit_url
delete_url
share_url
add_url
wm;
# async isProductInAnyWishlist(product_id)
Verify if a specific product belongs to any of the customer's wishlists.
Returns:
{Promise<boolean>} belongs
Usage:
The Promise resolves to True if the specified product ID belongs to any wishlist, False otherwise.
const product_id = 15; wm;
# on(name, callback)
Register an event listener.
Arguments:
{string} name
- The event name.{Function} callback
- The function to run when the event is triggered.
Usage:
All methods which changes the wishlists trigger events.
See the reference of each method for details on the provided event parameters:
const onCreateWishlist = { console;}; wm;
# off(name, callback)
Remove an event listener.
Arguments:
{string} name
- The event name.{Function} callback
- The function to be removed from listeners.
Usage:
In order to be able to remove an event listener, it is important to have a reference to it.
So, if your code will remove event listeners, it is better to avoid anonymous functions when registering them.
// GOOD EXAMPLE:const onCreateWishlist = { console;}; wm; wm; // AVOID USING ANONYMOUS FUNCTIONS:wm; wm; // Not reliable. Not recommended.
# async init({ wishlists, urls } = {})
Initialize the instance with optional context data.
Arguments:
{Object} context
- Stencil context.{array} wishlists
- Wishlists.{object} urls
- URLs.
Usage:
The call to init
method is not mandatory. It is optional. The context
parameter is also optional.
This is exactly what init
does:
// Use wishlists URLs from context if urls && urlsaccount && urlsaccountwishlists Object; // Cache warming if thisuseCache this; // Initial wishlists fetch, if not available in context if Array this; else await this;
1️⃣ Stencil context usually contains wishlists URL information, at context.urls.account.wishlists
. The init
method will configure the instance to use the context URLs. This usually will make no difference at all, since the configured defaults correspond to the values used by all BigCommerce stores.
2️⃣ Loads data from cache into the instance's wishlists
property.
3️⃣ If a wishlists
array is provided in context
, it will be used as initial source of truth, populating the instance's wishlists
property data. Otherwise, an AJAX call to BigCommerce will be made to retrieve the initial wishlists
data.
Thus, this initial HTTP request to BigCommerce server can be avoided if wishlists
is injected into the context. This can be achieved from the Handlebars page templates in the theme. This is done through a front-matter entry, and the usage of Handlebars inject
helper, like this:
---
customer:
wishlists:
limit:10
---
{{inject "wishlists" customer.wishlists}}
# wm.useCache
-
Type:
boolean
-
Default:
true
-
Details:
From the moment this is set tofalse
, the cache will not be read anymore.
If set totrue
, the cache will be available for reading.
This setting does not affect the write operations to the cache.
// To completely skip reading cache, turn it off before calling init
wm.useCache = false;
wm.init(this.context);
# wm.cacheDuration
-
Type:
integer
-
Default:
60
-
Details:
Time to expire cached data, in minutes.
This does not imply on cache data deletion.
If there is data stored in cache 90 minutes ago, it will be discarded when reading.
In this case, ifcacheDuration
is modified to 120, the next cache read operations will not discard anumore the data which has been stored in cache 90 minutes ago.
// It is recommended to set the preferred value for cacheDuration before calling init
wm.cacheDuration = 360;
wm.init(this.context);
# wm.urls
-
Type:
object
-
Default:
base: windowlocationorigin all: '/wishlist.php' add: '/wishlist.php?action=addwishlist' edit: '/wishlist.php?action=editwishlist' delete: '/wishlist.php?action=deletewishlist' view: '/wishlist.php?action=viewwishlistitems' add_item: '/wishlist.php?action=add' delete_item: '/wishlist.php?action=remove' share: '/wishlist.php?action=sharewishlist'
- Details:
URLs used for the remote AJAX requests.
They can be changed/configured.
// Use a test or proxy domain to receive the requests
wm.urls.base = 'https://example.com';
# wm.events
-
Type:
object
-
Default:
createWishlist: 'createWishlist' deleteWishlist: 'deleteWishlist' updateWishlist: 'updateWishlist' addWishlistItem: 'addWishlistItem' deleteWishlistItem: 'deleteWishlistItem'
- Details:
Instead of using hard-coded strings, it is possible to refer the events from this object property.
The event names can also be changed/configured.
wm.events.createWishlist = 'wishlistCreated';
wm.events.deleteWishlist = 'wishlistDeleted';
wm.on('wishlistCreated', () => 'A wishlist has been created.');
wm.on(wm.events.deleteWishlist, () => 'A wishlist has been deleted.');
wm.on(wm.events.updateWishlist, () => 'A wishlist has been updated.');
# wm.wishlists
-
Type:
object
-
Details:
Contains all wishlist data read from cache, or from remote requests, or changed via any of the method calls.
It always contains the most complete and up-to-date wishlists data the WishlistManager instance is aware of.
It is a dictonary keyed by the wishlist ID.
async foo() {
await wm.getWishlist(5);
const productIds = wm.wishlists[5].items.map(item => item.product_id);
}
async bar() {
await wm.getAllWishlistsDetails();
console.log(wm.wishlists); // ALL data is in here
}
The wishlists
property is suitable to be used in a reactive context.
Here is a Vue JS 3 example:
wmwishlists = Vue;wm; Vue;
With this setup, any change done using the "create", "update", "delete", "add item" or "remove item" is automatically reflected in the HTML table, without any then
callback, any event listener or any other kind of post-processing.
Maintenance
For development of this package, we use:
- ESLint for linting JS code
- Jest for testing
- Webpack for bundling
Lint
To lint the scripts, run npm run lint
Test
To perform the tests, run npm run test
Bundle
To generate the dist
folder and build bundle assets, run npm run build
License
This project is licensed under the MIT License - see the LICENSE file for details