Implementing a Custom Product Content Renderer
This tutorial will show you how to add a custom product content renderer by implementing the CPContentRenderer interface.
A product content renderer provides a style of displaying product details for a specific product type, in a variety of widgets that can display products. Liferay Commerce provides product content renderers for each out-of-the-box product type, such as SimpleCPContentRenderer for Simple products.
Overview
Deploy an Example
In this section, we will get an example product content renderer up and running on your instance of Liferay Commerce.
Start a new Liferay instance by running
docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.120-ga120
Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.
Then, follow these steps:
-
Download and unzip the Acme Commerce Product Content Renderer.
curl https://resources.learn.liferay.com/commerce/latest/en/developer-guide/content/liferay-q4f7.zip -O
unzip liferay-q4f7.zip
-
Build and deploy the example.
./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
noteThis command is the same as copying the deployed jars to
/opt/liferay/osgi/modules
on the Docker container. -
Confirm the deployment in the Docker container console.
STARTED com.acme.q4f7.web_1.0.0
-
Verify that the example product content renderer was added. Open your browser to
https://localhost:8080
and navigate to any catalog with products in Liferay Commerce. Click on the product to see the Product Details widget, then click Configuration for the widget.Under the Custom Renderer section, select Simple. Below the Simple Commerce Product Type Renderer Key dropdown, select the new renderer (“Q4F7 Commerce Product Content Renderer”).
-
When you select a product, the new renderer shows only the product’s SKU, price, availability, and stock quantity.
Congratulations, you’ve successfully built and deployed a new custom product content renderer that implements CPContentRenderer
.
Next, let’s dive deeper to learn more.
Walk Through the Example
In this section, we will review the example we deployed. First, we will annotate the class for OSGi registration. Second, we will review the CPContentRenderer
interface. And third, we will complete our implementation of CPContentRenderer
.
Annotate the Class for OSGi Registration
@Component(
property = {
"commerce.product.content.renderer.key=q4f7",
"commerce.product.content.renderer.order=1",
"commerce.product.content.renderer.type=" + SimpleCPTypeConstants.NAME
},
service = CPContentRenderer.class
)
public class Q4F7CPContentRenderer implements CPContentRenderer {
It is important to provide a distinct key for the product content renderer so that Liferay Commerce can distinguish the new renderer from others in the product content renderer registry. Reusing a key that is already in use will override the existing associated renderer.
The
commerce.product.content.renderer.order
property is an integer value that Commerce uses to list the renderer in the UI. Renderers are listed in ascending order. For example, the SimpleCPContentRenderer has this property set to the minimum integer value, so other renderers for Simple type products will appear after it in the list.The
commerce.product.content.renderer.type
property determines what type of product this renderer can be used for. In our example, we use a Simple type, so the renderer will appear under the Simple category in the UI.
Review the CPContentRenderer
Interface
Implement the following methods:
public String getKey();
This method provides a unique identifier for the product content renderer in the product content renderer registry. The key can be used to fetch the renderer from the registry. Reusing a key that is already in use will override the existing associated renderer.
public String getLabel(Locale locale);
This returns a text label that describes the product content renderer. See the implementation in Q4F7CPContentRenderer.java for a reference in retrieving the label with a language key.
public void render(
CPCatalogEntry cpCatalogEntry,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws Exception;
This is where we add the code to render a customized view for our product content renderer.
There are several ways to define a view: JSP, Freemarker template, or Soy template. In our example, we will use a JSP.
Complete the Product Content Renderer
The product content renderer is comprised of a custom view that we define and render. Do the following:
- Configure the
ServletContext
for the module. - Implement the
render
method. - Add a JSP for the custom view.
- Add the language key to
Language.properties
.
Configure the ServletContext
for the Module
Define the ServletContext
using the symbolic name of our bundle so that it can find the JSP in our module:
@Reference(target = "(osgi.web.symbolicname=com.acme.q4f7.web)")
private ServletContext _servletContext;
The value we set for
osgi.web.symbolicname
matches the value forBundle-SymbolicName
in our bnd.bnd file. These values must match for theServletContext
to locate the JSPWe also need to declare a unique value for
Web-ContextPath
in our bnd.bnd file so theServletContext
is correctly generated. In our example,Web-ContextPath
is set to/q4f7-web
. See bnd.bnd for a reference on these values.
Implement the render
Method
@Override
public void render(
CPCatalogEntry cpCatalogEntry,
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws Exception {
_jspRenderer.renderJSP(
_servletContext, httpServletRequest, httpServletResponse,
"/view.jsp");
}
Use a
JSPRenderer
to render the JSP for our product content renderer (in this case, view.jsp). Provide theServletContext
as a parameter to find the JSP we have created.
Add a JSP for the Custom View
<%
CPContentHelper cpContentHelper = (CPContentHelper)request.getAttribute(CPContentWebKeys.CP_CONTENT_HELPER);
CPSku cpSku = cpContentHelper.getDefaultCPSku(cpContentHelper.getCPCatalogEntry(request));
%>
CPContentHelper is a class that retrieves information about a particular product.
CPCatalogEntry represents the displayed product itself. We get more information about the product with its default SKU, contained in a CPSku object.
<c:if test="<%= cpSku != null %>">
SKU: <%= cpSku.getSku() %><br />
Price: <%= cpSku.getPrice() %><br />
Availability: <%= cpContentHelper.getAvailabilityLabel(request) %><br />
Stock Quantity: <%= cpContentHelper.getStockQuantityLabel(request) %>
</c:if>
<liferay-util:dynamic-include key="com.liferay.commerce.product.content.web#/add_to_cart#" />
We use Liferay Commerce’s add_to_cart_button.jsp to insert the “Add to Cart” feature to our view.
Add the Language Key to Language.properties
Add the language key and its value to a Language.properties file within our module:
q4f7-commerce-product-content-renderer=Q4F7 Commerce Product Content Renderer
See Localizing Your Application for more information.
Conclusion
Congratulations! You now know the basics for implementing the CPContentRenderer
interface, and have added a new product content renderer to Liferay Commerce.