Displaying Product Pricing in a B2B Search Page With the Augmented Result List Component
Displaying Product Pricing in a B2B Search Page With the Augmented Result List Component
The AugmentedResultList
component extends the ResultList
component to let you invoke a function to augment the raw
field of result list items before rendering them.
In a Visualforce Page for a Salesforce B2B Commerce Storefront search page, you can use the B2B Commerce for Visualforce (formerly CloudCraze) API to retrieve product information in that function.
A typical scenario where you would do this is in a B2B commerce interface where you want your result list items to display product information that’s not indexed by Coveo, such as pricing information. This article lays out the steps and provides examples to help you do so. While this article focuses on pricing information, you could adapt the same steps for any other product information you would want to retrieve using the B2B Commerce for Visualforce API.
Step 1: Create a Custom Visualforce Controller
Create a custom Visualforce controller which uses the B2B Commerce for Visualforce API to return the target product information.
Your controller takes a list of product ids as an argument and returns a dictionary that can contain the following key-value pairs:
-
"commonData": Map<String,Object>
(optional): A dictionary of data common to all products. -
"resultData": List<Map<String, Object>>
(optional): A list of product-specific information.
Example: Retrieving Product Pricing Information
You use the ccrz.ccApiProduct.fetch
function to retrieve product prices and the ccrz.cc_CallContext.userCurrency
object to retrieve user currency.
// ProductResultListController.apxc
global with sharing class ProductResultListController {
@RemoteAction
global static ccrz.cc_RemoteActionResult fetchProducts(final ccrz.cc_RemoteActionContext ctx, List<String> productIds) {
ccrz.cc_RemoteActionResult res = new ccrz.cc_RemoteActionResult();
ccrz.cc_CallContext.initRemoteContext(ctx);
res.success = false;
// Prepare a product query for the ccrz API
Map<String, Object> productFetchQuery = new Map<String, Object>{
ccrz.ccApi.API_VERSION => ccrz.ccApi.CURRENT_VERSION,
ccrz.ccApiProduct.PRODUCTIDLIST => new Set<String>(productIds),
ccrz.ccApiProduct.INCLUDE_ATTRIBUTE_PRICING => true,
ccrz.ccApiProduct.PARSE_ATTRIBUTE_PRICING => true,
ccrz.ccApiProduct.PARAM_INCLUDE_PRICING => true,
ccrz.ccApi.SIZING => new Map<String, Object>{
ccrz.ccApiProduct.ENTITYNAME => new Map<String, Object>{
ccrz.ccApi.SZ_DATA => ccrz.ccApi.SZ_XL
}
}
};
try {
// Call ccrz API with the above query
Map<String, Object> productFetchData = ccrz.ccApiProduct.fetch(
productFetchQuery
);
// Initialize return object
Map<String,Object> productDataResults = new Map<String,Object>();
// Populate the `resultData` object with product specific data
productDataResults.put('resultData', (List<Map<String, Object>>) productFetchData.get(
ccrz.ccApiProduct.PRODUCTLIST
));
// Call ccrz API to fetch data common to all products
Map<String,Object> contextData = new Map<String,Object>();
contextData.put('currency', ccrz.cc_CallContext.userCurrency);
// Populate the `commonData` object with data common to all products
productDataResults.put('commonData', contextData);
res.success = true;
res.data = productDataResults;
}
catch (Exception ex) {
res.success = false;
res.data = false;
ccrz.ccLog.log(System.LoggingLevel.ERROR, 'ERR',ex.getMessage());
}
return res;
}
}
Step 2: Leverage Your Controller in Your Visualforce Page
In the target Visualforce page, you need to create a function that leverages your controller and sets that function as a value of the fetchAugmentData
option on your AugmentedResultList
component, as shown in the following example.
Example: Using Your Visualforce Controller in Your Visualforce Page
<apex:page sidebar="false" showHeader="false" standardStylesheets="false" applyHtmlTag="false" controller="ProductResultListController">
<script>
// Remote action to fetch Pricing info for Product list
function getProducts(objectIdsList) {
return new Promise((resolve, reject) => {
if (!objectIdsList && !objectIdsList.isArray()) {
reject('objectIdsList is not an array.');
}
Visualforce.remoting.Manager.invokeAction(
'{!$RemoteAction.ProductResultListController.fetchProducts}',
CCRZ.pagevars.remoteContext,
objectIdsList,
function (result, event) {
if (event.status) {
resolve(result);
} else if (event.type === 'exception') {
reject(`${event.message} : ${event.where}`);
} else {
reject(event.message);
}
}
)
});
}
// Set the remote action function as an option on your AugmentedResultList component
document.addEventListener('DOMContentLoaded', function () {
var coveoSearchInterfaceRoot = document.getElementById('search');
Coveo.options(
coveoSearchInterfaceRoot,
{
AugmentedResultList: {
fetchAugmentData: window.getProducts
},
}
);
})
</script>
<CoveoV2:SearchInterface name="<SEARCH_INTERFACE_NAME>" catalog="<YOU_CATALOG_ID>"></CoveoV2:SearchInterface>
</apex:page>
Step 3: Include the AugmentedResultList
Component
Use the AugmentedResultList
component in your markup and use the target fields in your result template.
Example: Including the AugmentedResultList
Component
In your <SEARCH_INTERFACE_NAME>
interface markup, you use an AugmentedResultList
component and create a result template where you leverage the raw.price
and raw.currency
fields retrieved in the previous steps:
...
<div class="CoveoAugmentedResultList" data-layout="list">
<script id="ProductList" class="result-template" type="text/underscore" data-field-objecttype="Product">
<div class="coveo-result-frame">
<div class="coveo-result-cell">
...
<span class="CoveoFieldValue" data-field="@price" data-helper="currency" data-helper-decimals="2" data-helper-symbol="$"></span>
<span class="CoveoFieldValue" data-field="@currency"></span>
</div>
</div>
</script>
</div>
...