Yes, it is possible to refine the default search in SilverStripe to include only results from certain categories and highlight the searched keyword in the results.
To filter the search results by category, you can use the addFilter()
method of the FulltextSearchable
class. This method allows you to specify a filter function that will be applied to the search results before they are returned.
Here is an example of how you might use the addFilter()
method to filter the search results by category:
use SilverStripe\CMS\Search\SearchForm;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FulltextSearchable;
class MySearchForm extends SearchForm
{
public function getResults($data, $form)
{
$results = parent::getResults($data, $form);
$category = $data['Category'];
$results->addFilter(function ($item) use ($category) {
if ($item instanceof DataObject && $item->hasField('Category')) {
return $item->Category == $category;
}
return true;
});
return $results;
}
}
To highlight the searched keyword in the results, you can use a regular expression to search for the keyword and replace it with a highlighted version of the keyword. Here is an example of how you might do this:
use SilverStripe\View\ArrayData;
use SilverStripe\Control\Controller;
class MyController extends Controller
{
public function search($request)
{
$keyword = $request->getVar('q');
$results = MySearchForm::get_search_results($keyword);
$highlightedResults = new ArrayList();
foreach ($results as $result) {
$result->Content = preg_replace(
'/' . preg_quote($keyword, '/') . '/i',
'<span class="highlight-keyword">$0</span>',
$result->Content
);
$highlightedResults->push($result);
}
return $this->customise([
'Results' => $highlightedResults,
])->renderWith(['MySearchResults']);
}
}
To trim the text on both sides of the highlighted keyword, you can use the substr()
function to extract a portion of the content that includes the highlighted keyword and a certain number of characters before and after it. Here is an example of how you might do this:
use SilverStripe\View\ArrayData;
use SilverStripe\Control\Controller;
class MyController extends Controller
{
public function search($request)
{
$keyword = $request->getVar('q');
$results = MySearchForm::get_search_results($keyword);
$highlightedResults = new ArrayList();
foreach ($results as $result) {
$content = $result->Content;
$highlightedContent = preg_replace(
'/' . preg_quote($keyword, '/') . '/i',
'<span class="highlight-keyword">$0</span>',