Alternative use of Intershop breadcrumbs in site navigation

30.08.2012.

An important aspect of every web site is to provide customers with simple and effective navigation from one page to another. A common problem is provision of “back” link that redirects the customer to the original page. Examples are login pages, search results, related products etc. Search results are especially important since the “back” link also needs to take into account the pagination and relative location on the page where it was invoked. Intershop Enfinity Suite supports back and forward steps in the ordering and payment process, but there is no direct support for such functionality in the rest of the site (such as search).

Since back-reference links to search pages are usually long and messy URLs containing a lot of parameters (like search conditions, pages size, page number, category ID etc.), at some point it becomes too complicated to hard code all those URLs into the back links. Another problem that might arise is that a customer can be redirected two or more steps behind the current page so it is complex to remember the URL of the previously visited (and rendered) page. A very nice solution to such problems is to use rich breadcrumbs API and adapt it to provide back and forward functionality.

Intershop Breadcrumbs

Breadcrumbs support in Intershop API enables the storage and manipulation of links for all pages that customer has visited during his active browser session. Whenever a customer visits a certain page on the site, URL of that page is stored in an object called “breadcrumb” and that object is stored in the “breadcrumb trail” (stack of breadcrumbs) in the session dictionary. An object that contains all breadcrumbs is called ApplicationState. Whenever a customer visits a page with a URL that was stored in a certain breadcrumb, that breadcrumb and all of the breadcrumbs that were placed after it in the breadcrumb trail are removed from the trail. When the starting page is reached (the one that customer has visited first), trail is empty and there are no more breadcrumbs to be visited until a customer reaches another page.

Enfinity Suite also offers a template module which makes it possible to navigate breadcrumbs, called BreadcrumbTrail. As used on PrimeTech (Intershop example site), the breadcrumb trail on a page usually looks like this:

Every breadcrumb object has its name, ID and link. The name is what is displayed in breadcrumb trail list (i.e. Entertainment, Cables, …), link is URL of the page that breadcrumb points to and ID is its unique identifier. If two breadcrumbs have a same id they will be treated as same breadcrumbs (even if they have different name and link).

TIP:

Two breadcrumbs with same ID can never be placed one after another in the breadcrumb trail (even if their links are the same). If ID is not supported at the time breadcrumb is being added to the trail, breadcrumb link is saved as its ID.

Adaptation of Intershop Breadcrumbs

Back-reference links

In order to support back functionality, we obviously need a structure that would keep track of previously visited pages. Thus the breadcrumbs are the logical choice. The first step is to replace our hard coded back-reference links. This is how complete link with a back-reference link parameter looks without using breadcrumbs:

<a href="#URL(Action('ViewProductDetail-Start'),Parameter('ProductRef', Product:ProductRef), Parameter('CatalogCategoryID', CatalogCategoryID), Parameter('ReturnPipeline', URL(Action('ViewParametricSearch-OfferPaging'), Parameter('SearchCategoryUUID', SearchCategoryUUID), Parameter('SecPageableID', SecPageableID), Parameter('SecPageableName', SecPageableName), Parameter('SecPageNumber', SecPageNumber))))#">

In this example ReturnPipeline parameter represents the back-reference link that is used to get back to the page that we are currently located on. Depending on the page customer is currently browsing, some back-reference links could have up to 10 or more parameters, making them very complex and hard to track and debug if necessary. To replace those hard coded links, we use the breadcrumb module mentioned earlier in this blog entry, called breadcrumbTrail.

This is how module is used to add breadcrumb for the back-reference link in an example above:

<isBreadcrumbTrail link="#URL(Action('ViewParametricSearch-OfferPaging'), Parameter('SearchCategoryUUID', SearchCategoryUUID), Parameter('SecPageableID', SecPageableID), Parameter('SecPageableName', SecPageableName), Parameter('SecPageNumber', SecPageNumber))#" text="Katalog" hide="true" start="false">

This module is used on the example site Primetech to add a single breadcrumb to a trail and to display the breadcrumb trail on the page. A parameter “hide” of the module makes it possible to hide the breadcrumb trail from the page and use it just to add the breadcrumb to the trail. Since we are not using the id parameter, link is used as ID. If user just refreshes the page or visits the same page again, it won’t be added as another breadcrumb (since two breadcrumbs with same ID cannot be placed one after another). Another important parameter is start. If that parameter is set to true, it will make the added breadcrumb the first breadcrumb in the trail and all others will be removed.

That feature is particularly useful on catalog pages. Catalogs are usually the default start page and they always represent a starting point of products browsing. So breadcrumbs are usually not added before the catalog display page. If the last visited is configured to be a starting breadcrumb in the trail, it is easy to redirect customer back to starting point of his browsing when needed. We will explain later in this blog entry why this has proven to be very useful.

Landing page

The next step is use breadcrumbs on the landing page for providing back link functionality. This is an example of how we can retrieve a breadcrumb from session on an ISML template, using java code:

<%@page import = "com.intershop.beehive.core.capi.pipeline.PipelineDictionary"%>
<%@page import = "com.intershop.component.foundation.capi.application.ApplicationState"%>
<%@page import = "com.intershop.beehive.core.capi.request.Session"%>
<%
PipelineDictionary dict = getPipelineDictionary();
ApplicationState appState = (ApplicationState)dict.get("ApplicationState");
if (appState==null){
  Session s=(Session)dict.get("CurrentSession");
  appState = (ApplicationState)s.getObject("ApplicationState");
 
  if (appState==null){
   appState = new ApplicationState();
            s.putObject("ApplicationState", appState);
  }
  dict.put("ApplicationState",appState);
}
%>

The first three lines of the code are used to import packages that will be used for retrieving ApplicationState object, while the rest of code is used to simply retrieve the object from the pipeline or the session dictionary.

Once ApplicationState is retrieved, the breadcrumbs that are located in it can be used in a template:

<a href="<isprint value="#ApplicationState:LastButOneBreadcrumb:Link#"/>">Back</a>

The LastButOneBreadcrumb object represents the breadcrumb that was put in the trail before the last one (last one is usually the one that has link to the page customer is currently browsing).

Integrating other breadcrumb

In some cases it is useful to retrieve other breadcrumb besides LastButOneBreadcrumb. For example, after the conclusion of the shopping process, a costumer may be redirected back to the catalog where the shopping started from. If catalogs are marked as starting points in the breadcrumb trail, it is straightforward to find the first breadcrumb of the trail and use it for redirect:

if (!appState.isEmpty()) {
      Breadcrumb startBread = appState.goBackToStart();
      dict.put("StartBread",startBread);
}

Method goBackToStart() will simply return the first breadcrumb from the trail and we save it in the separate Breadcrumb object conveniently named “startBread”. The object is then put into pipeline dictionary and can be used on a template. We can simply use it in our back link like this:

<a href="<isprint value="#StartBread:Link#" encoding="off"/>" />
Navigating from pages without breadcrumb

There is also a case when a customer has reached a page that is not being put into breadcrumb trail (like his basket that has its own back and forth steps mechanism) and he wants to go back to last step. In that case we need to retrieve the last breadcrumb from the trail and redirect the customer to that page. This is how its done:

Breadcrumb lastBread = null;
Iterator<Breadcrumb> breadcrumbs = appState.getBreadcrumbs();
while (breadcrumbs.hasNext()) {
      lastBread = breadcrumbs.next();
}
dict.put("LastBread",lastBread);
Using breadcrumbs for redirects

Another use of breadcrumbs is to provide redirects to the originating page after certain actions (such as login, logout, finishing ordering process etc.). The obvious solution using breadcrumbs API is the following line of code:

<isredirect location="#LastBread:Link#"/>

However, it doesn’t always work because this piece of code can easily cause a redirection loop or when a customer is being redirected from a https to http protocol URL. As an alternative, the following code block can be used:

<html>
     <head>
          <isif condition="#isDefined(StartBread:Link)#">
                 <meta http-equiv="refresh" content="0; URL='<isprint value="#StartBread:Link#" encoding="off"/>'" />
          <iselse>
                 <meta http-equiv="refresh" content="0; URL='<isprint value="#URLEX(InsecureURL, '', Action('ViewApplication-DisplayCachedWelcomePage'))#" encoding="off"/>'" />
          </isif>
     </head>
     <body>
     </body>
</html>

The Refresh meta tag will simply refresh the current site to the new URL that is specified with a Breadcrumb, in a very short interval (0 seconds) which has the same effect as redirecting the customer to another site, without the drawbacks that the ISML redirect tag brings. The other part of the code block is used as a fallback strategy to redirect customer to the welcome page in case no breadcrumbs can be found (for example, user session has expired).

Conclusion

The illustrated use of breadcrumbs API is not relevant just for Intershop platform – it is a common problem on many complex web sites.

Breadcrumb trail technique (or should we call it a design pattern) essentially represents a controlled browsing history object that is kept in the user session and displayed to the user. In our example we avoid visual representation and use the breadcrumbs just for controlled history and back navigation support.

Breadcrumb trail technique (or should we call it a design pattern) essentially represents a controlled browsing history object that is kept in the user session and displayed to the user. In our example we avoid visual representation and use the breadcrumbs just for controlled history and back navigation support.

Controlled here means that not all URLs or redirects are kept in the history. Rather it is the developer who controls which URLs will be kept in the history without relying on referrer HTTP headers, encoding referrer URLs in request parameters and generated links etc. Since the history is kept in the user session, links are much cleaner and shorter than it would be possible without it.