Soma Posted October 25, 2011 Share Posted October 25, 2011 Is it possible to search for pages having a multi page reference field? Like it's possible with: image.description*=phrase I have built pages of properties containing a page reference field of some emergency addresses with phone numbers. Those addresses are separate pages which can be selected. Now would it be possible, when performing a search, to find pages with having a reference to a address containing the search term?. EDIT: I just figured a straight forward easy way of accomplishing this. Doing a search in addresses first for a matches then do another search for property pages having a page reference to one of the address pages. Will try after a shower Link to comment Share on other sites More sharing options...
ryan Posted October 25, 2011 Share Posted October 25, 2011 You are right about how to do it. This is all it should take: <?php $contacts = $pages->find("body*='search term', template=emergency-contact"); $parents = $pages->find("emergency-contacts=$contacts"); emergency-contact = your template name (optional) emergency-contacts = your page reference field name $parents will have all the pages that had one of the emergency contacts selected with the given search term. 1 Link to comment Share on other sites More sharing options...
Soma Posted October 25, 2011 Author Share Posted October 25, 2011 Was just about to write a foreach loop when I've seen your response. Ahh sure, forgot almost there's no need for loops here! Thanks a lot Ryan for giving the most amazing code example on planet earth. Love it!!! I don't know of any other system that would do this with just two short lines! Perfect. 1 Link to comment Share on other sites More sharing options...
ryan Posted October 25, 2011 Share Posted October 25, 2011 Thanks Soma. Hopefully it works I just typed in the browser and didn't test it locally. Let me know if it doesn't work, as I don't know if I've ever actually used this particular type of search in my sites. But I think it should work. Link to comment Share on other sites More sharing options...
Soma Posted October 25, 2011 Author Share Posted October 25, 2011 It works like a charm. Now I can't help but this amazes me more and more, I'm working on a pretty big and more "complex" site (multilang) and with the way PW works, I love how I can do a very powerful search with very simple readable maintainable code. Run multiple searches and combine them before output, and then being able to sort them by whatever and listing them differently depending on type (ie downloads, pages, addresses ...). It's so fun! EDIT: Only thing that's now bothering me is that multiple word searches don't seem to work over multiple fields well. I have problems to decide which to chose from *%~ . Any tips on this? Link to comment Share on other sites More sharing options...
ryan Posted October 25, 2011 Share Posted October 25, 2011 Multiple word searches should work fine over multiple fields using this syntax: $pages->find("title|body|sidebar*=Something"); Whether to use *= or ~= or %= just depends on what you need. If you want to match an exact phrase, then you'd use *= or %=. If you want to simply match all the words regardless of where they appear in a field, then you'd use ~=. More description here in the 'Selector Operators' section: http://processwire.com/api/selectors/ If you start needing to search lots of fields, then you may want to bundle them up into a 'cache' field. The advantage of a cache field is that there are fewer things for PW and MySQL to join together, so it's more efficient and may be faster. For example, you could create a cache field called 'keywords' that compiles the data from: title, body, sidebar, summary, description or whatever other fields you wanted it to. Then you could just search the cache field, like this: $pages->find("keywords*=Something"); Edit: bundling them into a cache field also gives you the possibility of a ~= being able to match one word in one field and another word in another field. Link to comment Share on other sites More sharing options...
Soma Posted October 25, 2011 Author Share Posted October 25, 2011 Thanks Ryan for the help. I'm doing tests with this a little more, but cases I thought where not giving results but should with multiple phrases, I mean part of words. Only having exact phrases will not always find the desired. As for the page reference search I'm still having some issue, but I'm sure it's me. Will maybe come back. But this should work with multiple contacts found no?, and then find pages with having at least one contact (there's multiple) page reference out of this page array? Hope this makes sense. Link to comment Share on other sites More sharing options...
Soma Posted October 25, 2011 Author Share Posted October 25, 2011 I just tested some more and it was me getting confused, but I can confirm it works with multiple matches. Now I notice a problem concerning multiple words, using any of the *= %= ~= . I search for : "lift notfall" = no results. "lift" = 4 results ("notfall" doesn't relly exist somewhere) This is on a search over simple fields: title|textfield|textfield Edit: Ok I understand it that "~" is only if all words exactly match. It doesn't match only parts of words like with %. But when using % it doesn't search with multiple words. How would it be possible to archive this having multiple words? I know search is not an easy topic and I've done it only roughly few times in the past, last doing it using Doctrine ORM with CI and performing index searches using Doctrine Search, was hard to find the right way that's working fine with multiple words. Like searching for "zeit bern" it finds "Berner Zeitung". Link to comment Share on other sites More sharing options...
ryan Posted October 26, 2011 Share Posted October 26, 2011 Thanks Ryan for the help. I'm doing tests with this a little more, but cases I thought where not giving results but should with multiple phrases, I mean part of words. Only having exact phrases will not always find the desired. ProcessWire won't do a partial match for multiple words with a single operator, i.e "Mike Hunt" matching "Michael Hunter". However, this is easy to solve: $pages->find("keywords*=Mike, keywords*=Hunt"); This is how you might handle it from a submitted search query: <?php $selector = ''; $words = explode(' ', $this->input->get->phrase); foreach($words as $word) { $word = $this->sanitizer->selectorValue($word); if($word) $selector .= "keywords*=$word, "; } $pages->find($selector); Now I notice a problem concerning multiple words, using any of the *= %= ~= . I search for : "lift notfall" = no results. "lift" = 4 results ("notfall" doesn't relly exist somewhere) This is correct. If the term "notfall" is present in the search but not in any of the pages, it's not going to match any pages. It doesn't match only parts of words like with %. But when using % it doesn't search with multiple words. The %= performs the same phrase match as *= except that it uses a non-indexed MySQL 'LIKE' search, which is slower but can match stopwords and words shorter than what MySQL will fulltext index. Like with *=, if you wanted it to match parts of multiple words then you'd have to split it like in the example above. Like searching for "zeit bern" it finds "Berner Zeitung". Either of these will work: $pages->find("keywords*=zeit, keywords*=bern"); $pages->find("keywords%=zeit, keywords%=bern"); 1 Link to comment Share on other sites More sharing options...
Soma Posted October 26, 2011 Author Share Posted October 26, 2011 Thanks you a lot Ryan for the input. Very helpful! Just one thing I don't get, what you mean by cache field? I don't get it. Link to comment Share on other sites More sharing options...
ryan Posted October 26, 2011 Share Posted October 26, 2011 To use a cache field: 1. Go to Setup > Fields > Add New Field 2. Name it "keywords" (or something else if you prefer) 3. In the field type selection, select "cache". If you don't see it there, go to Modules > Fieldtype > Cache > Install, and then go back to step 1. 4. Save the field. In the details tab, it will ask you to select what fields you want to be part of the cache. Select them and click Save. It will build the cache right there. Now you can use your 'keywords' field for searches. Another benefit: If you make it 'autojoin' (if that's appropriate for your use), or you reference it before other fields in the cache (in your API use) then it will use the cached version. Meaning same data loaded but with fewer queries (faster and less overhead). Link to comment Share on other sites More sharing options...
Soma Posted October 26, 2011 Author Share Posted October 26, 2011 Ahh now I get it! But with lots of fields in 3 languages its quite tedious to set up. Nonetheless its a great feature. Now I did what you said and hit save, but there's no cache created. If I check "regenerate cache" and hit save it throws an error Cache 'emergency_contacts_field_cache' is not assigned to any templates. What now? Do I need to attach that field to templates too? Link to comment Share on other sites More sharing options...
ryan Posted October 26, 2011 Share Posted October 26, 2011 Yes, sorry I missed that step– The cache field needs to be assigned to the template where it's used, just like any other field. Link to comment Share on other sites More sharing options...
Soma Posted October 26, 2011 Author Share Posted October 26, 2011 Ok I get it. Good to know this is possible. Though I'm not sure I'll set this up in this site. There's not sooo many fields I'm using in the search and there's some multilang fields on templates, so it would need 3 cache fields for some "_de,_en,_fr", or include them all in one an sort page out from other language trees.... This can get cumbersome and not so easy to maintain. I like it to have it in code form. What you mean when you speak of lots of fields? My selector part is now like following and there will be max of like 200-300 pages/downloads/properties/contacts total for a language. Do you think caching fields would really make a difference? I didn't notice any impact yet without cacheing. <?php $q = $sanitizer->selectorValue($input->post->q); $words = explode(' ', $q); foreach($words as $word) { $word = $sanitizer->selectorValue($word); if($word) $selectorPages .= "title|headline|headline2|body|summary%=$word, "; if($word) $selectorObjects .= "title|beschreibung_$lang|strasse|ort|bewirtschaftung|hauswart_adresse|headline1_$lang|headline2_$lang%=$word, "; if($word) $selectorEmergencyContacts .= "title|label_$lang%=$word, "; if($word) $selectorDownloads .= "title%=$word, "; } Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now