Allow portlet pages to be shown in Liferay Search

In Liferay DXP , Search has been expanded to also allow content pages. This allows the user to be able to find pages as well, and not just content. However, widget/portlet pages are not shown in the Liferay Search Results portlet. I did some research and found a simple solution to allow portlet pages to be included in the search results.

In this article I will provide a way to allow Portlet/Widget pages to be found in Liferay Search.

Why are portlet pages not shown?

All pages use the same underlying entity framework, namely the Layout. Layout is a fully assetized entity, and can be selected in the "Type" facet portlet. However, only content pages are shown when one selects the Page/ Layout entity. How can that happen, when they both use the same underlying entity? Well, to allow different types of pages a 'type' parameter is added to the layout model. Content pages (that allow fragments) are of the type 'content' while widget pages are of the type 'portlet'. I suspected that there was some type of filtering / indexing based on the type of Layout that causes only content pages to be shown and that is exactly what is happening. There is a PreFilterContributor called LayoutModelPreFilterContributor that filters the search query to only show Layout of the type "content". We can see this filter in action when we add a search insight portlet to the page. In the underlying Image you can see that there is a TermsFilter in the query where Layout MUST have type: ["content"].

{"bool":{"must":[{"term":{"entryClassName":{"value":"com.liferay.portal.kernel.model.Layout"}}},{"terms":{"type":["content"]}},{"terms":{"type":["content"]}}]}}

How to allow Portlet Pages in Search Results

The solution is simple, we should try to change this PreFilterContributor to allow Portlet pages as well. Luckily we can make use of pre-filtering as well to add our own logic. We can do this by creating our own PreFilterContributor. This contributor also has to target the com.liferay.portal.kernel.model.Layout indexer. In our own filter we can retrieve the already existing filters that apply to Layout. We have to make sure we target the correct one and then we can add our own type 'Portlet' to the existing filter.


@Component(
	immediate = true,
	property = "indexer.class.name=com.liferay.portal.kernel.model.Layout",
	service = ModelPreFilterContributor.class


public class PortletLayoutModelPreFilterContributor
	implements ModelPreFilterContributor {


	/**
	 * Overrides LayoutModelPreFilterContributor to stop portlet pages from being filtered out
	 * @param booleanFilter
	 * @param modelSearchSettings
	 * @param searchContext
	 */
	@Override
	public void contribute(
		BooleanFilter booleanFilter, ModelSearchSettings modelSearchSettings,
		SearchContext searchContext) {


		List<BooleanClause<Filter>> filters = booleanFilter.getMustBooleanClauses();
		for(BooleanClause<Filter> filter: filters) {
			if(filter.getClause().getClass().equals(TermsFilter.class)) {
				TermsFilter termsFilter = (TermsFilter)filter.getClause();
				if(termsFilter.getValues().length > 0 && termsFilter.getValues()[0].equalsIgnoreCase(LayoutConstants.TYPE_CONTENT)) {
					termsFilter.addValues(new String[] {LayoutConstants.TYPE_CONTENT, LayoutConstants.TYPE_PORTLET});
				}
			}
		}
	}
}

That's pretty much all we have to do. After deploying, we can check the Search Insights portlet again to see whether the MUST filter contains the type 'Portlet':

{"bool":{"must":[{"term":{"entryClassName":{"value":"com.liferay.portal.kernel.model.Layout"}}},{"terms":{"type":["portlet","content"]}},{"terms":{"type":["portlet","content"]}}]}}

As you can see, our type 'portlet' is now added to the allowed Layout types in the search query. Now we can also search for our widget pages. Check out the source code link for a fully working module, and to see which dependencies you need for the module.

Source code

Danielle Ardon

Fullstack developer[email protected]LinkedIn
Meer van Danielle Ardon

Meer artikelen

Composer
Composer 2
Dependency hell
Bash

Use multiple composer versions simultaneously

Valerie Valkenburg
4 minuten lezen
Lees het artikel Use multiple composer versions simultaneously
React
pwa
scraping
json
php

Make an app, scrape the net

Emmanuel Maltete
12 minuten lezen
Lees het artikel Make an app, scrape the net
liferay 7.2
liferay upgrade dxp
liferay
my account
screen navigation
panels

Removing panels from my account in Liferay 7.2

Danielle Ardon
9 minuten lezen
Lees het artikel Removing panels from my account in Liferay 7.2