Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}
Refcard #126

Essential Liferay

A Definitive Guide for Enterprise Portal Development

Includes web content management, workflow, administration, hot tips and more.

23.8k

Brought to you by

Rivet Logic
Free .PDF for easy Reference

Written by

James Falkner Community Manager, Liferay Inc.
Alaaeldin El-Nattar COO, Rivet Logic
Refcard #126

Essential Liferay

A Definitive Guide for Enterprise Portal Development

Includes web content management, workflow, administration, hot tips and more.

23.8k
Free .PDF for easy Reference

Written by

James Falkner Community Manager, Liferay Inc.
Alaaeldin El-Nattar COO, Rivet Logic

Brought to you by

Rivet Logic
Table of Contents

Introduction

About This Refcard

Getting Set Up

Liferay Basics

Portal Architecture

Web Content Management

Template and Theme Variables

Workflow

Kaleo Workflow Definitions

Liferay Administration

App Server Configuration

Portal Properties

Developing for Liferay

ElasticSearch

Audience Targeting

More Information

Section 1

Introduction

Liferay Portal is a free and open-source enterprise portal written in Java and distributed under the GNU LGPL. Now in its thirteenth year of development, the award-winning product is one of the most widely deployed portal technologies on the market, with over five million downloads worldwide. More than a portal, Liferay is a platform for creating effective business applications and solutions. It offers a robust feature set, impressive scalability, time-saving development tools, support for over 30 languages, and a flexible, scalable architecture that is open-source developed and enterprise refined.

Section 2

About This Refcard

This Refcard will help both novices and professionals quickly navigate some of Liferay’s most popular features and hidden gems. It will cover topics such as installation, configuration, administration, and development features.

Section 3

Getting Set Up

Liferay Portal Community Edition is freely downloadable here. You will be presented with multiple download options from the linked page.

Liferay Digital Experience Platform (Liferay DXP) is an equivalent version of Liferay Enterprise Edition from the previous versions of Liferay. This download comes with a 30-day trial license that allows you to navigate the full features of Liferay DXP.

Liferay Portal CE

Bundles are archives that combine Liferay Portal with popular application servers such as Tomcat, GlassFish, and others.

All bundles are cross-platform and should run on any modern flavor of Windows, Linux, macOS, or other Unix-based operating systems. The complete compatibility matrix of Liferay DXP can be found here.

Starting Liferay

In most cases, installing a bundle is as easy as uncompressing the archive and then starting the application server.

For example, Tomcat is started with:

$ ${LIFERAY_HOME}/tomcat-8.0.32/bin/startup.sh

$ tail –f ${LIFERAY_HOME}/tomcat-8.0.32/logs/catalina.out

Once started, your web browser should automatically be launched and directed to http://localhost:8080, which should display the default Liferay website, as shown here.

Image title


Other bundles are started in a similar fashion.

Section 4

Liferay Basics

Liferay is a portal server. This means that it is designed to be a single environment where all of the required applications (represented by individual portlets) can run, and these applications are integrated together in a consistent and systematic way.

Section 5

Portal Architecture

In the illustration below, each arrow may be read using the words “can be a member of.” It is important to note that the diagram illustrates only users and their collections. Permissions do not flow through all of these collections; permissions can be assigned to roles only.

Image title

The following concepts are used throughout Liferay:

  • Portals are accessed by Users.
  • Users can be collected into User Groups.
  • Users can belong to Organizations and join/leave Communities.
  • Roles are collections of permissions on portal objects that can be assigned to Users.
  • Organizations can be grouped into hierarchies, such as Home Office/Regional Office/Satellite Office. Communities are not hierarchical.
  • Users, Groups, and Organizations can belong to Communities that have common interests.
  • Within Organizations and Communities, users can belong to Teams, which are groupings of users for specific functions within a community or organization.
  • Users, Organizations, and Communities have two separate collections of Pages called Public and Private Pages. Each page can have as many applications (portlets) as desired. The page administrator can lay out these applications into zones defined by a default or customized layout template.
Section 6

Web Content Management

Liferay Web Content Management (WCM) is a system that allows non-technical users to publish content to the web without advanced knowledge of web technology or programming of any sort. Liferay Content Management System (CMS) empowers you to publish your content with a simple point-and click interface and it helps you keep your site fresh.

You can use WCM to author both structured and unstructured content. Unstructured content is authored using an HTML-based WYSIWYG editor. Structured content is authored and displayed by combining Web Content Structures, Web Content Templates, and Web Contents. Structures and Templates are defined individually using a text editor or through the Liferay WCM UI.

Accessing Structure Elements

The following table shows how to access structure data from your Web Content Template code (when using FreeMarker templates; other template languages such as XSL or CSS have similar constructs). The variable name defined in the structure is denoted in bold and will be different depending on the name assigned in the structure.

Element Type FreeMarker Template Accessors
Text field  ${tf.getData()} 
Text box  ${textbox.getData()} 
Text area (HTML)  ${textarea.getData()} 
Checkbox  ${checkbox.getData()} 
Selectbox  ${selectbox.getData()} 
Multi-selection list
#foreach($selection in $mylist.options)

$selection

#end


Image gallery <img src=”/image/image_gallery?img_id=$img.getData()”/>
Link to page  ${linkToPage.getFriendlyUrl()} 
Repeatable
<#if el.getSiblings()?has_content>

<#list el.getSiblings() as cur_el>

${cur_el.getData()}

</#list>

</#if>


Hierarchy
<#if el.getChildren()?has_content>

<#list el.getChildren() as cur_child>

${cur_child.getData()}

</#list>

</#if>


Section 7

Template and Theme Variables

The following table lists the most common built-in variables accessible from FreeMarker Template code (when using FreeMarker templates; other template languages such as CSS or XSL have similar constructs) — for example, $layout.getChildren(). Items marked with an asterisk (*) are only available from Liferay Theme files.

Variable Name Description
request HTTPServletRequest object
company Current company object; represents the portal instance on which the user is currently navigating.
companyId Current company ID.
groupId ID of the group in which this web content is published.
locale Current user's locale, as defined by Java.
randomNamespace A randomized string. It is very useful for creating IDs that are guaranteed to be unique.
browserSniffer Dynamic browser capabilities, i.e. $browserSniffer.isMobile().
portal Current portal instance.
portletURLFactory Creates portlet URLs (action URLs, etc.).
stringUtil Useful string utilities.
portletConfig* Standard PortletConfig object describing information from the portal.xml file.
renderRequest* Standard Portlet RenderRequest object.
renderResponse* Standard Portlet RenderResponse object.
themeDisplay* Contains many useful items, such as the logged-in user, layout, logo information, paths, and more.
user* The User object representing the current user.
layoutSet* The set of pages to which the user has navigated. Generally, communities and organizations have a public set and a private set.
scopeGroupId* groupId that is used to identify the scope where the data of the current portlet is stored and retrieved. The scope can represent a community, organization, user, the global scope, or a scope tied to a specific page.
timeZone* The current user's time zone, as defined by Java.
viewMode i.e. “print” when clicked print icon
fullTemplatesPath* Path to all templates used.
pageTitle* Title of the page.
serviceLocator Access to other Liferay services. By default, this variable is disabled; it must be enabled via portal-ext.properties
prefsPropsUtil Access to portal settings that were set from the Control Panel or through the portal.properties configuration file.
permissionChecker An object that can determine, given a particular resource, whether the current user has a particular permission for that resource.

[css|images|javascript

t|templates]_folder*

Full path to various theme files.

Hot Tip: A Web Content Template that is set as Cacheable will return a cached result when accessing the variables (potentially returning stale or sensitive data). To ensure you get an uncached result, make sure that you uncheck the Cacheable option for your Web Content Template.

Section 8

Workflow

A Liferay Workflow is a predetermined sequence of connected steps. In Liferay, a workflow is designed to manage the creation, modification, and publication of all supported web content types (including web content, blogs, wikis, message boards, documents, and other user-generated content). Liferay ships with a default workflow engine called Kaleo. It can generate and reference roles scoped for Organizations, Communities, and the entire Portal. This engine is deeply integrated with Liferay but can be replaced with an external engine, such as jBPM.

Section 9

Kaleo Workflow Definitions

Liferay comes with a default Kaleo workflow definition called “Single Approver,” which means that a single approval is needed before content is published. You can create custom workflow definitions by using the APIs and workflow definition format provided. An example skeleton of a simple workflow is shown below:

<workflow-definition>
<name>MyName</name>
<version>1</version>
<state>
</state>
<state>
</state>
<task>
</task>
<task>
</task>
</workflow-definition>


Assets, States, Transitions, and Tasks

The key parts of the workflow definition are the asset, states, transitions, and tasks. The asset is whatever piece of content is being reviewed and approved in the workflow. States represent stages of the workflow, such as “created,” “rejected,” or “approved.” Transitions occur between states and indicate what the next state should be. Tasks are steps in the workflow that require user action.

Example State


<state>
 <name>MyState</name>
 <initial>true</initial>
 <actions>
  <action>
        <name>SomeAction</name>
        <execution-type>onEntry</execution-type>
        <script>
           <![CDATA[
    // some javascript code here
       ]]>
       </script>
       <script-language>javascript</script-language>
       <priority>7</priority>
  </action>
 </actions>
 <transitions>
   <transition>
        <name>Task1</name>
        <target>task1</target>
        <default>true</default>
   </transition>
 </transitions>
</state>


Notable Elements Options
<actions> Defines actions to be taken upon entering state.
<transitions> Defines possible transitions out of this state.
<script-language> Groovy, JavaScript, Python, Ruby.
<priority> Integer; controls execution order of actions.
<execution-type> onEntry, onAssignment, onExit.
<template-language> text, velocity, freemarker.
<notification-type> email, im, private-message.


Example Task

 <task>
       <name>MyTask</name>
       <due-date-duration>12</due-date-duration>
       <due-date-scale>day</due-date-scale>
       <actions>
         <notification>
               <name>A Notification</name>
               <execution-type>onAssignment</execution-type>
               <template>You have a new task</template>
               <template-language>text</template-language>
               <notification-type>email</notification-type>
         </notification>
       </actions>
       <assignments>
         <roles>
               <role>
                       <role-type>community</role-type>
               <name>Community Administrator</name>
           </role>
         </roles>
       </assignments>
       <transitions>
         <transition>
               <name>Transition1</name>
               <target>state1</target>
               <default>true</default>
     </transition>
          <transition>
                 <name>Transition2</name>
                 <target>state2</target>
                 <default>false</default>
          </transition>
     </transitions>
</task>


Notable Elements Options
<due-date-duration> Defines when the task is due.
<ue-date-scale> Second, minute, hour, day, week, month, year.
<roles> Users who have this role can be assigned this task.
<role-type> Regular, community, organization.
Section 10

Liferay Administration

Portal Properties

Liferay uses the concept of overriding the defaults in a separate file rather than customizing the default configuration file. The default configuration file is called portal.properties and it resides inside of the portal-impl.jar file. This .jar file is located in Liferay Portal’s WEB-INF/lib folder. If you have a copy of the Liferay source code, this file can be found in portal-impl/src. The file used to override the configuration is portal-ext.properties. This file can be created in your Liferay Home folder or anywhere in the application server’s classpath.

System Settings

Many Liferay components have configuration options in the Control Panel > System Settings section. These configuration updates get registered in the Configuration_ table in the DB and this overrides any properties introduced via portal-ext.properties file (where applicable). The same configuration options can be introduced via configuration files in the {liferay-home}/osgi/configs folder.

Database Setup

Out of the box, Liferay bundles are configured to use HSQLDB, which should only be used for development or demo purposes. You cannot use this database in production.

For production use, Liferay supports MySQL, Microsoft SQL Server, Oracle Database, IBM DB2, PostgresQL, and Sybase. Liferay can also connect to Apache Derby, Firebird, Informix, Ingres, or SAP DB. To use these databases, the database and user with appropriate access must be created and the appropriate JDBC driver must be available in your app server. Consult your database documentation for details on syntax and how to create databases and users.

To use a particular database, you must set the following four properties in your portal-ext.properties.

MySQL Example

1. jdbc.default.driverClassName=com.mysql.jdbc.Driver
2. jdbc.default.url=jdbc:mysql://localhost/lportal?
                       useUnicode=true&characterEncoding=UTF-
                       8&useFastDateParsing=false
3. jdbc.default.username=
4. jdbc.default.password=

Oracle Example

jdbc.default.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.default.url=jdbc:oracle:thin:@localhost:1521:xe
jdbc.default.username=lportal
jdbc.default.password=lportal

It’s also possible to delegate this configuration to the application server through a DataSource by using the following property:  jdbc.default.jndi.name=NameOfDataSource 

Section 11

App Server Configuration

Liferay is supported on Geronimo, GlassFish, JBoss, Jetty, JOnAS, Oracle, Resin, Tomcat, WebLogic, and WebSphere. Consult your app server documentation for details on configuration. The following table lists common files that are involved in configuring your app server.

Tomcat 8.x Location
Global libraries ${TOMCAT_DIR}/lib/ext
Portal libraries ${TOMCAT_DIR}/webapps/ROOT/WEB-INF/lib
Primary configuration ${TOMCAT_DIR}/conf/server.xml
Primary log files ${TOMCAT_DIR}/logs/catalina.out
JBoss 7.x Location
Default instance directory ${JBOSS_DIR}/server/standalone
Global libraries ${JBOSS_INSTANCE_DIR}/lib/ext
Portal libraries ${JBOSS_INSTANCE_DIR}/deployments/ROOT.war/WEB-INF/lib
Primary configuration ${JBOSS_INSTANCE_DIR}/configuration/jboss-service.xml
Primary log files ${JBOSS_INSTANCE_DIR}/log/server.log ${JBOSS_INSTANCE_DIR}/log/boot.log

Troubleshooting and Debugging

The following items should be checked when troubleshooting a problem.

Item Notes
Log files Log files for several app servers are listed above. These should be checked for warnings, errors, Java stack traces, etc.
Log settings Liferay uses the Apache Log4j library to perform all of its logging operations. See below on how to configure log settings.
JMX Liferay provides out-of-the-box JMX MBeans, which allow introspection into the runtime; for example, to identify and isolate problematic behavior, such as poor cache performance or slow portlet rendering.
Debug

To attach a Java debugger to Liferay, you must start the JVM with special properties. Some servers have done this for you; for example, to start Tomcat under a debugger, run “bin/catalina.sh jpda start”

Other servers may need the JVM properties added manually. A typical set of properties is:

-Xdebug

-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

Hot Tip: JBoss includes its own Log4j configuration that may override Liferay’s configuration. The JBoss Log4j configuration file can be found in $JBOSS/server/default/ conf/log4j.xml. Read the JBoss documentation for details.

Section 12

Portal Properties

Listed below are several properties and descriptions that can be used to configure Liferay. These settings belong in your portal-ext.properties file.

Property Name Description and Examples

liferay.home

Default: Depends on app server

Specifies the root of Liferay’s working directory /configuration. Example: /var/lr-home

portal.ctx

Default: /

Specifies the path of the portal servlet context. If you change this, you must also change the setting in web.xml Example: /mysite

jdbc.default.jndi.name

Default: Not set

Set the JNDI name to look up the JDBC data source. If none is set, Liferay will attempt to create the JDBC data source based on the properties prefixed with jdbc. default. Example: jdbc/LiferayPool

jdbc.default.driverClassName

jdbc.default.url

jdbc.default.username

jdbc.default.password

Defaults: settings for HSQL

Database configuration options for creating the Liferay Database connection pool.

company.default.web.id

Default: liferay.com

Default Web ID. Omni administrators must belong to this company. Example: mycompany.com
Section 13

Developing for Liferay

You can develop many things both for and in Liferay: portlet OSGi modules (including ServiceBuilder OSGi modules), fragments, themes, layout templates, and more.

Gradle Workspace

Liferay DXP has introduced new toolings on the development environment, but Ant- or Maven-based plugin development environments are still supported. To get the full benefit of the OSGi module build environment, the following items need to be installed and configured according to the documentation. Many options of Blade or Gradle tasks are available, but the core behavior is same. Portlet OSGi modules have clean build and deploy tasks. Service Builder OSGi modules have clean buildService and deploy tasks.

Creating and Deploying New “Hello World” OSGi Module

Once all tools (Gradle and Blade CLI) are ready, a new project can be created and deployed using this Blade command:

$ cd modules; blade create -t mvc-portlet -p com.example.helloworld -c HelloWorld hello-world
$ cd hello-world; blade deploy
//Or
$ gradle deploy // if Gradle is installed in global path of your development environment


Anatomy of a Portlet Project

Anatomy of OSGi Module Portlet

The following directories and files are created when an OSGi module portlet is created by Blade CLI.

Folder Description
src This folder is the “root” of your application.
src/main/java Java packages including the controller class, action classes, resource action classes, etc.
src/main/resources Module resources.
src/main/resources/content Module-specific Language.properties.
src/main/resources/META-INF/resources UI components such as JSP or JavaScript files.
bnd.bnd Descriptor file to create an OSGi module. This file is the foundation of MANIFEST.MF, which controls the behavior of the OSGi module (dependency export/import) within the OSGi container.
build.gradle Gradle build definition file that includes modules build dependencies, gradle tasks etc.

Liferay Fragments

Fragments OSGi Module

Fragments are similar to hooks, but use OSGi technology. They’re designed for overriding Liferay’s JSP files.

Folder Description
src This folder is the “root” of your application.
src/main/resources Module resources.
src/main/resources/META-INF/resources UI components such as JSP files to override using the same path defined in the target OSGi module to override.
bnd.bnd

Descriptor file to create an OSGi module. This file is the foundation of MANIFEST.MF, which controls the behavior of the OSGi module (dependency export/import) within the OSGi container. Fragment-Host needs to be defined in this file with a correct target module bundle-version. The fragment won’t be effective if bundle-version doesn’t match.

Fragment-Host: com.liferay.journal.web;bundle-version="1.4.0"

build.gradle Gradle build definition file that includes module build dependencies, Gradle tasks, etc.

JSP File Override

This allows overriding of any JSP from the core of Liferay by using the same paths Liferay uses within the specified directory. Use with care:

<hook>
<custom-jsp-dir>/META-INF/custom_jsp</custom-jsp-dir>
</hook>

Then, create custom JSPs:

/META-INF/custom_jsps/html/portlet/blogs/view.jsp
/META-INF/custom_jsps/html/portlet/calendar/week.jsp


Services

By wrapping services, it’s possible to extend any core Liferay service method to perform additional operations or replace the default operations.

<hook>
 <service>
       <service-type>
         com.liferay.portal.service.UserLocalService
       </service-type>
       <service-impl>
         com.liferay.test.hook.service.impl.MyUserLocalServiceImpl
       </service-impl>
 </service>
</hook>

Liferay Themes

Themes are plugins and are therefore hot-deployable, just like portlet plugins. You can use plugins to build your themes automatically so that they can be deployed to any Liferay instance. The Plugins SDK packages a theme into a .war file just like a portlet, and this .war file can then be hot-deployed to Liferay. However, Liferay DXP has introduced a set of new toolings to build themes and layout templates modules. To generate themes and successfully deploy them using the new toolings, this documentation will have to be followed. Also, install Node.js, Gulp, and Liferay Theme Generator.

Anatomy of a Theme

PathWithin Theme Description
gulpfile.js Gulp JavaScript library for Gulp build tasks.
liferay-theme.json Liferay theme deployment properties for app server path, deployment path, etc.
package.json Liferay theme build properties defining theme name, dependencies, version, etc.
node_modules Modules from Node.js for theme-building.
src/css Folder to host CSS classes for the theme.
src/fonts Folder to host fonts libraries for the theme.
src/images Folder to host images for the theme.
src/js Folder to host JavaScript for the theme.
src/templates Folder to host FreeMarker template files for the theme.
src/WEB-INF

Folder to host

liferay-layout-templates.xml (if layout template is included in the theme)

liferay-look-and-feel.xml

liferay-plugin-package.properties

Service Builder

Service Builder is a source code generation tool built by Liferay to automate the creation of interfaces and classes for database persistence and local and remote services. This is useful when developing data-driven applications that make frequent calls to the underlying database.

A “service” in Liferay is simply a class or set of classes designed to handle retrieving and storing data classes. A local service is used by code running in the local instance of Liferay, while a remote service can be accessed from anywhere over the internet or your local network. Remote services support SOAP, JSON, and Java RMI.

Image title

Sample Service

Services are defined by creating a service.xml file. Once defined, source code can be generated for the persistence and data access/transfer layers of your data-driven app. An example:

<service-builder package-path="com.sample.portlet.library">
 <namespace>Library</namespace>
 <entity name="Book" local-service="true" remote-service="true">
       <!-- PK fields -->
       <column name="bookId" type="long" primary="true" />
       <!-- Group instance -->
       <column name="groupId" type="long" />
       <!-- Audit fields -->
       <column name="companyId" type="long" />
       <column name="userId" type="long" />
       <column name="userName" type="String" />
       <column name="createDate" type="Date" />
       <column name="modifiedDate" type="Date" />
       <!-- Other fields -->
       <column name="title" type="String" />
 </entity>
</service-builder>


New in OSGi Service Builder Module
The same API and Service package concept is applied in OSGi Service Builder module but they are generated as separate .jar files, service-builder-name-api.jar and service-builder-name-service.jar, where the API .jar module contains all interfaces and static utility classes that can be accessed by other modules if needed and the service .jar module contains all the implementations exposed via the API .jar module.

Artifact Name Description
sample-common-service-api

An OSGi module with interfaces and/or static utility classes. Other modules in the same OSGi container communicate through the API module.

The bnd.bnd file from this module exposes any services that need to be consumed by other modules in the same OSGi container.

sample-common-service-service An OSGi module with implementations of all services built from service.xml.

Generating the Code

$ gradle buildService
Or
$ blade buildService


Social Tools and Activity Streams

Liferay’s portal, content, and collaboration frameworks are tied together using a rich suite of social features. For developers, plugging social software into Liferay can be achieved in many ways; for example, using the native Social Relationship API for managing relationships between users (via the com.liferay.portlet. social package), interacting with the Activity Stream (via the SocialActivity model), calculating and visualizing Social Equity participation and contribution values, or dropping OpenSocial gadgets onto a page and managing them via Liferay’s Control Panel.

Service Access Policy

RESTful APIs that we can expose via Service Builder can have individualized service access policies. Each API call can be specifically exposed via Service Access Policy.

Image title

Section 14

ElasticSearch

Liferay Portal is an open-source project, so you won’t be surprised to learn that the default search engine that ships with Liferay Portal is also an open-source project. Elasticsearch is a highly scalable full-text search and analytics engine that ships with Liferay Portal.

By default, Liferay Portal runs Elasticsearch as an embedded search engine, but it’s only supported in production locally or remotely as a separate server or cluster. This guide walks you through that process.

If you’d rather use Solr, it’s also supported. See here for information on installing and configuring Solr.

To get up and running quickly with Elasticsearch as a remote server, refer to this article, which has basic instructions for installating and configuring Elasticsearch in a single server environment. It includes more details and information on clustering and tuning Elasticsearch. You’ll learn to configure your existing Elasticsearch installation for use in Liferay Portal production environments.

If you’ve come here looking for information on search engines in general, or the low level search infrastructure of Liferay Portal, refer instead to this tutorial.

Embedded vs. Remote Operation Mode

When you install Liferay Portal, there’s an embedded Elasticsearch already installed. In embedded mode, Elasticsearch search runs with Liferay Portal as a library in the same JVM. This is done by default to make it easy to test-drive Liferay Portal with minimal configuration. Running Elasticsearch and Liferay Portal in the same process has drawbacks:

  • Your Elasticsearch configuration uses the same JVM options as Liferay Portal.
  • Liferay Portal and Elasticsearch compete for resources.
  • You wouldn’t run an embedded database like HSQL in production, and you shouldn’t run Elasticsearch in embedded mode in production either. Instead, you want your Liferay Portal installation to run alongside Elasticsearch. This is called remote operation mode as a standalone server or a cluster of server nodes.

For detailed Elasticsearch configuration information, refer to the Elasticsearch documentation.

The name of your Elasticsearch cluster is important. When you’re running Elasticsearch in remote mode, the cluster name is used by Liferay Portal to recognize the Elasticsearch cluster.

Section 15

Audience Targeting

Liferay provides the ability to segment your audience into user segments and show tailored content to users based on their segment. It is available as a Marketplace App for 6.2 CE customers or Liferay 7 DXP customers. Segmentation of users can be done on multiple attributes including location, age, gender, user's social media profile, etc.(see screenshots below). Liferay also provides an API for developers to create user segments based on any other attribute that’s not supported out-of-the-box. In addition to segmenting and targeting content to user segments, audience targeting allows site admins to create campaigns, track user actions, and generate reports. More information on Liferay DXP Audience Targeting can be found here.

Image title

Image title

Image title

Image title

Image title

Image title

Section 16

More Information

For up-to-date and in-depth information, please refer to the official documentation for Liferay here.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}