Custom Search Filter
Introduction
The Advanced Search Perspective allows you to search on all fields of your documents types. Out-of-the-box, the Advanced Search Perspective shows filters for generic document metadata fields such as document type and location. The Advanced Search Perspective can easily be customized by adding more search plugins that filter on specific properties of your documents types.
You can either configure the built-in generic property filter plugin for simple extra filtering purpose, or implement your own filter plugin by extending the generic property filter plugin or implementing a new filter plugin.
Configuring the Generic Property Filter
The Generic Property Filter allows the user to enter a text string that is used as a filter on a property of type String or Long. Below you see an example filtering on the document Title:
To configure this, first you need to determine the property in your content model you want to filter on; in this case the filter property is the hippogogreen:title property. Then, you can add the following repository configuration under /hippo:configuration/hippo:frontend/cms/cms-advanced-search node:
/hippo:configuration/hippo:frontend/cms/cms-advanced-search: /titlePropertyFilter: jcr:primaryType: frontend:plugin plugin.class: com.onehippo.cms7.search.frontend.filters.GenericPropertyFilterPlugin wicket.id: ${search.extensions} wicket.model: ${model.search} filterPropertyName: hippogogreen:title filterPropertyType: text
Also, please note that the labels ("Title Filter" and "Title") shown in the screenshot above can be configured as repository resource bundle labels.
To do that, load the following translations. The GenericPropertyFilterPlugin uses the name of the initialize item (titlePropertyFilter) from the initialize item above to look up the translations for the property name and title field below:
{ "hippo:cms": { "advanced-search-filters": { "en": { "titlePropertyFilter.propertyName": "Title", "titlePropertyFilter.title": "Title Filter" }, "nl": { "titlePropertyFilter.propertyName": "Titel", "titlePropertyFilter.title": "Titel Filter" } } } }
Extending the Generic Property Filter
The built-in generic property filter, com.onehippo.cms7.search.frontend.filters.GenericPropertyFilterPlugin, is a simple filter plugin implementation which allows users to enter a text string that is then used to filter the search result based on a specific document property.
For simplicity, the generic property filter plugin can handle only two property types currently:
- String : If the specified property is type of String, then the filter uses "jcr:contains" operator to filter the search result.
- Long: If the specified property is type of Long, then the filter uses "Equals" operator to filter the search result.
For your information, the above is implemented like this:
@Override public List<Constraint> getConstraints() { List<Constraint> constraints = new LinkedList<Constraint>(); if (StringUtils.isNotBlank(getFilterPropertyName()) && StringUtils.isNotBlank(getFilterPropertyValue())) { if (FILTER_PROPERTY_TYPE_INTEGER.equals(getFilterPropertyType())) { constraints.add(QueryUtils.integer(getFilterPropertyName()).isEqualTo(NumberUtils.toInt(getFilterPropertyValue()))); } else { constraints.add(QueryUtils.text(getFilterPropertyName()).contains(getFilterPropertyValue())); } } return constraints; }
So, if you want a more sophisticated filter plugin based on some other property, then you may create a new class extending the GenericProperyFilterPlugin. In most cases, you can simply override the #getConstraints() method.
Implementing a More Complex Custom Search Filter
If you need a more complex search filter, not just using single property, or using a different input mechanism, then you should implement a custom search filter.
Custom constraint providers can be implemented by creating a plugin that implements the IConstraintProvider interface:
MyDocumentsPlugin.java:
package org.example; import java.util.LinkedList; import java.util.List; import com.onehippo.cms7.search.frontend.ISearchContext; import com.onehippo.cms7.search.frontend.constraints.IConstraintProvider; import com.onehippo.cms7.search.frontend.constraints.YesNoNeither; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.CompoundPropertyModel; import org.hippoecm.frontend.plugin.IPluginContext; import org.hippoecm.frontend.plugin.config.IPluginConfig; import org.hippoecm.frontend.service.render.RenderPlugin; import org.hippoecm.frontend.session.UserSession; import org.onehippo.cms7.services.search.query.QueryUtils; import org.onehippo.cms7.services.search.query.constraint.Constraint; import org.onehippo.cms7.services.search.query.constraint.TextConstraint; public class MyDocumentsPlugin extends RenderPlugin implements IConstraintProvider { private String authoredByMe; public MyDocumentsPlugin(final IPluginContext context, final IPluginConfig config) { super(context, config); Form form = new Form("form", new CompoundPropertyModel(this)); form.add(new YesNoNeither("authoredByMe") { @Override protected void onModelChanged() { super.onModelChanged(); updateSearchResults(); } }); add(form); } private void updateSearchResults() { ISearchContext searcher = getPluginContext().getService( ISearchContext.class.getName(), ISearchContext.class); searcher.updateSearchResults(); } @Override public List<Constraint> getConstraints() { List<Constraint> constraints = new LinkedList<Constraint>(); if (authoredByMe != null) { final TextConstraint iamTheUser = QueryUtils.text("hippostd:holder").isEqualTo( UserSession.get().getJcrSession().getUserID()); if ("yes".equals(authoredByMe)) { constraints.add(iamTheUser); } else { constraints.add(QueryUtils.not(iamTheUser)); } } return constraints; } @Override public void clearConstraints() { authoredByMe = null; redraw(); } }
The YesNoEither component is provided by the advanced search plugin api; the ISearchContext can be used to trigger an update of the shown results.
As shown, the plugin implements the constraint provider interface. It's methods are invoked when a new query is built ( getConstraints) or all constraints should be reset ( clearConstraints).
The markup to go along with this code:
MyDocumentsPlugin.html:
<html xmlns:wicket="http://wicket.apache.org/"> <wicket:panel> <div class="hippo-advanced-search-filter"> <form wicket:id="form"> <ul> <li class="filter"> <h3>Author</h3> <ul> <li style="clear: both; margin-top: -15px;"> <span class="hippo-advanced-search-radio"> <span class="hippo-advanced-search-select"> <wicket:message key="yes">Y</wicket:message> </span> <span class="hippo-advanced-search-select"> <wicket:message key="no">N</wicket:message> </span> <span class="hippo-advanced-search-reset"></span> </span> </li> <li style="clear: both;"> Authored by Me <span wicket:id="authoredByMe" class="hippo-advanced-search-radio"> <input type="radio" wicket:id="authoredByMe-yes" class="hippo-advanced-search-select"/> <input type="radio" wicket:id="authoredByMe-no" class="hippo-advanced-search-select"/> <span class="hippo-advanced-search-reset"> <img wicket:id="authoredByMe-reset"/> </span> </span> </li> </ul> </li> </ul> </form> </div> </wicket:panel> </html>
These plugins need to be registered in the advanced search perspective at /hippo:configuration/hippo:frontend/cms/cms-advanced-search:
/hippo:configuration/hippo:frontend/cms/cms-advanced-search: /myDocuments: jcr:primaryType: frontend:plugin plugin.class: org.example.MyDocumentsPlugin wicket.model: ${model.search} wicket.id: ${search.extensions}
Make sure that if you add the MyDocumentsPlugin.java and MyDocumentsPlugin.html to the cms project that you make sure that the .html (and .properties if you I18N your custom search filter) end up in the jar. You can do this by making sure the cms pom.xml build contains :
<build> <finalName>cms</finalName> <resources> <resource> <filtering>false</filtering> <directory>${basedir}/src/main/java</directory> <includes> <include>**/*.html</include> <include>**/*.properties</include> </includes> </resource> </resources> .....
If you want your plugin to be ordered at a higher location, just move your myDocuments node up in the repository configuration at /hippo:configuration/hippo:frontend/cms/cms-advanced-search
The end result: