Facets Behavior Extensions In Oracle ATG Web Commerce Endeca
Recently, I was tasked with a challenging assignment on one of our Oracle ATG Web Commerce projects. A client of ours decided to opt out of OOTB Endeca’s RefinementMenu cartridge and asked us to make RefinementMenu work slightly (or one might think significantly) different from its originally designed functionality. I will first describe how Endeca’s RefinementMenu cartridge works and then explain how I made the cartridge work according to client’s requirements.
Imagine we go to the product listing page on an online book store and see a faceted navigation panel with facets like author, genre, and language on the left-hand side. One way faceted navigation panel can be implemented is by a standard OOTB Endeca cartridge called RefinementMenu for every facet (using Endeca’s terminology: dimension). The RefinementMenuHandler prepares the RefinementMdexQuery, which executes an mdex request and finally retrieves results. These results are then parsed to obtain actual refinement objects that filled faceted navigation panel for a particular facet.
In Experience Manager, we specify a set of facets we want to see on the sidebar using the RefinementMenu cartridge. Suppose we have the following navigation panel with multi-select refinements:
Let’s see how the navigation panel changes after we apply some refinement. We use OOTB RefinementMenuHandler to fill the guided navigation panel.
After selecting the author J.-P. Desmoulins, who writes only in French in the genres of travel and history, the “language” facet disappears and the “genre” facet does no longer include “religion” and “science” refinements. This occurs due to Endeca’s inability to return results on mdex request when choosing J.-P. Desmoulins and “science” genre, for instance. Additionally, because this author writes only in French, the system does not offer any refinement for language. So this behavior excludes combinations of refinements that produce no results.
But what if the client does not want these facets and refinements to be hidden? He wants to save all possible filtering criteria from the starting point when the user got to the listing page. Please see the following table:
The client also wants the system to display a message if a combination of refinements returns zero results that reads as follows: “No results found. Please try to adjust filtering criteria.”
The solution we found to meet the client’s requirement was to use the ATG session scoped component and make a specific map structure to save this facet data during the user navigation process. We called this map structure guidedNavigationSnapshots.
As a key in this map stands a combination of navigation filters, search filters, and user segments. These navigation and search filters are retrieved from the UrlNavigationState object. Navigation and search filters correspond to a given state of the guided navigation panel. User segments divide various types of listing pages. Guided navigation panels are associated with a value in this map, where every value has a List type. So when a user goes on the listing page for the first time, a special droplet is invoked in order to put guided navigation panel snapshot to the guidedNavigationSnapshots map.
Let’s suppose there is a website that sells books and magazines. Suppose the user goes on the listing page for the first time. Search filters and user segments are empty but navigation filters hold a filter for the selection “Category: Books”. After the user applies some refinement (e.g. by the author J-P. Desmoulins), navigation filters change to the following: “books_dimval_id+Desmoulins_dimval_id”. We want to obtain the original navigation panel before the author J-P. Desmoulins was selected. In order to obtain it from the map, we need to form the right key of the guidedNavigationSnapshots map. Since navigation filters array is filled by the NavigationStateBuilder in the order of refinement selection, we need to remove the last filter from the array and create a key from these filters and segments. Using this key, we obtain the guided navigation panel we need. The only remaining thing to do is to populate the refinement links on the retrieved navigation panel using the NavigationState object for the current request. The RefinementBuilder can help solve this problem.
After that, the user can select Travel refinement from the genre facet. To get the right panel the last navigation filter needs to be removed and a snapshot key by these filters needs to be formed. Then we have to check if guidedNavigationSnapshots contains this key. If so, we will retrieve the value for the key; if not, we will remove the last navigation filter again until the end of the array. If no data is retrieved from the map, then current guided navigation panel should be put to the guidedNavigationSnapshots map.
Let’s suppose we have the following case. The user selects religion refinement and sees, “No results found. Please try to adjust the filtering criteria” message. Then he can remove this refinement and see the results. After that, if the user goes on the listing page under Magazines category, he will only see facets related to magazines and not books, because the guidedNavigationSnapshots map will not contain the key for the selection “Category: Magazines”.
To sum up, this is only one possible solution that we thought was effective and most importantly suitable for the client. Although we deviated from Endeca’s OOTB refinement functionality, we offered our custom solution that works in accordance with the client’s specific requirement of keeping all the original facets in the guided navigation panel.