Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Data Model Questions /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Restrict / Limit the default Search Results


Go to End


3 Posts   1857 Views

Avatar
neilcreagh

Community Member, 136 Posts

13 July 2016 at 9:20pm

Edited: 13/07/2016 9:22pm

I've developed an online bookshop and it's using Silverstripe's standard SiteSearch ( FulltextSearchable::enable(); ). This searches all Pages and Files - but the client would like to restrict the search results, limiting them to just:

1. Search 'Book’ pages only
Just pages with the ClassName ‘Book’ - not Files or other pages

2. Restrict the search to NOT search the Content - just the Title and Meta Description
(I have the Title and Authors automatically included into the MetaDescription for every Book page)

3. If multiple words are entered into the search then only show results with BOTH
If multiple words are used only search for Books that contain BOTH.

For example, at the moment if someone searches for "Dublin History" they get dozens of results but a search for Dublin is only one page of results. My client would prefer if that search only returned titles with BOTH so that it's more specific

Does that make sense? Is it easy enough to restrict the default Results or should I build a custom search form to achieve this?

Avatar
Vix

Community Member, 60 Posts

14 July 2016 at 5:15pm

You can try customising the search form to have a different action. I did something similar a long time ago, this might help give you some ideas.

In Page.php
Eg. SearchForm function

public function SearchForm() {
		$searchText =  _t('SearchForm.SEARCH', 'Search');

		if($this->owner->request && $this->owner->request->getVar('Search')) {
			$searchText = $this->owner->request->getVar('Search');
		}

		$fields = new FieldList(
			new TextField('Search', false, $searchText)
		);
		$actions = new FieldList(
			new FormAction('fullresults', _t('SearchForm.GO', 'Go')) //this is the only real change to tell the form to use a different function for the action
		);
		$form = new SearchForm($this->owner, 'SearchForm', $fields, $actions);
		$form->classesToSearch(FulltextSearchable::get_searchable_classes());
		return $form;
	}

Also in Page.php the fullresults funciton

public function fullresults($data, $form, $request) {
		
		
		$results = $form->getResults();
		$query = $form->getSearchQuery();
		$title = _t('SearchForm.SearchResults', 'Search Results');
		
		$data = array(
			'Results' => $results,
			'Query' => $query,
			'Title' => $title
		);
		
		$keyword = $request->requestVar('Search');
		$keyword = Convert::raw2sql($keyword);
  		$keywordHTML = htmlentities($keyword, ENT_NOQUOTES, 'UTF-8');
		
		$blocks = new ArrayList();
		$mode = ' IN BOOLEAN MODE';
		$doClasses = array('ContentBlock', 'Media');  //select your dataobject or page classes here
  		$doMatch = "MATCH( Title, Content ) AGAINST ('$keyword'$mode) 
                  + MATCH( Title, Content ) AGAINST ('$keywordHTML'$mode)"; //customise your own sql statement here so the results have to have both terms queried.
				  
		foreach($doClasses as $c){
			  $query = DataList::create($c)->where($doMatch);
		  	  $query = $query->dataQuery()->query();
		  	  $query->addSelect(array('Relevance' => $doMatch));
	  
		  	  $records = DB::query($query->sql());
		  	  $objects = array();
		  	  foreach( $records as $record ){
				if ( in_array($record['ClassName'], $doClasses) )
			    $objects[] = new $record['ClassName']($record);
		     }
		     $blocks->merge($objects);
		}
		
		$blocks->sort(array(
    		'Relevance' => 'DESC',
    		'Title' => 'ASC'
  		));
		
		$results = $results->merge($blocks);
		
		return $this->owner->customise($data)->renderWith(array('Page_results', 'Page'));
	}

This was from quite a while back, so I am a bit rusty on what exactly I did, but hopefully it helps point you in the right direction.

Avatar
neilcreagh

Community Member, 136 Posts

15 July 2016 at 3:01am

That's great - thanks!