Jump to content

Search to find pages containing ALL search terms across different fields


JoshoB
 Share

Recommended Posts

Hello again.

So, I'm building a website that features a catalogue of books. I have different product pages (with template "product"). The key fields here are the following:

  • title (= text)
  • subtitle (= text)
  • summary (= textarea)
  • body (= textarea)
  • product_isbn (= text)

In addition, there's a repeater field with author data. It looks like this:

  • authors (= repeater)
    • authors_name (= PageArray)

The authors_name field is populated with pages with template "author". So that means that authors_name stores the ID of the page in question.

Now, what I want visitors to be able to do is to enter a search and the system will spit out the proper results, e.g. "Milton Paradise" should give the visitor ALL pages that contain both of these terms. Now, the problem is that I can't seem to be able to get ProcessWire to do this.

Here's what I have right now as far as the selector is concerned:

$q = str_replace(' ', '|', $q); 
$selector = "template=product, limit=10, (title|subtitle|summary|body|product_isbn%=$q), (authors=[authors_name=[title%=$q]])"; 

The problem is obvious, I think: this will list all pages where EITHER the title, subtitle (etc.) match any of the keywords, AND/OR which match the author's name (title, in this case; ideally, I should also like to include name_first, name_initials, and name_last). Anyway, the result is that this selector includes pages with both "Milton" and "Paradise", or just "Milton", or just "Paradise". If it functioned as I would like it to, I would get e.g. 4 results. But with the selector as it is now, I get e.g. 11 results.

I've been at this for a while now and I can't seem to fix it. There are some threads here that deal with the same problem, but without an obvious fix. Perhaps there is none. I started working with PageArrays and then matching IDs and that sort of thing, and ended up with an unsightly mess of code that untangled as soon as I tried to correct some issue or other. I think that the solution is probably simple, but it eludes me.

I hope the above is clear. Any help would, as always, be greatly appreciated!

 

Link to comment
Share on other sites

@JoshoB, the problem is in the first line:

$q = str_replace(' ', '|', $q); 

You are replacing the space character with the selector "or" operator, meaning wherever you use $q you will match fields with any of the words. So you want to remove that line.

By the way, your way of matching the author title in the repeater is unnecessarily verbose. You can replace...

authors=[authors_name=[title%=$q]]

...with...

authors.authors_name%=$q

...because in a selector PW will try to match a string to a Page Reference's title by default.

This selector should do what you want:

$selector = "template=product, limit=10, title|subtitle|summary|body|product_isbn|authors.authors_name~=$q)";

 

  • Like 5
Link to comment
Share on other sites

Thanks for the suggestions!

And @RobinS -- thanks for the less verbose version of the author selector: I had no idea.

I want to use the %= operator, so that it also matches partial words. I want lazy visitors who search for "milton paradi" to get the results they want, too (more pertinently perhaps, this also matches singular and plural nouns: a search for "dog" will also return books with the word "dogs" in them, etc.).

For the same reason, I want ProcessWire to separate out the query string. If I don't, ProcessWire will look for the phrase rather than individual words.

9 hours ago, Robin S said:

$selector = "template=product, limit=10, title|subtitle|summary|body|product_isbn|authors.authors_name~=$q";

Perhaps to deal with this more specifically: this doesn't work for me, because it searches for the keywords as a phrase (with the ~=  operator). It also doesn't mix and match authors and titles, e.g. "Milton Paradise" won't yield any results unless one of the fields contains that specific phrase. If I split the $q again, as I have done, I get results, but it's again a broad selection, matching either or both, but never exclusively both of the keywords.

Current version, which results in too broad a selection:

$q = str_replace(' ', '|', $q); 
$selector = "template=product, limit=10, title|subtitle|summary|body|product_isbn|authors.authors_name%=$q)"; 

Thanks again!

Link to comment
Share on other sites

46 minutes ago, JoshoB said:

Perhaps to deal with this more specifically: this doesn't work for me, because it searches for the keywords as a phrase (with the ~=  operator).

No, it doesn't search as a phrase but it does require all of the words to be present in the field, and does not match partial words. So if $q = "red dog" it will match "I have a dog and she loves red frisbees" but it won't match "I have three red dogs".

When using the %= operator with multiple words, you will need to explode on spaces and foreach:

$q = preg_replace("/\s+/", ' ', trim($q)); // trim and replace multiple spaces with single space
$q_words = explode(' ', $q);
$selector = "template=product, limit=10";
foreach($q_words as $q_word) {
    $selector .= ", title|subtitle|summary|body|product_isbn|authors.authors_name%=$q_word";
}

 

  • Like 4
Link to comment
Share on other sites

if i understand him correctly this would still not be what he wants, because it would also find this page:

title = the red island
body = three dogs lived happily...

i guess it should NOT find this page?

i think proper searching is beyond what can accurately and easily be done with selectors. one forum member recently linked to this search service: https://www.algolia.com/product that is free until 10k records and 100k operations. google custom search could also be an option: https://developers.google.com/custom-search/ 

and last but not least we have the elastic search module that looks like it could match perfectly for you. i've never used it though, so it would be nice to hear some experiences from others: https://modules.processwire.com/modules/elastic-search/

  • Like 1
Link to comment
Share on other sites

4 hours ago, Robin S said:

When using the %= operator with multiple words, you will need to explode on spaces and foreach:

Perfect -- that seems to be exactly what I'm looking for! Thanks very much.

(Edit: as always, ProcessWire makes things a lot easier than I initially thought -- I was seriously overthinking this problem. Thanks again!)

3 hours ago, bernhard said:

if i understand him correctly this would still not be what he wants, because it would also find this page:


title = the red island
body = three dogs lived happily...

i guess it should NOT find this page?

No, it's precisely what I want. ;)

  • Like 1
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...