Adding a New Product Type
This tutorial will show you how to add a new product type by implementing three interfaces: CPType, ScreenNavigationCategory, and ScreenNavigationEntry.
Product types can be used to group products that share similar characteristics. Liferay Commerce provides three product types out-of-the-box: Simple, Grouped, and Virtual.
Overview
Deploy an Example
In this section, we will get an example product type 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.55-ga55
Sign in to Liferay at http://localhost:8080. Use the email address [email protected] and the password test. When prompted, change the password to learn.
Then, follow these steps:
Download and unzip the Acme Commerce Product Type.
curl https://resources.learn.liferay.com/commerce/latest/en/developer-guide/catalog/liferay-c1n4.zip -O
unzip liferay-c1n4.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 Liferay Docker container console.
STARTED com.acme.c1n4.web_1.0.0
Verify that the example product type was added. Open your browser to
https://localhost:8080
. Click the Applications Menu () and navigate to Commerce → Products. Then click on the (+) icon to add a new product. The new product type (“Example”) will be present in the list of types to choose from.
In Liferay Commerce 2.1 and earlier, find the products page by navigating to Control Panel → Commerce → Products.
Congratulations, you’ve successfully built and deployed a new product type that implements CPType
.
Next, let’s dive deeper to learn more.
Walk Through the Example
In this section, we will review the example we deployed. We will create two classes: a product type class and a screen navigation entry class for a custom screen. Walk through the following:
- Annotate the Product Type Class for OSGi Registration
- Review the
CPType
Interface - Annotate the Screen Navigation Entry Class for OSGi Registration
- Review the
ScreenNavigationCategory
Interface - Review the
ScreenNavigationEntry
Interface - Complete the Product Type
Annotate the Product Type Class for OSGi Registration
Our product type class implements the CPType
interface:
@Component(
property = {
"commerce.product.type.display.order:Integer=16",
"commerce.product.type.name=c1n4"
},
service = CPType.class
)
public class C1N4CPType implements CPType {
The product type name must be a unique value so that Liferay Commerce can distinguish our product type from existing product types.
The
commerce.product.type.display.order
value indicates how far into the list of product types our product type will appear in the UI. For example, the virtual product type has a value of 15. Giving our product type a value of 16 ensures that it will appear immediately after the virtual type.
Review the CPType
Interface
Implement the following methods of CPType
in the product type class:
public void deleteCPDefinition(long cpDefinitionId) throws PortalException;
This method is where any custom deletion logic for the product type will be added.
public String getLabel(Locale locale);
This returns a text label that describes the product type. See the implementation in C1N4CPType.java for a reference in retrieving the label with a language key.
public String getName();
This returns the name of our product type. This name may be a language key that corresponds to the name that will appear in the UI.
Annotate the Screen Navigation Entry Class for OSGi Registration
Our screen navigation entry class implements both the ScreenNavigationCategory
and ScreenNavigationEntry
interfaces:
@Component(
property = {
"screen.navigation.category.order:Integer=11",
"screen.navigation.entry.order:Integer=11"
},
service = {ScreenNavigationCategory.class, ScreenNavigationEntry.class}
)
public class C1N4ScreenNavigationEntry
implements ScreenNavigationCategory, ScreenNavigationEntry<CPDefinition> {
It is important to provide a distinct key for the navigation screen class so that Liferay Commerce can distinguish it as a separate screen from the existing screens. Reusing a key that is already in use will override the existing associated navigation screen.
The
screen.navigation.category.order
andscreen.navigation.entry.order
values determine what position in the product type screens this screen will appear. For example, the Details screen class has these values set to 10; setting them to 11 will ensure that our custom screen appears after it in the list.
Review the ScreenNavigationCategory
Interface
Implement the following methods in the screen navigation entry class:
public String getCategoryKey();
This returns a unique identifier for the category used for the screen navigation entry.
public String getLabel(Locale locale);
This returns a text label for the screen navigation entry that will be displayed in the UI. See the implementation in C1N4ScreenNavigationEntry.java for a reference in retrieving the label with a language key.
public String getScreenNavigationKey();
This returns a key to indicate where our screen should appear in Liferay. Return the string value
"cp.definition.general"
so it properly appears among the other screens for products.
Review the ScreenNavigationEntry
Interface
Continue to build on the screen navigation entry class with the following methods:
String getCategoryKey();
This returns a unique identifier for the screen navigation category used by our screen.
String getEntryKey();
This returns a unique identifier for the screen navigation entry. It returns the same value as
getCategoryKey
.
String getScreenNavigationKey();
This is the same method as
getScreenNavigationKey
for theScreenNavigationCategory
interface. We implemented this method by returning the string value"cp.definition.general"
.
public void render(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws IOException;
This is where we add the code to render a customized screen for our product type.
Complete the Product Type
The product type is comprised of backend logic for deleting the product, logic to render the screen in the navigation menu, and the custom screen itself. Do the following:
- Configure the
ServletContext
for the module. - Implement the
ScreenNavigationEntry
’srender
method. - Override the
ScreenNavigationEntry
’sisVisible
method. - Add the product type deletion logic to
deleteCPDefinition
. - Add a JSP to render the custom screen.
- Add the language key to
Language.properties
.
Configure the ServletContext
for the Module
Define the ServletContext
in our ScreenNavigationEntry
class using the symbolic name of our bundle so that it can find the JSP in our module:
@Reference(target = "(osgi.web.symbolicname=com.acme.c1n4.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 JSP.We 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/c1n4-web
. See bnd.bnd for a reference on these values.
Implement the ScreenNavigationEntry
’s render
Method
@Override
public void render(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws IOException {
_jspRenderer.renderJSP(
_servletContext, httpServletRequest, httpServletResponse,
"/c1n4.jsp");
}
Use a
JSPRenderer
to render the JSP for our product type’s custom screen (in our example, c1n4.jsp). Provide theServletContext
as a parameter to find the JSP we have created.
Override the ScreenNavigationEntry
’s isVisible
Method
@Override
public boolean isVisible(User user, CPDefinition cpDefinition) {
if (cpDefinition == null) {
return false;
}
return Objects.equals(
cpDefinition.getProductTypeName(), getCategoryKey());
}
Implement logic here to determine when to show the custom screen. In our example, we only check whether the product type from the
CPDefinition
matches our example product type.
Add the Product Type Deletion Logic to deleteCPDefinition
Our example does not require any logic to be added to deleteCPDefinition
.
Add a JSP to Render the Custom Screen
In our example, we are adding a JSP that prints “Hello C1N4.”.
<h1>Hello C1N4.</h1>
Implement any other inputs or actions desired on the custom screen here, such as a form or MVC action command. See MVC Action Command for more information on adding an MVC action command that can be accessed from the JSP.
Add the Language Key to Language.properties
Add the language key and its value to a Language.properties file within our module:
c1n4-commerce-product-type=C1N4 Commerce Product Type
c1n4-screen-navigation-entry=C1N4 Screen Navigation Entry
See Localizing Your Application for more information.
Conclusion
Congratulations! You now know the basics for implementing the CPType
interface, and have implemented a new product type with its own custom screen to Liferay Commerce.