How to limit portal searches to INavigationRoot
Okay. So what is this all about?
We currently have some major customers that have kind of sub-sites for special topics or products. Since we sometimes need data across those sites and like to re-use components/preferences/users within a Plone instance, we just add a new folder to the Plone instance, bind a skin to it and add an INavigationRoot marker interface (in the ZMI of newer Zope versions).
This gives us (sub)sites that look different from the main site and have their own navigation. There's only one side-effect: If you enter something into the livesearch or use the search form (from within that sub-site), you will end up with a list of results from the main site and even all other sub-sites.
Why is that bad?
Well. In some usecases it might not. But at least for our usecase it is in most cases: We have sites about different topics. Even if there is another document in the main site, that might hit the same needs, most of the time the users will search for quite general keywords, that might be enough to limit the results within the microsite, but not enough for the universe of all the sites within the instance. Apart from the irritation if the site changes its outfit as soon as you click on a result from another microsite
What needs to be changed?
There are 2 templates and 1 script I found useful to customize. (you can also customize the search forms you use and add a hidden field "path" there, but this approach is more general)
- global_searchbox.pt (because it contains paths to the portal root)
- search.pt (which does the search itself and outputs the results)
- livesearch_reply.py (which searches independently from search.pt)
Here we go:
global_searchbox.pt contains 2 offending (yes, they offend me ;) ) lines containing:string:${portal_url}/search;
andstring:$portal_url/search_form
that need to be changed to
string:${context/@@plone/navigationRootPath}/search;
and
string:${context/@@plone/navigationRootPath}/search_form
You could of course also add a hidden "path" input here to limit the search to a path, but we will leave that to search.pt
search.pt is a little nasty to path. We will add some code to it so that it "patches" it's own request.
Thats not nice, but it makes sure that ALL searches that use search.pt go through this modification (including the call to the RSS generation that reside in this template)
The original search.pt starts like this:
<metal:block metal:fill-slot="head_slot">
<link rel="alternate" title="RSS 1.0" type="application/rss+xml"
tal:condition="request/SearchableText|nothing"
tal:attributes="href string:$here_url/search_rss?${request/QUERY_STRING}"/>
</metal:block>
<metal:block fill-slot="top_slot"
tal:define="dummy python:request.set('disable_border',1)" />
<div metal:fill-slot="main"
tal:define="use_types_blacklist request/use_types_blacklist | python:True;
results python:here.queryCatalog(REQUEST=request,use_types_blacklist=use_types_blacklist);
Batch python:modules['Products.CMFPlone'].Batch;
b_size python:30;b_start python:0;b_start request/b_start | b_start;
desc_length site_properties/search_results_description_length;
desc_ellipsis site_properties/ellipsis;
searchterm request/SearchableText|nothing;
use_view_action site_properties/typesUseViewActionInListings|python:();">
We modify this slightly to add some request patching and while we are at it path the call for RSS generation too.
<metal:block metal:fill-slot="head_slot">
<link rel="alternate" title="RSS 1.0" type="application/rss+xml"
tal:condition="request/SearchableText|nothing"
tal:attributes="href string:$here_url/search_rss?${request/QUERY_STRING}&path=${request/form/path|context/@@plone/navigationRootPath}"/>
</metal:block>
<metal:block fill-slot="top_slot"
tal:define="dummy python:request.set('disable_border',1)" />
<div metal:fill-slot="main"
tal:define="use_types_blacklist request/use_types_blacklist | python:True;
results python:here.queryCatalog(REQUEST=request,use_types_blacklist=use_types_blacklist);
Batch python:modules['Products.CMFPlone'].Batch;
b_size python:30;b_start python:0;b_start request/b_start | b_start;
desc_length site_properties/search_results_description_length;
desc_ellipsis site_properties/ellipsis;
searchterm request/SearchableText|nothing;
use_view_action site_properties/typesUseViewActionInListings|python:();">
There's another occurrence of

Author: