- Table of contents
- Getting Started
- Events
- Widget Customization & Settings
- Shop this look
- Facebook Pixel Integration
- Debugging
This package doesn't support internet explorer.
Install the plugin with NPM
npm i @adalong/widget
Then you can import it in your code
import AdalongWidget from '@adalong/widget';
Add the CDN url directly in your HTML code to make it available globally. Ensure to replace [VERSION] with the right version.
<script src="https://cdn.jsdelivr.net/npm/@adalong/widget@[VERSION]/dist/adalongWidget.js"></script>
First, you need a tag in which to put the widget. For example:
<div id="widget"></div>
You can define two different types of media sources: collections & products.
Add the data-products attribute to load the media linked to the provided products.
Add the data-collections attribute to load the media linked to the provided collections.
Those values must be an array of strings referring to respectively the product references and the collection ids.
<div id="widget" data-products='["PRODUCT_REF1", "PRODUCT_REF1", ...]' data-collections='["COLLECTION_ID1", "COLLECTION_ID2", ...]'></div>
In case you don't specify any data-*
attributes, the media would come from the fallback sources defined in the widget configuration.
Then you can instantiate the widget with your API key and settings and load it by giving the CSS selector of the DOM element.
const adalongWidget = new AdalongWidget('token', { id: 'customUniqId' });
await adalongWidget.load('#widget');
console.log(adalongWidget.layout); // carousel, mosaic or wall
Once instantiated, all widgets in the page can also be retrieved using the global object window.adalongWidgetAPI
.
// subscribe on events for all widgets
window.adalongWidgetAPI.widgets.forEach((widget) => widget.onEvent(...))
// find a particular widget from another script in the page
window.adalongWidgetAPI.widgets.find((widget) => widget.id === 'customUniqId')
You can also subscribe to events :
adalongWidget.onEvent('postOpened', (event) => {
console.log(event.post);
// console.log(event.product)
// console.log(event.position)
// console.log(event.direction)
// console.log(event.elapsedSeconds)
});
For example, this would be the type of information you could receive from an event about a post :
export interface IMedia {
id: string;
type: 'image' | 'video' | 'text';
caption: string;
source: 'instagram' | 'twitter';
username?: string;
post: string;
image?: string;
video?: string;
thumbnail?: string;
products?: IProduct[];
// local properties set by the browser
postIndex: number;
}
Available events are 'widgetLoaded', 'widgetLoadingFailed', 'thumbnailLoaded', 'thumbnailUnavailable', 'thumbnailHover', 'thumbnailClicked', 'originalPostOpened', 'postOpened', 'postClosed', 'postNavigation', 'videoPlayed', 'carouselArrowClicked', 'carouselNativeScroll', 'shopThisLook', 'minContentNotReached', 'minContentReached', 'widgetViewed'
For more details about events, please refer to the EventMap interface in ./src/types.ts
A custom event is also emitted when a new widget instance is created in the page.
document.addEventListener('adalongWidgetCreated', ({ detail }) => {
console.log(detail.widget.id);
// Note that at this point the widget instance should not be loaded yet but
// you can now wait for the widgetLoaded event or check if the loaded property is true
if (!detail.widget.loaded) {
detail.widget.onEvent('widgetLoaded', () => {});
}
});
You can now fully customize the widget according to your needs. This includes :
-
Partial customization :
- Arrow design and visibility (mobile & desktop mode),
- All customization available through the AdAlong interface. Those settings & more are also documented as typescript interface in src/types.ts.
-
Global customization :
- Controlling the carousel layout : Control the carousel (the media list) to slide back and forth between medias thanks to a public function.
- Controlling the post viewer : Control the postviewer (the view modal) to slide back and forth between medias thanks to a public function.
All custom settings can be passed during instantiation to override the default settings :
await adalongWidget.load('#widget', {
...customSettings,
});
Some tags have classes starting with "adl-wdgt-" to help styling and customizing. You can also override this prefix by passing a string in the config object when instantiating the widget.
new AdalongWidget('token', {
classPrefix: 'myPrefix',
});
The AdalongWidget class has some public functions that can be called to control the widget with custom code launched from outisde.
public getSlideState(): { canSlideLeft: boolean, canSlideRight: boolean } {
return {
canSlideLeft: this.storeState.getState().canSlideLeft,
canSlideRight: this.storeState.getState().canSlideRight,
}
}
This function will tell you if the carousel is able to slide right or left, thus if there are more images to view in either direction. Then, you can call
public setSlider(dir: 'left' | 'right') {
dispatchEvent(new CustomEvent('adalongWidget_slide', {detail: dir}))
}
To trigger a movement in the carousel in the desired direction (by default new images are overflowing on the right).
The last function is to cycle through the elements in the carousel once their thumbnail has been clicked, and the popup with the details is shown:
public changePost(dir: 'left' | 'right') {
dispatchEvent(new CustomEvent('adalongWidget_changePost', { detail: dir }))
}
the 'left' input will open the previous media, while the 'right' input will open the next.
The click on a "shop this look" link will by default open the product url. This behavior can be overridden by providing a function to the shopThisLookHandler field in the config object.
new AdalongWidget('token', {
shopThisLookHandler: ({ media, product }, targetUrl) => {
const url = new URL(targetUrl);
url.searchParams.set('utm_source', 'source');
url.searchParams.set('utm_medium', 'medium');
window.open(url.href, '_blank');
},
});
You can now fully customize the "shop this look" section according to your needs. This includes :
-
Partial customization :
-
"shop this look" text :
shopThisLookText?: string;
-
"more like this" text :
moreLikeThisText?: string;
-
arrows and background color, including the possibility to hide arrows in carousel mode, desktop and/or mobile :
hideArrows?: boolean;
displayMobileCarouselArrows?: boolean;
-
"shop this look" maximum number of columns to be shown :
shop_this_look_max_columns?: number;
-
"shop this look" custom product buttons (for ex. to add a "Add to cart" or "Add to favorites" button) : See Shop this look custom product buttons
-
all options directly available through the widget editing tool in our app
-
-
Global customization :
- Shop this look : When enabled, the "shop this look" section can be entirely replaced by a piece of code of your own creation.
You can add up to four custom buttons to your products.
This function is called for each product when we have to render and must return an object with react components for rendering the custom buttons. All button events must be handled here following react rules.
Place this function in an object as a parameter of the function AdalongWidget
.
/**
* @param react The react lib used by AdalongWidget
* @param product Current rendered product
* @param media Current opened media
*/
getCustomProductButtons: (react, product, media) => {
const addToCart = () =>
react.createElement(
'button',
{
onClick: () => handleAddToCart(),
},
'🛒'
);
const addToFavorites = () =>
react.createElement(
'button',
{
// ... same here
},
'♡'
);
return {
topRight: addToCart,
// each position is optional
bottomRight: addToFavorites,
};
},
You can use four keys to position your custom buttons on the product image : topRight
, bottomRight
, topLeft
, bottomLeft
.
If you want to place two buttons next to each other on the product image, you can use react fragments to create a single element :
const twoButtons = () =>
react.createElement(
react.Fragment,
null,
react.createElement(
'button',
{
onClick: () => handleAddToCart(),
},
'🛒'
),
react.createElement(
'button',
{
onClick: () => handleAddToFavorites(),
},
'❤️'
)
);
If you do not want to use the standard "Shop This Look" design, you can entirely customize this section to your needs, thanks to a rendering function called displayCustomShopThisLook
.
In this function, you'll insert your piece of react or your react component as well as your logic in order to display it in place of the standard "Shop This Look". This function gives you the possibility to get all products-related info in order to map on it.
Here is a very simple example of the use of this function, by mapping on the products :
/**
* @param react The react lib used by AdalongWidget
* @param products An array containing all related products
* @param media Current opened media
* @param isMobile If the widget is viewed in desktop mode (false) or mobile mode (true)
*/
displayCustomShopThisLook: ({ react, products, media, isMobile, context }) => {
const { createElement } = react;
// Optional : Add the "Shop This Look" event tracking function
const handleProductClick = (product, e) => {
if (media) {
context.triggerEvent('shopThisLook', {
post: media,
originalEvent: e,
product: product.id,
});
}
};
// Map over the products array and create JSX elements for each product
const productElements = products.map((product) =>
createElement(
'div',
{ key: product.id },
createElement('img', { src: product.image_link, alt: product.title }),
createElement('h3', null, product.title),
createElement('p', null, product.description),
createElement('p', null, `${product.price} ${product.currency}`),
createElement('a', { href: product.link, onClick: (e) => handleProductClick(product, e), }, 'See the product'),
createElement('button', null, createElement('i', { className: 'fa fa-heart' }))
)
);
// Return the JSX to be rendered in place of the standard "Shop This Look" section
return createElement(
'div',
null,
createElement('h2', null, 'Custom Shop This Look'),
...productElements
);
},
Here is the info you'll receive about a product :
export interface IProduct {
catalog_id: string;
company_id: string;
description: string;
id: string;
image_link: string;
link: string;
price?: number;
currency?: string;
title: string;
updated_at: string;
variant_name?: string;
}
If you ingested an international catalog, a localization can be set via the AdAlong widget customization interface. This will be the default location for displaying product names, links and pricing information in shop the look. You can override this setting by passing a new location directly as a parameter when the widget is loaded.
adalongWidget.load('#widget', { localization: 'GB' });
You can leverage AdAlong widget events in your Facebook Pixel.
First you have to follow those instructions to create a FB pixel. Once created, you need to add the following base code into the <head>
tag of the page. Please note that you should reference your pixel id in two places.
<!-- Facebook Pixel Code -->
<script>
!(function (f, b, e, v, n, t, s) {
if (f.fbq) return;
n = f.fbq = function () {
n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments);
};
if (!f._fbq) f._fbq = n;
n.push = n;
n.loaded = !0;
n.version = '2.0';
n.queue = [];
t = b.createElement(e);
t.async = !0;
t.src = v;
s = b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t, s);
})(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '{your-pixel-id-goes-here}');
fbq('track', 'PageView');
</script>
<noscript>
<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id={your-pixel-id-goes-here}&ev=PageView&noscript=1" />
</noscript>
<!-- End Facebook Pixel Code -->
Now to send information to Facebook from the AdAlong Widget you can map AdAlong events to Facebook standard events:
adalongWidget.onEvent('widgetLoaded', (event) => {
fbq('track', 'ViewContent', { posts: event.posts });
});
Here is the full documentation on standard Facebook events
Now if you want to track specifically which post has been opened, and not only viewed, Facebook Pixel allows to track custom events following this model:
adalongWidget.onEvent('postOpened', (event) => {
fbq('trackCustom', 'PostOpened', {
post: event.post,
productIds: event.post.products.map(({ id }) => id),
});
});
Note that in the example we send information about which products the opened post illustrates.
Use npm start
to build and watch for changes.
Then use npm link
to link this repo to another project in which to require the library.
You can also use node debug.js
to directly test the library and display it on
http://localhost:9800/?apiKey=yourWidgetKey&products=productRef1,productRef2&collections=collectionId1,collectionId2