-
Templating and Integration Guide
- Part 1: Concepts
- Part 2: Modules
- Part 3: Templates and Studio
- Part 4: Content Definitions and Views
- Part 5: Advanced Techniques
- Part 6: Setting up an integration environment
- Part 7: Step by step integration
- Further reading and resources
In practice: creating a custom search component
Objective
The goal of this little example is to create a custom search component. Once dropped in a page, this component will display a form composed of a text field (full text search string) and a drop-down list of constraints to limit the search to a certain type of nodes. Upon form submit, the component will return in the same page the search results.
Overview
Before starting the how-to, let’s note that there are several ways to implement this module.
The first approach would be to base everything on one single component that includes the form and the display zone in the same view.
The second approach could be to use two different components: one for the form request, and a second one to display results.
The best approach is clearly the second one as it gives much more flexibility on the long term, and will allow easier debugging if necessary.
The idea is to create a form in the JSP of the first component to perform do the search, with a form to be submitted, that will store parameters in the request. The second component will retrieve the parameters, execute the query using them, and display the results.
We will also illustrate parameters useful to limit the number of results, or specify a page redirection after submit.
Creating the module
Let’s now create a folder with the name of our choice, for this example the module will be named myCustomSearch, which will include all folders and files related to the module.
Under the myCustomSearch folder we create the following tree of folders:
![jahia6_6_integration_en-64.png [image]](/files/live/sites/jahiacom/files/documentation/6.6/en/images/IntegrationGuide/jahia6_6_integration_en-64.png)
The folders and their importance are detailed here:
- src : Source folder that includes all files and folders
-
main: folder that contain the files to be packaged
- java (optional folder, not illustrated above) : folder that includes all Java class source files related to the module)
-
webapp: contains all core files of the module
- META-INF: include definitions file (and optionally Spring Framework configurations files)
- resources: includes all resources bundles for multi-language support
- WEB-INF: include web.xml file (optionally macro files)
- site: folder for documentation related to the module
Then we create a web.xml file in the WEB-INF folder with this content:
![jahia6_6_integration_en-65.png [image]](/files/live/sites/jahiacom/files/documentation/6.6/en/images/IntegrationGuide/jahia6_6_integration_en-65.png)
This is used to specify the name of the module.
The next step is to create a definitions.cnd node type definition file in META-INF folder
As we need two different node types, one for the query and other one to receive the results, the definitions file contains the following definitions:
![]()
The mixins used are:
- jnt:content: specifies that the node is a basic content
- jnt:list: marks the component as a list, allows pagination and other special features associated to lists
- jmix:queryContent: specifies that this component will appear in the query content category in left panel
To build the views for the components, you can simply copy the contents from the jnt_simpleSearchForm and the jnt_searchResults directories from the search module in the directory
jahia/modules/search.
Next, to package and deploy your module, you need to have a proper Maven module project. Here is an example of the pom.xml Maven project file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>jahia-modules</artifactId>
<groupId>org.jahia.modules</groupId>
<version>6.5-SNAPSHOT</version>
</parent>
<groupId>org.jahia.modules</groupId>
<artifactId>myCustomSearch</artifactId>
<name>My Custom Search</name>
<packaging>war</packaging>
<description>These is my custom module (myCustomSearch) for running on a Jahia server.</description>
<dependencies>
<dependency>
<groupId>org.jahia.server</groupId>
<artifactId>jahia-impl</artifactId>
<version>6.5-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jahia.server</groupId>
<artifactId>jahia-taglib</artifactId>
<version>6.5-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${war.plugin.version}</version>
<configuration>
<warSourceExcludes>resources/*.properties</warSourceExcludes>
<webResources>
<resource>
<directory>${project.build.directory}/native2ascii</directory>
<targetPath>resources</targetPath>
</resource>
</webResources>
<archive>
<manifestEntries>
<Implementation-Title>${project.name}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Implementation-Vendor>${jahia.manifest.vendor.name}</Implementation-Vendor>
<Implementation-Vendor-Id>${jahia.manifest.vendor.id}</Implementation-Vendor-Id>
<Implementation-URL>${jahia.manifest.vendor.url}</Implementation-URL>
<Specification-Title>${project.name}</Specification-Title>
<Specification-Version>${project.version}</Specification-Version>
<Specification-Vendor>${jahia.manifest.vendor.name}</Specification-Vendor>
<package-name>${project.name}</package-name>
<depends>Default Jahia Templates</depends>
<module-type>module</module-type>
<root-folder>${project.artifactId}</root-folder>
</manifestEntries>
</archive>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
</plugins>
</build>
</project>
The most important tags in the pom.xml file for your module are:
- The artifactId will be used as the package name and upon deployment will be the root folder of your module (here: myCustomSearch)
- The project name (here: My Custom Search) is used to name your project but will also be used to lookup resources files by stripping all space characters (so My Custom Search becomes MyCustomSearch.properties).
In order to properly support internationalization, we now show how to create the resource bundle files. These must be located in the src/main/webapp/resources directory and should have the following names:
- MyCustomSearch.properties (default, usually the same as the English version)
- MyCustomSearch_en.properties (English bundle)
- MyCustomSearch_fr.properties (French bundle)
In order for this example to stay simple, we will just illustrate how to setup two keys in the resource bundles.
In the MyCustomSearch.properties and MyCustomSearch_en.properties, insert:
jnt_myCustomSearch=My custom search
jnt_myResultSearch=My result search
In the MyCustomSearch_fr.properties, insert:
jnt_myCustomSearch=Ma recherche
jnt_myResultSearch=Mes résultats
We now need to provide views for both nodes. We will therefore create one folder per nodetype in the src/main/webapp filter. These folders have the same name as the nodetype, except that the colon “:” character is replaced by an underscore “_” character. Under these folders we create a template type folder called html and finally inside both html folders we create JSP files that have the same name as the nodetype without the namespace prefix. The resulting files should therefore be:
src/main/webapp/jnt_myCustomSearch/html/myCustomSearch.jsp
src/main/webapp/jnt_myResultSearch/html/myResultSearch.jsp
At this point the module folder structure should look like this:
![jahia6_6_integration_en-67.png [image]](/files/live/sites/jahiacom/files/documentation/6.6/en/images/IntegrationGuide/jahia6_6_integration_en-67.png)
Now the structure of the module is complete, we can build it and deploy it in Jahia. We can then finish the work by writing the code for the JSP views.
The myCustomSearch.jsp view
In the form we have two fields, one to select the search category, and the other for the actual keyword search, as illustrated in the source below:
![jahia6_6_integration_en-63.png [image]](/files/live/sites/jahiacom/files/documentation/6.6/en/images/IntegrationGuide/jahia6_6_integration_en-63.png)
Storing parameters in the request
The resulting action of submitting the form points to the same page, but we could have easily have it point to another page. As we will be used request parameters for the search, it is important though that you point to an URL that has the result node in it’s content.
We use a hidden parameter named jcrMethodToCall to force the use of a HTTP GET method, but we could have also simply changed the form method attribute to GET. Yet it is interesting to illustrate this possibility because some Javascript libraries might not give complete control over form submission and this is a way to override it.
The parameter names are defined by the html element’s attribute name, so our parameters are actually named search-categories and search-text.
In the first version of the custom search form we hardcoded the category values, but it would be much more interesting to be able to pick them at component creation time. In order to do so, we will modify the example so that we can retrieve the list of values from a component property. This property has the following definition:
-j:categories (weakreference, category[autoSelectParent=false]) multiple
Our full definitions.cnd file now looks like this:
[jnt:myCustomSearch] >jnt:content, jmix:queryContent
-j:categories (weakreference, category[autoSelectParent=false]) multiple
[jnt:myResultSearch] >jnt:content, jmix:list, jmix:renderableList, jmix:queryContent, mix:title
What the above definition does is that it actually defines a property that will use the category selector to populate the property. We can then build a drop down list that uses the selected values to let the user performing a search query select from the values that were specified at component creation time. The search form must be modified slightly to incorporate the HTML SELECT form field, as in the code below:
<jcr:nodeProperty node="${currentNode}" name="j:categories" var="categories"/>
<template:tokenizedForm>
<form method="post" action="${renderContext.mainResource.node.name}.html">
<input type="hidden" name="jcrMethodToCall" value="get">
<label for="categorySearch">Categories:</label>
<select id="categorySearch" name="search-category">
<option>all</option>
<c:forEach items="${categories}" var="category" varStatus="status">
<jcr:node var="categoryNode" uuid="${category.string}"/>
<option value="${category.string}">${categoryNode.properties['jcr:title'].string}</option>
</c:forEach>
</select>
<label for="textSearch">Text:</label>
<input name="search-text" type="text" id="textSearch"/>
<input type="submit" title="Submit"/>
</form>
</template:tokenizedForm>
The actual values for the HTML SELECT options will be the UUID identifiers of the category nodes, which we will use in the result view to build the corresponding query.
The myResultSearch.jsp view
In order to perform the query, we need to retrieve parameters previously sent by the form in the first module, for that we use the following lines:
${renderContext.request.parameterMap['search-category'][0]}
${renderContext.request.parameterMap['search-text'][0]}
As we will use a list loading mechanism instead of a regular content object, we need to rename the myResultSearch.jsp to myResultSearch.hidden.load.jsp
Now we just have to retrieve these parameters as we saw previously, and build the query:
<%@ taglib prefix="jcr" uri="http://www.jahia.org/tags/jcr" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="utility" uri="http://www.jahia.org/tags/utilityLib" %>
<%@ taglib prefix="template" uri="http://www.jahia.org/tags/templateLib" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="functions" uri="http://www.jahia.org/tags/functions" %>
<%@ taglib prefix="query" uri="http://www.jahia.org/tags/queryLib" %>
<%--@elvariable id="currentNode" type="org.jahia.services.content.JCRNodeWrapper"--%>
<%--@elvariable id="out" type="java.io.PrintWriter"--%>
<%--@elvariable id="script" type="org.jahia.services.render.scripting.Script"--%>
<%--@elvariable id="scriptInfo" type="java.lang.String"--%>
<%--@elvariable id="workspace" type="java.lang.String"--%>
<%--@elvariable id="renderContext" type="org.jahia.services.render.RenderContext"--%>
<%--@elvariable id="currentResource" type="org.jahia.services.render.Resource"--%>
<%--@elvariable id="url" type="org.jahia.services.render.URLGenerator"--%>
<c:if test="${renderContext.request.parameterMap['search-text'][0] != ''}">
<query:definition var="listQuery" limit="10">
<query:selector nodeTypeName="nt:base"/>
<query:descendantNode path="${renderContext.site.path}"/>
<query:fullTextSearch searchExpression="${renderContext.request.parameterMap['search-text'][0]}"/>
<c:if test="${renderContext.request.parameterMap['search-category'][0] != 'all'}">
<query:equalTo propertyName="j:defaultCategory"
value="${renderContext.request.parameterMap['search-category'][0]}"/>
</c:if>
</query:definition>
<c:set target="${moduleMap}" property="editable" value="false" />
<c:set target="${moduleMap}" property="listQuery" value="${listQuery}" />
<c:set target="${moduleMap}" property="subNodesView" value="link" />
</c:if>
As we can see in the above source code, the query is copied into the moduleMap structure, which is then use by the standard list components to display the list of resulting objects.
build your module, deploy it on jahia
mvn install jahia:deploy
then from the studio, select module as module type, pick your module in module list, then deploy it on your web project to have the components available.
Finally, we can drag and drop both components in a page and test them.

