Jump to content

How to optimise site search?

Recommended Posts

HI all.

I recently built a web shop with PW and it works pretty good. I love the simplicity and freedom working with templates and how stuff works and the client loves the back-end.

However, the part I am unhappy about is the site search. Beside the API selectors work fine, it seems not be suitable for that kind of search. People search for words, phrases, they mix spaces, hyphens etc., add measurements … so a lot of searches end up in 0 results.

I know of the ElasticSearch module and other external things like Sphider, Google CSE, algolia.com … but some are quite complicated and limit my control or bring google's ads on the site :) 

So perhaps you have any improvements, ideas how to get a better search engine on my website. Most problems come from spelling issues, singular/plural, hyphenated words/searches. 


$vars['q'] = $q;
$input->whitelist('q', $q);
$q = $sanitizer->selectorValue($q);

// 1.
// Item Number
// If there is a number in it that matches a product's numbers, redirect to product directly
$q_numeric           = preg_replace('/\D/', '', $q);
$prodcut_item_number = $pages->get("template=product|product_variation, product_item_number=$q_numeric");

if ( $prodcut_item_number->id && $prodcut_item_number->template == 'product') {
elseif ( $prodcut_item_number->id && $prodcut_item_number->template == 'product_variation') { // variations are saved as sub-pages, but have no public web-page

// 2.
// Product title and description
// Search the product's title, headline and summary
$matches = $pages->find("title|headline|summary~=$q, template=product, limit=50");

// 3.
// Categories
// If search is a category, append all its products
$categories = $pages->find("title%=$q, template=category, limit=10");
if ( count($categories) ) {
	$category_ids = $categories->each('id');
	$category_ids = implode('|', $category_ids);
	$append_products_from_category = $pages->find("template=product, has_parent={$cat_ids}");

// 4.
// Split search phrase
// If nothing above matches, try each word separatly
if( !count($matches) ) {
	$q_separate = preg_replace('/\PL/u', ' ', $q); // "Remove" everything but letters 
	$q_separate = preg_split('/\s+/', $q_separate);

	foreach ($q_separate as $q_word) {
		if ( $q_word != '' && strlen($q_word) > 4 ) {
			$append_products_separate = $pages->find("title|headline|summary~=$q_word, template=product, limit=50");

// PLEASE NOTE – this doesn't come from my production code, but is a current idea I have
// There is no highly need of weighting results and order best results on top, because there are just a few products for each keyword :-)


Share this post

Link to post
Share on other sites

Just a few random thoughts...

From what I can see, your code is very much heading in a good direction - splitting the task into manageable chunks is IMHO a good way to go.

I assume your product names are in German, based on your location. If so, AFAIK you may not be able to use some of the cool stuff available for English like mySQL's SOUNDS LIKE (bit of discussion here).

How many products is 'just a few', BTW?

One thing to consider is making your product search AJAX powered. Then users can see instantly if they are finding products or otherwise, and you can kind of 'lead' their searching efforts. (One easy way is intercooler.js - see http://intercoolerjs.org/examples/activesearch.html. There is a PW module.)

A small thing that I have found useful in the past is to proactively deal with common misspellings - see 

and the rest of that thread. (YMMV)


  • Like 1

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By sebr
      In my search page, I used a selector like this :
      $searchQuery = $sanitizer->entities($input->get('q')); $searchQuery = $sanitizer->selectorValue($searchQuery); $selector = 'title|subtitle|summary|html_body_noimg~=' . $searchQuery; $matches = $pages->find($selector); I don't have the same results if $searchQuery contains accent or not.
      For example,
      with « bâtiment » I have no result with « batiment » I have onea result : « Les bâtiments et les smart-city » Normally I should have the same results? How can I do that ?
      Thanks for your help
    • By michelangelo
      Hello guys, I am building a sort of an archive. Relatively simple, although I have about 8000 records, each with 15 fields (text, int, images, url). I created a crude search system with a form (emulating the famous Skyscrapper example) to filter through the system. Everything works but it is quite slow... I have 2 questions which are related:

      1. How can I search through the database?
      2. What is a good practice to display many records like these?
      1. I am retrieving the results with
      $songs = $pages->findMany('template=nk-song'); Then I do a foreach to render them all. I am unsure if that is a good way. If I render all of them on the page, it creates thousands of divs with a bit of text, and this can take a while (10s-15s).
      2. This one is even worse :D as every time I retrieve my desired records with something like this:
      $page->find("field_to_search_through~=my_query_string") I get between 20 and 200, but when I render them I am creating iframes with YouTube videos and that can take up to 10s to finish. I "solved" it by only loading the iframes if they are in view with IntersectionObserver on the client-side. But I feel there is a more precise PHP / ProcessWire approach.
      Just to clarify, I started doing all of this custom rendering and querying because tools like ElasticSearch or SearchEngine were a bit complicated and I needed a simple to retrieve information and then display it in my own way.
      Thank you!
    • By snobjorn
      I have a website with multiple content types that I want to be accessible through search. I really like the live search on processwire.com, that sorts content types while typing. I tried to find the code to recreate this, with no luck. Does anyone know if this is jquery, specific jquery plugins, json/xml cached files, and what kind of PHP code is used? Any tip that point me in the right direction would be much apperciated.
      The search result listing seems fairly easy to create with sorting through parameters.
    • By Anders
      I want to allow full text search on my site. There is a very nice solution that comes right out of the box:
      $selector = "title|body~=$q, limit=50"; This works, but to make it even better I would want to give higher weight to pages where the search term occurs in the title, than if it just occurs in the body. After all, a page with the title "Wine from France" is probably the best match for the search "france wine". How do I accomplish this in ProcessWire?
      I can see three possible paths, but I am not very fond of any of them:
      Do a direct SQL query, circumventing the API, along these lines. But I would prefer to abstract away the database layout if at all possible. Use something like ElasticSearch, but to be honest that would be to complicated to set up and maintain in the long run. Make multiple lookups, first for matches in the title, then for matches in the body, and merge and sort in PHP. My suspicion is that this would get complicated quite quickly. For instance, how do you deal with a page that has two of the three search terms in the title and the third in the body? Is there a magic option four I should look into? Or are any of the above options better than the others? Any input is welcome!
    • By jds43
      I have a search page loosely based on Skyscrapers where I'm parsing a selector with options 'beds', 'bathrooms', 'size' fields. It is working well until I select 'Any' after I've run a search. This is where no results are returned (/?beds=&bathrooms=&size=&submit=). I want it to reset and show all results.
      I hope this isn't too vague.
  • Create New...