Blogs
New approach for Liferay sites implementation
Overview
For the many years Liferay theme was the only way for defining the portal appearance. Usually, when a new project started (or customer requested a new site with a brand new design) - development began with a new theme creation. With themes it's possible to define the overall styling and the basic page structure. Also, we can define the configuration options with theme settings, and theme variations with color schemes. We can import resources with theme's resource importer, or use the theme inheritance to build the hierarchies for related themes.
Then, in the latest versions Liferay introduced a new approach for site creation. Custom themes were not required anymore. And, instead, a brand new features were introduced: Master Pages, Fragments and StyleBooks. Honestly, at the beginning I was a bit sceptical about such an approach. In my opinion, such features could successfully complement the custom theme, but not actually replace it.
But, recently we implemented two different sites for our customer (both of sites were content-based).
For the first one we used the well-known approach. We created a theme, defined the theme settings, and implemented the page structure in a theme (header/footer,etc.). But some time after, we were asked questions from the customer, like: how can I modify this thing or how can I modify that thing? Sometimes we explained how to make the changes, but sometimes we had to answer: “You can’t modify this, this is a part of the theme's code, we need to make code changes and re-deploy”. And the customer was surprised - “Why? Liferay is so flexible, why can't I make these changes directly on the portal?”. And added “We have code freeze, we’re not allowed to deploy anything”. For big clients sometimes there is too much bureaucracy, and changing a single line of code (even theme’s code) will lead to the entire cycle of deployments to DEV/QA/PROD, regression testing etc.
Considering this, we decided to build a new site with a new approach. We created custom fragments for header and footer, created Master Pages for basic page templates, implemented widget templates for navigation, and configured the search results page. Everything was ready in less than in a week, and no deployment was required. With the LAR files we could easily move the new site between the environments.
Site Implementation Approaches
As mentioned above, there are two ways for implementation the site's appearance: theme-based and theme-less. See the comparison below (pros highlighted as bold):
Theme-Based Approach |
Theme-Less Approach |
|
Page structure is staticly defined in theme
|
Page structure can be defined directly on portal (e.g. with Master Pages)
|
|
All code is stored in a single place (Git)
|
Code is scattered across different components on portal: fragments, widget templates, etc.
|
|
Version history is supported (considering theme's code is stored in Git)
|
No version history (e.g. can't revert widget template to a previous state after an unintentional corruption)
|
| Deployment is required | No deployment required, just configuration |
| Strong front-end development skills required for | Less development skills required, mostly configuration |
| Anything can be styled in a theme | Limited options for styling, fonts, colors, etc. |
| Becomes deprecated | Modern Liferay Features are used (Master Templates, Content Pages, Fragments, StyleBook) |
| Not recommended in most cases | Recommended by Liferay |
Each of approaches has it's own pros and cons, and can be used in different cases. But, generally "theme-less" one wins - because it's dynamic, recommended by Liferay, and uses the modern features, on which the platform development team invests the most of resources.
"Code-Less" definition
"Code-less" here means that all the site implementation is performed directly on portal. No custom theme and deployment is required. But, some code is still needed: HTML/CSS/JS code for custom fragments, Freemarker code for custom widgets templates. Thus, it's a low-code, theme-less and deployment-less site implementation.
Sample site overview
As an example, we'll build a "Learning Center" site, similar to the https://learn.liferay.com/
Welcome page will display the welcome message, search bar and a link to Learning Center home page. There should be external links, language switcher and profile in the header. Footer will also have some links and social icons.
Home page will display the left navigation for navigation between chapters/pages. Search will be placed to the header. There will be a breadcrumb and chapters navigation in the content section.
Chapter page should display the chapter information and page navigation in the content section.
Finally, the content page should display the actual content.
Header Implementation
Header for the site can be implemented as a custom Fragment. Fragments not only provide customizable pieces of content, but can also include embedded widgets or even drop zones, and have the configuration options.
Header's fragment HTML can be the implemented like this:
<div id="header" class="d-flex justify-content-between py-2 mx-2 mx-2">
<div class="d-flex justify-content-start">
<!-- Logo and Header-->
<a href="/web/learning-center">
<img alt="LC Logo" src="" class="h-75" data-lfr-editable-type="image" data-lfr-editable-id="lc-logo"
/>
<h2 data-lfr-editable-type="rich-text" class="px-2" data-lfr-editable-id="lc-header">
Header
</h2>
</a>
</div>
<div class="d-flex justify-content-end">
<div class="px-2">
<!-- Navigation and Search -->
<lfr-drop-zone></lfr-drop-zone>
</div>
<div class="px-2">
<!-- Language Switch -->
[#if configuration.showLanguage]
[@liferay_portlet["runtime"]
portletName="com_liferay_site_navigation_language_web_portlet_SiteNavigationLanguagePortlet"/]
[/#if]
</div>
<div class="px-2">
<!-- User Account -->
[#if configuration.showPersonalBar]
[@liferay_portlet["runtime"]
portletName="com_liferay_product_navigation_user_personal_bar_web_portlet_ProductNavigationUserPersonalBarPortlet"/]
[/#if]
</div>
</div>
</div>
Within this small code snipped the following fragment features are used:
- Editabled fields - for header logo/image, with data-lfr-editable-type attributes;
- Embedded widgets - for language switcher and user account. Note: I use liferay_portlet["runtime"] tag library here, because these widgets are not available with <lfr-widget-xxx tag.
- Embedded drop zone - for navigation and search section, to make them more dynamic.
- Configuration options - for toggling the visibility of language/account widgets, see the configuration file.
Footer Implementation
For the footer we can also use a custom fragment. But we can make it even more "generic" by defining the footer's structure and adding the drop zones, see:
<footer id="footer" role="contentinfo" class="container-fluid py-2">
<div class="row">
<div class="col-md-2">
<!-- Logo and Header-->
<a href="/web/learning-center">
<img alt="Liferay Logo" class="h-50" data-lfr-editable-type="image" data-lfr-editable-id="liferay-logo" />
<h2 data-lfr-editable-type="rich-text" data-lfr-editable-id="liferay-header">Liferay</h2>
</a>
</div>
<div class="col-md-8">
<!-- Navigation -->
<lfr-drop-zone></lfr-drop-zone>
</div>
<div class="col-md-2">
<!-- Social Links -->
<lfr-drop-zone></lfr-drop-zone>
</div>
</div>
</footer>
Here we also define the configurable logo image and title, and add two drop zones: for navigation and for social links.
Header Menu Implementation
External links in the header can be created as a "Link to URL" Liferay pages (with appropriate URL in page configuration). We can add a custom navigation menu "Top Links" and group those pages together here:
Master Pages Implementation
Now it's time to introduce the Master Pages. Master Page Templates provide a way to define the page structure, which was previously a part of theme's implementation. Master page is a "basic template" for pages. Regular page templates and individual pages can be created then based on a master page. Master page has a pre-defined "DropZone" element, which can't be removed, but can be placed in any place on a page, together with the manually added elements. On the pages, created from master page, only the "DropZone" area is editable, other part of page is static, as it's defined in a master page.
"LC Basic Page" Implementation
We can create a "LC Basic Page" template with a custom header and footer fragments:
In both header and footer fragment we can select logo icon and type the heading text (using the fragment's editable fields).
In the header fragment we can add a "Navigation Menu" widget to a fragment's DropZone, and configure it to display the "Top Links" navigation menu, created above.
For the footer we can add a grid, and place the editable links. In the right section we can add the pre-defined "Social" fragment, and configure the appropriate links.
"LC Page with Left Nav" Implementation
We can create a new "LC Page with Left Nav" master page for the pages with the left navigation. We can make a copy of "basic" one, created above, and make the following adjustments:
- add a grid into the middle section;
- add a "Navigation Menu"to the left column. Note: navigation should be configured to use a custom widget template "LEFT_NAV", created in the next section.
- move DropZone to the right column;
- add a "Breadcrumb" widget above the DropZone;
- add a "Search Bar" widget to the header's DropZone, right to the navigation.
Widget Templates Implementation
Widget Templates are used for customization the portlet's appearance. The "Navigation Menu" widget has some pre-defined widget templates (which can be discovered in the "Global" site on portal). But when a new structure for navigation is required - a custom widget template can be implemented. It's a best practice to create a custom template as a copy of out-of-the-box one, and make the custom changes on top of it.
"LEFT_NAV" Widget Template
Left navigation should display the menu from the current page, and optionally display a "Go Back" button to navigate a level up in site navigation. It can be implemented like this.
After implementation, this widget template should be selected in the "Navigation Menu" configuration on the "LC Page with Left Nav" master page.
"CHAPTER_NAV" Widget Template
Chapter navigation should be shown inside the content of parent page, and display the navigation boxes with child / sub-child pages, like we see on the learn.liferay.com:
Code for chapter navigation can be implemented like this:
<div id="${navbarId}">
<#if layoutNavItem.hasBrowsableChildren()>
<div class="sections-wrapper">
<#list layoutNavItem.getChildren() as nav_child>
<div class="section-card">
<div class="autofit-row autofit-row-center">
<div class="autofit-col autofit-col-expand">
<a href="${nav_child.getURL()}">
<h4 class="sidebar title">${nav_child.getName()}</h4>
</a>
<#if nav_child.hasBrowsableChildren()>
<ul class="subsection">
<#list nav_child.getChildren() as nav_sub_child>
<li>
<a href="${nav_sub_child.getURL()}">
${nav_sub_child.getName()}
</a>
</li>
</#list>
</ul>
</#if>
</div>
</div>
</div>
</#list>
</div>
</#if>
</div>
(see the complete version on GitHub).
Page Templates Implementation
As far, as we created already the required Master Pages and Widget Templates - we can start with the pages/content creation. But we can make a step forward to simplify the individual page creation process, and create page templates for specific pages (in our case - welcome, chapter, content and search templates):
For example, for the chapter template we can add a header, paragraph, and navigation menu (already configured to display the chapter navigation) to the content section (DropZone).
Then, on individual pages, we'll have to only change the values for the editable fields (but will be also able to add new elements, if needed).
Site Pages Creation
Now it's time to setup the site pages and content. We can create site pages based on the page templates created in the previous chapter. We may have a page tree, like this:
Once pages are created - we'll finally see the resulting site:
(but do not judge the styling quality, I'm not a designer ?)
Style Books
With a custom StyleBook we can configure the styling options (colors, spacing, fonts, etc.) and define the styling according to the site's requirements. We may have different style books with different styling options, and apply them when we need to modify the site's appearance.
Note: style books load configuration options (token definitions) from a theme (default "Classic" theme in our "code-less" approach). When more configuration options are required - a custom theme is still needed, and custom token definitions can be defined in this case.
Conclusions
We have created a sample site with a "code-less" approach, using the Liferay features:
- Fragments;
- Master Pages;
- Navigation Menus;
- Widget Templates;
- Page Templates;
- Content Pages;
- Style Books.
We have compared two ways of site creation: "theme-based" and "theme-less". Each of them has it's own pros and cons. Theme-less approach is more modern and dynamic. And theme approach is more powerful. Actually, both approaches can be also used together: with a custom theme we can define the basic styling and custom options for style books; with master page templates we can define the portal page structure.
Source code for templates: https://github.com/liferay-apps/liferay-codeless/tree/master/modules/learning-center
See you on /dev/24
Enjoy ?

