joe_ma Posted May 10, 2016 Share Posted May 10, 2016 Hi On a new site I use pw as a data base for addresses (located in the admin section of the page tree). On the pages these addresses are displayed in a table according to certain selectors. How can I include the content of these tables in the search results, in a way that the resulting links don't go to the data base but to the page, where the address is listed? Like this: Page about old age lists all addresses that have anything to do with old age like: - social insurance - rest home 1 - rest home 2 You get the idea. Now I'd like the search to "see" that "rest home 1" exists in the data base, but links to the page about old age. With the default settings of the search template, search results don't list information from the data base. I.e. if I search for "rest home 1", nothing is found. Thanks for help. Link to comment Share on other sites More sharing options...
Robin S Posted May 21, 2016 Share Posted May 21, 2016 (edited) ...accidentally overwrote my post, whoops. Anyway, continued below... Edited May 21, 2016 by Robin S Link to comment Share on other sites More sharing options...
LostKobrakai Posted May 21, 2016 Share Posted May 21, 2016 You can do that, but there's no way to detect this automagically. You'd need to define this connection either in code or even in the data layer by using e.g. a pagefield to link pages to their appearance-pages (if different). Link to comment Share on other sites More sharing options...
Robin S Posted May 21, 2016 Share Posted May 21, 2016 Further to what LostKobrakai said regarding storing your references to other pages in a Page field... So you have these pages somewhere in your site: social insurance rest home 1 rest home 2 And then you have a page "old age" that stores references to the pages above using a Page field called "addresses". You should be able to match "rest home 1" to page "old age" with a search selector like: $pages->find("addresses=rest home 1"); Link to comment Share on other sites More sharing options...
joe_ma Posted May 21, 2016 Author Share Posted May 21, 2016 Thanks a lot for both of your answers. Yes, I think I didn't make myself very clear here. So, let me try it again: The website in question gives all sorts of information for people who deal with migration. I.e. administration people, employers and migrants themselves. Have a look for yourselves. There is also a data base with somewhat over 600 addresses. Each of them is a page, but doesn't have a template to be displayed. Both the information pages and the address pages have an asm select field for category. On the information pages these addresses are displayed according to their categories in a table. See this example: At the bottom of this page you find the addresses for the category "wohnen". What I'd like to achieve is, that (staying with the example above) when someone searches for "Ombudsstelle" (second row of the address table), the search results in the url of the information page rather than the address page of the "Ombudsstelle". Link to comment Share on other sites More sharing options...
Robin S Posted May 22, 2016 Share Posted May 22, 2016 Here is a start for how you could create your search. It needs to be fleshed out for usage as global site search. For search input "rest home 1"... $addresses = $pages->find("template=address, title=rest home 1"); $categories = new PageArray(); foreach ($addresses as $address) { $categories->add($address->categories); } $categories = $categories->unique(); // not strictly necessary $results = $pages->find("template!=address, categories=$categories"); As an aside, because you are using Javascript pagination for your address list you could consider populating the filter field from a get variable for search results. To make it easier for visitors to see the address they have searched for if that address appears on page 3 or whatever. Nice looking site, BTW. Link to comment Share on other sites More sharing options...
joe_ma Posted May 22, 2016 Author Share Posted May 22, 2016 Thanks Robin for showing me the way to proceed. I'll give this a try. Nice looking site, BTW. Thanks, I like it too. Link to comment Share on other sites More sharing options...
joe_ma Posted May 27, 2016 Author Share Posted May 27, 2016 Nearly there, but not quite … So my search code looks like this: // Find pages that match the selector $matches = $pages->find($selector); $cnt = $matches->count; // did we find any matches? if($cnt) { // yes we did: output a headline indicating how many were found. // note how we handle singular vs. plural for multi-language, with the _n() function $content = "<h2>" . sprintf(_n('Found %d page', 'Found %d pages', $cnt), $cnt) . "</h2>"; // create dt-list with results $content .= "<dl>"; foreach ($matches as $m){ if ($m->parent->id = 1293) { // Page is an address and has no template to be displayd $rubriken = new PageArray(); foreach ($m as $adr){ $rubriken->add($adr->adr_rubrik); // add the categories from the pagefield (asm select) on the address page } $rubriken = $rubriken->unique; $results = $pages->find("template=basic-page, adr_rubrik=$rubriken"); // find the information pages with template basic-page that have the same categories as the address page foreach ($results as $r){ $content .= "<dt><a href='$r->url'>$r->title</a><br><span>URL: $r->url</span></dt>"; if(strlen($r->body) > 250) { // Limit displayed text to 150 signs $r->body = substr($r->body,0,250).'…'; $string_ende = strrchr($r->body, ' '); $r->body = str_replace($string_ende," …", $r->body); } $content .= "<dd>" . strip_tags($r->body) . "</dd>"; } } else { $content .= "<dt><a href='$m->url'>$m->title</a><br><span>URL: $m->url</span></dt>"; if(strlen($m->body) > 250) { // limit displayed text to 150 signs $m->body = substr($m->body,0,250).'…'; $string_ende = strrchr($m->body, ' '); $m->body = str_replace($string_ende," …", $m->body); } $content .= "<dd>" . strip_tags($m->body) . "</dd>"; } } $content .= "</dl>"; It seems like this is producing some kind of loop: the results keep repeating themselves. But I can't find out, where I made a mistake. As an aside, because you are using Javascript pagination for your address list you could consider populating the filter field from a get variable for search results. To make it easier for visitors to see the address they have searched for if that address appears on page 3 or whatever. Nice idea. But I haven't got a clue on how to do this. The filter is setup by the dataTable javascript. Link to comment Share on other sites More sharing options...
Robin S Posted May 28, 2016 Share Posted May 28, 2016 I suggest you go a different route. The downside to the way you are finding pages in your code above is that you can't do a consistent pagination of results. This is because you do a foreach() within your results list which produces an unknown number of additional results. So say if you need to apply a limit of 20 results for pagination you could end up with 22 on page 1 and 37 on page 2, etc. To avoid this it's best to get your results from a single $pages->find() operation. You don't show what is going into your $selector variable above, but below is some example code. The variable $search_term would be the sanitized term(s) coming from your search form. // Define the piece of the selector that checks fields for the search term // Let's say we only need to check the body field // But you can expand this with any other fields you need to search $selector_piece = "body~=$search_term"; // First we find any matching address pages $addresses = $pages->find("template=address, address_field~=$search_term"); $categories = new PageArray(); foreach($addresses as $address) { // And add their categories to a PageArray $categories->add($address->categories); } $categories = $categories->unique(); // Strip out any duplicates if($categories->count) { // Now we use OR-groups to say either the body must contain the search term // or the page must have the same category as one of the matching addresses $selector_piece = "($selector_piece), (categories=$categories)"; } // Search the website pages, but not address pages because we already dealt with them // If there is the potential of a lot of matches you should apply a pagination limit $matches = $pages->find("$selector_piece, template!=address, limit=20"); // Output the matches, if any if($matches->count) { foreach($matches as $match) { echo "<p><a href='{$match->url}?searched={$search_term}'>{$match->title}</a></p>"; } } else { echo "<p>Sorry, no matches.</p>"; } And then in your pages where you show addresses in a filterable table: <script> $(function() { $.urlParam = function(name) { var results = new RegExp('[\?&]' + name + '=([^]*)').exec(window.location.href); if(results==null) { return null; } else { return results[1] || 0; } }; var searched = $.urlParam('searched'); if(searched){ $('#filter').val(searched); } }); </script> Adjust $('#filter') to match your filter field as needed. You might need to attach this to a callback that runs once the table plugin has initialised. Link to comment Share on other sites More sharing options...
joe_ma Posted May 28, 2016 Author Share Posted May 28, 2016 Wow! Thank you very much for this concise answer. My search.php now looks like this: <?php // look for a GET variable named 'q' and sanitize it $q = $sanitizer->text($input->get->q); // did $q have anything in it? if($q) { $input->whitelist('q', $q); $q = $sanitizer->selectorValue($q); // Search the title and body fields for our query text. $selector = "title|body~=$q"; // First we find any matching address pages (category field = adr_rubrik) $addresses = $pages->find("template=adress_daten, title|adr_beschreibung~=$q"); $categories = new PageArray(); foreach($addresses as $address) { // And add their categories to a PageArray $categories->add($address->adr_rubrik); } $categories = $categories->unique(); // Strip out any duplicates if($categories->count) { // Now we use OR-groups to say either the body must contain the search term // or the page must have the same category as one of the matching addresses $selector = "($selector), (adr_rubrik=$categories)"; } // Search the website pages, but not address pages because we already dealt with them // If there is the potential of a lot of matches you should apply a pagination limit $matches = $pages->find("$selector, template!=adress_daten, limit=20"); if($user->isLoggedin()) $selector .= ", has_parent!=2"; $cnt = $matches->count; // did we find any matches? if($cnt) { // yes we did: output a headline indicating how many were found. $content = "<h2>" . sprintf(_n('Found %d page', 'Found %d pages', $cnt), $cnt) . "</h2>"; // create dt-list with results $content .= "<dl>"; foreach ($matches as $m){ $content .= "<dt><a href='$m->url'>$m->title</a></dt>"; if(strlen($m->body) > 250) { // limit to 150 signs $m->body = substr($m->body,0,250).'…'; $string_ende = strrchr($m->body, ' '); $m->body = str_replace($string_ende," …", $m->body); } $content .= "<dd><span><a href='$m->url'>URL: $m->url</a></span><br>" . strip_tags($m->body) . "</dd>"; } $content .= "</dl>"; } else { // we didn't find any content = "<h2>" . __('Sorry, no results were found.') . "</h2>"; } } else { // no search terms provided $content = "<h2>" . __('Please enter a search term in the search box (upper right corner)') . "</h2>"; } This works like a charm, thanks to Robin's help. Only thing: pagination doesn't seem to work. The limit in $matches limits the results themselves, not the display of the results. When I set the limit to e.g. 5, even the title says «Found 5 pages», even when there are more results than this. Link to comment Share on other sites More sharing options...
Robin S Posted May 28, 2016 Share Posted May 28, 2016 You have to add in the pagination. For the total count of matches use getTotal(). Link to comment Share on other sites More sharing options...
joe_ma Posted May 28, 2016 Author Share Posted May 28, 2016 Yes, stupid me. It came just to my mind in this second. Shame on me! 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