Recently Viewed Products¶
Display to customers the last 10 products they viewed in a carousel. The Products are stored in Session Storage.
Installation¶
- Install the
optional-extensions/recently-viewed
package on your theme:- Copy the extension from
optional-extensions/recently-viewed
tothemes/custom-extensions/recently-viewed
- Copy the extension from
-
Add the extension template code to a new function conditional block in the JAPI page template.
- Make sure the following two items are assigned:
html_profile
(to load in our global variables)readytheme
(for the product card iterator)customfields
(if you need them)
- Create a new ReadyTheme Content Section with the code
load_products_data
and place this template code in it.
- Make sure the following two items are assigned:
<mvt:comment>
|
| Take in `l.settings:load_products_data`
| :settings
| :items Array of Product Codes, or Product IDs. Please see `code_or_id`.
| :image_type Image Type Code. Default: Main
| :image_height Image Height. Default: 360
| :image_width Image Width. Default: 360
| :code_or_id Use Product Code, or ID from the array. Defaults to `ID`.
| :customfields Comma seperated list of custom field codes
|
| Output
| :products Array of Products with data
| :products_count Count of the :products array
|
</mvt:comment>
<mvt:assign name="l.settings:load_products_data:products" value="''" />
<mvt:assign name="l.settings:load_products_data:products_count" value="0" />
<mvt:assign name="l.settings:load_products_data:settings:code_or_id" value="toupper( l.settings:load_products_data:settings:code_or_id )" />
<mvt:if expr="ISNULL l.settings:load_products_data:settings:code_or_id">
<mvt:assign name="l.settings:load_products_data:settings:code_or_id" value="'ID'" />
</mvt:if>
<mvt:if expr="ISNULL l.settings:load_products_data:settings:image_type">
<mvt:assign name="l.settings:load_products_data:settings:image_type" value="'main'" />
</mvt:if>
<mvt:assign name="l.settings:load_products_data:settings:image_height" value="int( l.settings:load_products_data:settings:image_height )" />
<mvt:if expr="l.settings:load_products_data:settings:image_height EQ 0">
<mvt:assign name="l.settings:load_products_data:settings:image_height" value="360" />
</mvt:if>
<mvt:assign name="l.settings:load_products_data:settings:image_width" value="int( l.settings:load_products_data:settings:image_width )" />
<mvt:if expr="l.settings:load_products_data:settings:image_width EQ 0">
<mvt:assign name="l.settings:load_products_data:settings:image_width" value="360" />
</mvt:if>
<mvt:comment>
|
| Create discount state to use for discount pricing
|
</mvt:comment>
<mvt:do file="g.Module_Feature_PGR_UT" name="l.discount_state_success" value="DiscountState_CreateEmpty( l.discount_state )" />
<mvt:if expr="l.discount_state_success">
<mvt:do file="g.Module_Feature_PGR_UT" name="l.pricegroup_count" value="ResolvedPriceGroupAndModuleList_Load_Customer_Cached( g.Basket:cust_id, l.pricegroups )" />
<mvt:do file="g.Module_Feature_PGR_UT" name="l.success" value="DiscountState_Set_PriceGroups( l.discount_state, l.pricegroups, l.pricegroup_count )" />
<mvt:do file="g.Module_Feature_PGR_UT" name="l.void" value="DiscountState_Disable_Unused_Item_PriceGroups( l.discount_state )" />
<mvt:do file="g.Module_Feature_PGR_UT" name="l.void" value="DiscountState_Predict_Baseline_Discounts( l.discount_state )" />
</mvt:if>
<mvt:do file="g.Module_Library_DB" name="l.ImageType_Load_Code_Success" value="ImageType_Load_Code( l.settings:load_products_data:settings:image_type, l.image_type )" />
<mvt:foreach iterator="code_or_id" array="load_products_data:settings:items">
<mvt:assign name="l.settings:product_data" value="''" />
<mvt:assign name="l.productimage" value="''" />
<mvt:assign name="l.temp" value="''" />
<mvt:assign name="l.load_cropped" value="''" />
<mvt:comment>
|
| Load product runtime data / skip if product cannot be loaded
|
</mvt:comment>
<mvt:if expr="l.settings:load_products_data:settings:code_or_id EQ 'ID'">
<mvt:do file="g.Module_Library_DB" name="l.loaded_product" value="Runtime_Product_Load_ID_Cached( l.settings:code_or_id, l.settings:product_data )" />
<mvt:else>
<mvt:do file="g.Module_Library_DB" name="l.loaded_product" value="Runtime_Product_Load_Code_Cached( l.settings:code_or_id, l.settings:product_data )" />
</mvt:if>
<mvt:if expr="NOT l.loaded_product">
<mvt:foreachcontinue />
</mvt:if>
<mvt:comment>
|
| Set product data members:
| :base_price
| :formatted_base_price
| :formatted_price
| :link
| :imagetypes:main (or image type code)
| :src
|
</mvt:comment>
<mvt:do file="g.Module_Feature_URI_UT" name="l.settings:product_data:link" value="Store_Product_URL( l.settings:product_data, l.flags )" />
<mvt:do file="g.Module_Library_DB" name="l.ProductImage_Load_Type_Success" value="ProductImage_Load_Type( l.settings:product_data:id, l.image_type:id, l.temp:productimage )" />
<mvt:do file="g.Module_Library_DB" name="l.load_cropped" value="GeneratedImage_Load_Dimensions( l.temp:productimage:image_id, l.settings:load_products_data:settings:image_width, l.settings:load_products_data:settings:image_height, l.temp:cropped_image )" />
<mvt:if expr="NOT l.load_cropped">
<mvt:do file="g.Module_Library_DB" name="l.Image_Load_ID_Success" value="Image_Load_ID( l.temp:productimage:image_id, l.temp:imagedata )" />
<mvt:do file="g.Module_Library_DB" name="l.Image_Load_File_Success" value="Image_Load_File( l.temp:imagedata:image, l.temp:product_image )" />
<mvt:do file="g.Module_Library_DB" name="l.GeneratedImage_FindOrInsert_Image_Dimensions_Success" value="GeneratedImage_FindOrInsert_Image_Dimensions( l.temp:product_image, l.settings:load_products_data:settings:image_width, l.settings:load_products_data:settings:image_height, l.temp:cropped_image )" />
</mvt:if>
<mvt:assign name="l.settings:product_data:imagetypes:main" value="l.temp:cropped_image:image" />
<mvt:if expr="NOT ISNULL l.settings:product_data:imagetypes:main">
<mvt:assign name="l.settings:product_data:src" value="l.settings:product_data:imagetypes:main" />
</mvt:if>
<mvt:assign name="l.settings:product_data:base_price" value="l.settings:product_data:price" />
<mvt:if expr="ISNULL l.settings:product_data:formatted_price">
<mvt:do file="g.Module_Store_Module_Currency" name="l.settings:product_data:formatted_price" value="CurrencyModule_AddFormatting( g.Store:currncy_mod, l.settings:product_data:price )" />
</mvt:if>
<mvt:assign name="l.settings:product_data:formatted_base_price" value="l.settings:product_data:formatted_price" />
<mvt:if expr="l.discount_state_success">
<mvt:do file="g.Module_Feature_PGR_UT" name="l.success" value="DiscountState_Predict_Product_Discounts_WithProductSubscriptionTerm( l.discount_state, l.settings:product_data, 0, 0, 1, l.settings:product_data:price, l.settings:product_data:discounts, l.settings:product_data:discount_count )" />
<mvt:do file="g.Module_Store_Module_Currency" name="l.settings:product_data:formatted_price" value="CurrencyModule_AddFormatting( g.Store:currncy_mod, l.settings:product_data:price )" />
</mvt:if>
<mvt:if expr="l.settings:load_products_data:settings:customfields">
<mvt:if expr="miva_splitstring( l.settings:load_products_data:settings:customfields, ',', l.settings:load_products_data:settings:customfields_codes, 'trim' ) EQ 1">
<mvt:assign name="l.settings:load_products_data:settings:customfields" value="l.settings:load_products_data:settings:customfields $ ',fake_customfield'" />
</mvt:if>
<mvt:item name="customfields" param="Read_Product_ID( l.settings:product_data:id, l.settings:load_products_data:settings:customfields, l.settings:product_data:customfield_values:customfields )" />
</mvt:if>
<mvt:assign name="l.settings:load_products_data:products_count" value="miva_array_insert_var( l.settings:load_products_data:products, l.settings:product_data, -1 )" />
</mvt:foreach>
<mvt:assign name="l.settings:load_products_data:settings" value="''" />
- On
PROD
add the following where you want the Recently Viewed products carousel to display:<div id="js-recently-viewed" class="lazyload"></div>
- Install the Storage Factory package.
- In
PROD.js
, add the following code in theonReady
method:this.recentlyViewed();
- In
PROD.js
, add the following functions:recentlyViewed () { const recentlyViewedElement = document.getElementById('js-recently-viewed'); if (!recentlyViewedElement) { return; } if (recentlyViewedElement.classList.contains('lazyloaded')) { this.loadRecentlyViewed(); return; } document.addEventListener('lazybeforeunveil', (e) => { if (e.target.id === 'js-recently-viewed') { this.loadRecentlyViewed(); } }); } async loadRecentlyViewed () { const {default: RecentlyViewed} = await import('custom-extensions/recently-viewed'); new RecentlyViewed(this.pageContext.Product_Code, this.pageContext.Japi_Url); }
Options¶
The RecentlyViewed
object takes in 2 required parameters, and an optional object as a third argument that is utilized for overriding any of the default configuration settings. The following table defines the available options:
Name | Type | Description | Default Value |
---|---|---|---|
productCode | String | The Current Product Code you're viewing. Required. | |
apiURL | String | The API url (JAPI). Required. | |
container | Element | Overwrite recently-viewed container element. | #js-recently-viewed |
productsToShow | Number | Overwrite number of products to show. | 10 |
Template¶
The default template is the same as the "Related Products" carousel on the Product Page and can be updated on the JAPI
page template after adding the extension template code. If you need to load in more data (example: custom fields), you can make your edits there. It will utilize the product_card_iterator
template for each product card.