horst Posted August 7, 2014 Share Posted August 7, 2014 On a little site I have a pagetree like: home main sub page page sub page main sub page sub page page main ... every page use the same template, every page has a tag field with a string shown as above (main, sub or page) The same structure is used for the navigation and sitemap on the frontend too. What I would like to achieve is the same presentation for search results. Therefor I need a results array ordered this way. Is it possible to cover this with the search selector only? The amount of total pages is less than 100 and ever would be less than 300 in the future too. The pages are fetched from a big german online electronic kompendium. I need the site to filter only the very basics from the online site which seems to hold many thousand pages. It is for local / private use only. (for my son as a searchable reference) Link to comment Share on other sites More sharing options...
reems Posted August 7, 2014 Share Posted August 7, 2014 I've done something like that in building a menu based on search results. In your case you could generate the sitemap but only show an item after a check if it exists in your search result. More in detail: You can create a basic php array from the sitemap as well from the search result with page id's. Then, showing the sitemap you could check for every item with php function "in_array" if the page id exists in the search array and only then echo the item. Worked perfect for me in a travelsite I built where people first choose a sort of trip. Based on the choice the site is searched for that type of trip (multiselectfield in every page) and after that a two level menu is created based on parts of the world and countries. So: part of the world - country - trip, more or less the same as your main - sub - page. Hope this gives you a direction. 2 Link to comment Share on other sites More sharing options...
horst Posted August 7, 2014 Author Share Posted August 7, 2014 Hi reems, this sounds really good and I have tried it out. I use a slightly modified renderNav function from the current dev branch minimal site profile for that. But unfortunately the page ids of the main and sub pages are not within the matches of a search query. With this way to generate the sitemap / search results output it does not work. // $items always is the homepage // $matches is an array with key-values the same: $matches[id] = $id; function renderNav4($matches, $items, $maxDepth = 0, $fieldNames = '', $class = 'nav') { // if we were given a single Page rather than a group of them, we'll pretend they // gave us a group of them (a group/array of 1) if($items instanceof Page) $items = array($items); // $out is where we store the markup we are creating in this function $out = ''; // cycle through all the items foreach($items as $item) { if('site-map'==$item->name) continue; $show = isset($matches[$item->id]); // markup for the list item... // if current item is the same as the page being viewed, add a "current" class to it $out .= $show ? ($item->id == wire('page')->id ? "<li class='current'>" : "<li>") : ''; // markup for the link $out .= $show ? "<a href='$item->url'>$item->title</a>" : ''; // if there are extra field names specified, render markup for each one in a <div> // having a class name the same as the field name if($fieldNames) foreach(explode(' ', $fieldNames) as $fieldName) { $value = $item->get($fieldName); if($value) $out .= $show ? " <div class='$fieldName'>$value</div>" : ''; } // if the item has children and we're allowed to output tree navigation (maxDepth) // then call this same function again for the item's children if($item->hasChildren() && $maxDepth) { if($class == 'nav') $class = 'nav nav-tree'; $out .= renderNav4($matches, $item->children, $maxDepth-1, $fieldNames, $class); } // close the list item $out .= $show ? "</li>" : ''; } // if output was generated above, wrap it in a <ul> if($out) $out = "<ul class='$class'>$out</ul>"; // return the markup we generated above return $out; } Using it this way produces only a list of pages, not the hierarchical structure of the sitemap. I need the main and sub branches, but only where they contain at least one page in matches. Any other ideas or tips? Link to comment Share on other sites More sharing options...
reems Posted August 7, 2014 Share Posted August 7, 2014 Hi, In the travelsite I have taken a little different approach. I'm just a sparetime php scripter, so I'me sure the more experienced ones can simplify the following code or come up with a better solution. I've changed what I use a little bit to fit your situation. If there would be more levels of pages a recursive function would also be better I think. $selection = $pages->find("your search"); // check if there is a search result if(count($selection) > 0) { foreach($selection as $selected) { // get id's of found pages #selectionid[] = $selected->id; // get id's of parent pages $firstparentsid[] = $selected->parent_id; // get parents for next foreach $firstparents[] = $selected->parent; } foreach($firstparents as $first) { // get page id's of next level $secparentsid[] = $first->parent_id; } // combine all id's $all_ids = array_merge($selectionid , $firstparentsid , $secparentsid); // remove double results $all_ids = array_unique($all_ids); } In my case where I use this in the travel site to build menus it's different from your case because my mainmenu and submenu are build seperately (different templates) where a sitemap has to combine the different levels. In your case you can check if the pageid of a link is included in the $all_ids array before printing it in your sitemap. I have a sitemap in the travelsite for which I use the listChildrenTree function in this topic:https://processwire.com/talk/topic/1886-submenu-with-overview-links/ It should be simple to add a check with the array to the echo statements. 1 Link to comment Share on other sites More sharing options...
horst Posted August 7, 2014 Author Share Posted August 7, 2014 Hi reems, thanks! Yes what was needed was to collect the ids of the main- and sub- levels too. The above posted renderNav4 function need no changes then. Just passing an array with involved main-, sub- and page-ids to it works. The only thing I would do a bit different is to collect the ids in assoc key=>value arrays: // $myArray[] = $page->id; $myArray[$page->id] = $page->id; This way you don't get double or multiple entries (no need for calling array_unique), but much more important: you are able to check for existence of an id by calling if(isset($myArray[$id])) what is much, much faster than if(in_array($id, $myArray)) So, I think this only becomes important with huge arrays and a high amount of calls to the function. 1 Link to comment Share on other sites More sharing options...
reems Posted August 8, 2014 Share Posted August 8, 2014 Nice work And your advice about the arrays is something I certainly going to implement. Thanks. But....what about the different colors in your sitemap, how did you do that? Bases on page tags or so? 1 Link to comment Share on other sites More sharing options...
horst Posted August 8, 2014 Author Share Posted August 8, 2014 Yes, I have added three fields to the template: mainid, subid and tag. I use an array with a predefined structure that I use for adding pages via API: $struktur = array( 'grundlagen' => array( 'elektrotechnische-physik', 'stromkreisgesetze', 'elektrotechnische-chemie', 'wechselstrom-und-wechselspannung', 'signal-und-energiequellen', 'messtechnik', 'praxis' ), 'bauelemente' => array( 'lineare-und-nichtlineare-widerstaende', 'kapazitive-und-induktive-bauelemente', 'halbleiter', 'transistoren', 'integrierte-schaltungen', 'sonstige-bauelemente', 'praxis' ), 'schaltungstechnik' => array( 'grundschaltungen', 'transistorschaltungen', 'stabilisierungsschaltungen', 'anwendungen-mit-operationsverstaerker', 'praxis' ) ); Here a bit simplyfied the import process: foreach($struktur as $main => $subs) { $mainPage = $pages->get("/$main/"); // let out the check if the mainPage exists or need to be created here foreach($subs as $sub) { $subPage = $pages->get("parent=$mainPage, name=$sub");// let out the check if the subPage exists or need to be created here // ... execute code for fetching the urls for this subPage here ... foreach($urls as $url) { $dump = @file_get_contents($url, false, $context); if(!$dump) continue; // fetch or create this page $newPage = $subPage->child("source_url={$url}"); if(0==$newPage->id) { // create a new page $newPage = new Page(); $newPage->parent = $subPage; $newPage->source_url = $url; $newPage->tag = 'page'; // can be one out of main, sub, or page $newPage->mainid = $mainPage->id; // store main parent id $newPage->subid = $subPage->id; // store sub parent id ... (template, title, name, etc) $newPage->save(); } $assetsUrl = '/site/assets/files/' . $newPage->id . '/'; // ... parse and adjust the body content, store it into $newContent ... $newPage->of(false); $newPage->body = $newContent; $newPage->save(); wire('pages')->uncache($newPage); } } } This way i have all needed information in the contentpage itself. In my search template I use $selector = "title|body%=$q, tag=page, limit=$limit"; $matches = $pages->find($selector); $selection = array(); foreach($matches as $match) { $selection[$match->id] = $match->id; if(0<intval($match->mainid)) $selection[$match->mainid] = $match->mainid; // add involved mainPage to the ids if(0<intval($match->subid)) $selection[$match->subid] = $match->subid; // add involved subPage to the ids } In my case here this was all to do to get it working with the above posted renderNav4. Into the generated output of the renderNav4 I have added css classes: "<li class='main{$item->mainid} type{$item->tag}'>" I only need to lookup the ids of the three mainPages and add these lines to main.css: li.main2908 a, li.main2908 { color: #465E8A !important; } li.main2916 a, li.main2916 { color: #5B7D12 !important; } li.main2924 a, li.main2924 { color: #AB5D65 !important; } In the sidebar I display the list of the next higher level. It is a really nice and functional site what doesn't take much effort because of Ryans new minimalistic SiteProfile in dev-branch. I only had to manage the import and had to modify the renderNav function into two different behaviours. I love ProcessWire Screenshots: 2 Link to comment Share on other sites More sharing options...
reems Posted August 8, 2014 Share Posted August 8, 2014 Nice job A good day is a day I've learned again something (of PW) 1 Link to comment Share on other sites More sharing options...
horst Posted August 8, 2014 Author Share Posted August 8, 2014 A good day is a day I've learned again something (of PW) +1 A bit OT regarding the threadtitle but another great thing that one can use with ProcessWire is the Hannacode module. When fetching pages from an online resource and store them locally I want that links in the bodycontent point to the local resources if they are available. But which one is, will or should be locally stored isn't easy to determine when fetching the (first) pages is in progress. Therefore I installed Hannacode and store every a-href in the bodycontent as hannacode: [[source_url source_url=http://example.com/path/to/page.html]] The codesnippet that get invoked for every link: $p = $pages->get("template=elektronik, source_url=$source_url"); if(0<$p->id) { // page is locally available echo $p->url; } else { // page is only online available, add a css class to the tag that this can be shown in the page output echo $source_url . '" class="externLink'; } This way I can add or remove pages without breaking (locally) references in other pages. Summary: created an importer script, modified the renderNav function, added one Hannacode and some css styles = a nice and comfortable to use site! 1 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