wmushtaq Posted February 14, 2012 Share Posted February 14, 2012 PW is extremely useful for developers. Loving it and learning alot from it. I have a question. Lets say I have a site with a page 'Videos' that has 'Channels' as child pages and each channel has videos in them. I know the 'Videos' page id. So how can I get all videos through it? In other words how can I get all grand children of 'Videos' page? I appologize if I missed something already mentioned in docs. Link to comment Share on other sites More sharing options...
Pete Posted February 14, 2012 Share Posted February 14, 2012 Without actually testing this, I think you could just do the following to fetch those pages: $grandchildren = $page->children->children; Link to comment Share on other sites More sharing options...
diogo Posted February 14, 2012 Share Posted February 14, 2012 (edited) this didn't work for me $grandchildren = $page->children->children; neither did this, or any other variations of this kind: $grandchildren = $page->children()->children(); what worked for me was this: $gp = $pages->get(5766); $children = $gp->children; foreach($children as $child){ // there was a ")" missing $gchildren=$child->children; // corrected from $children to $child foreach($gchildren as $gchild) echo $gchild->title; } you can also give all of the videos the same template and call them simply like this: $pages->find("template=video") // corrected from get() to find() after soma's reply or if you need the videos to have different templates: $pages->find("template=video1|video2|video3") // also corrected from get() to find() edit: Ryan, I also assumed parent->parent children->children would work. Why doesn't it? I'm sure there is a very interesting explanation involving methods and classes and lots of oop stuff Edited February 14, 2012 by diogo 1 Link to comment Share on other sites More sharing options...
Soma Posted February 14, 2012 Share Posted February 14, 2012 You mean why "$page->children()->children()" didn't work? ("$page->parent->parent" actually works to get the grandparent of a page.) Well it's simply that "children()" returns a 1 dimensional page array, so it works only with 1 explicit parent. As it would have to do a multidimensional page array which doesn't exists as far as I know. So a simple loop is needed here like diogo provided. Though I would do it with some check and a little simpler. Also there's a typo in the example of diogo. $channels = $pages->get(5766)->children(); foreach($channels as $channel) { if($channel->numChildren){ // has any children? echo "<h3>" . $channel->title . "</h3>"; foreach($channel->children() as $videopage) { echo "<p>" . $videopage->title . "</p>"; echo "<p>" . $videopage->videourl . "</p>"; // or whatever you need } } } Remember you could also add selectors to children("string"). Or if you want just to get all videos, you can use the ones diogo showed, but I'm not sure it will work or return a page array with only using "$pages->get("template=video")". I think something is missing, usually "get()" returns a single page. Following is the best method to use. You could limit it to the "Video" branch, so it doesn't need to scan whole site. $videos = $pages->get("/videos/")->find("template=video"); foreach($videos as $vid){ ... Or what I think diogo wanted to write is something like this. $videos = $pages->find("template=video"); But this will search through whole site structure. Something you might want to limit. 1 Link to comment Share on other sites More sharing options...
ryan Posted February 14, 2012 Share Posted February 14, 2012 $page->children()->children() This doesn't work because $page->children is an array of pages (PageArray), not a Page. Think of it like a boat carrying a bunch of people. The boat can't have children, but the people in it can. I'm also not sure $page->children->children would be all that useful, because they would have lost all sorting context. However, I'm only thinking in context of the sites I make and know everyone has different needs. So if you want to have something equivalent to $page->children->children, it would be $page->find('id>0'). But I would suggest using Soma's examples as they are more specific to a template, and it's better to be specific. You could limit it to the "Video" branch, so it doesn't need to scan whole site. Nearly any search that gets passed through a selector is fully indexed, so it doesn't have to scan the whole site. If you put in "template=video" it [mysql] heads straight to an index of pages with the video template, so it's not scanning or considering other pages. But this will search through whole site structure. Something you might want to limit. You'd want to limit that if you were using the video template elsewhere in the site and didn't want videos from one branch getting mixed in with videos from another. However, if you know where you are using the video template and aren't going to be using it on other branches in the site, there's no speed advantage to performing the search within a parent $page rather than just using $pages->find() to do it. Technically, there's slightly more [minor] overhead doing a $page->find() than a $pages->find() because it's adding a lookup table to the search that may or may not need to be there. 2 Link to comment Share on other sites More sharing options...
diogo Posted February 14, 2012 Share Posted February 14, 2012 Oh, sorry for the typo and errors... next time I will be sure I'm awaken when I post edit: ok, now I understand why children->children could never work. But I think in some situations it can be useful to target pages like @wmushtaq asked. Maybe a parameter like this "deep=2" passed to children(), or even a method descendants() with this same parameter... Link to comment Share on other sites More sharing options...
ryan Posted February 14, 2012 Share Posted February 14, 2012 Maybe a parameter like this "deep=2" passed to children(), or even a method descendants() with this same parameter... If you wanted all grandchildren, and nothing deeper, you could do this: $page->find("parent=$page->children"); If you wanted grandchildren and anything deeper, you could do this: $page->find("parent!=$page"); If you wanted children, grandchildren and anything deeper, you could do this: $page->find(''); 6 Link to comment Share on other sites More sharing options...
Pete Posted February 14, 2012 Share Posted February 14, 2012 Thanks for this ryan - this one in particular makes sense in terms of the original post I think (assuming this is being called from the "Videos" page itself): $page->find("parent=$page->children"); Link to comment Share on other sites More sharing options...
diogo Posted February 15, 2012 Share Posted February 15, 2012 (assuming this is being called from the "Videos" page itself) If not, it can be called like this: $gp = $pages->get(5766); $gc = $pages->find("parent=$gp->children"); foreach($gc as $a) { echo $a->title; etc... } Link to comment Share on other sites More sharing options...
kongondo Posted April 9, 2013 Share Posted April 9, 2013 If you wanted all grandchildren, and nothing deeper, you could do this: $page->find("parent=$page->children"); If you wanted grandchildren and anything deeper, you could do this: $page->find("parent!=$page"); If you wanted children, grandchildren and anything deeper, you could do this: $page->find(''); If not, it can be called like this: $gp = $pages->get(5766); $gc = $pages->find("parent=$gp->children"); foreach($gc as $a) { echo $a->title; etc... } Could someone please give me examples of using the selector "include=hidden" in the above examples by Ryan and Diogo? I tried this and wasn't able to fetch hidden grandchildren. How do I get "hidden" children? What about both "hidden" parent and grandchildren? Thanks. Btw, in the API docs it says. Check the box for the 'hidden' status when editing a page, which will hide it from find(), children() and siblings() methods. Is this true for get() as well? Thanks /k Link to comment Share on other sites More sharing options...
diogo Posted April 11, 2013 Share Posted April 11, 2013 include hidden works as any other selector. In the examples above: $page->find("parent=$page->children, include=hidden"); $page->find("parent!=$page, include=hidden"); $page->find('include=hidden'); $gc = $pages->find("parent=$gp->children, include=hidden"); Is this true for get() as well? I thought so, but just tried it, and surprisingly it returns the first page that is not hidden. So. I guess not. But you can have the same result by doing: $page->find('include=hidden')->first(); although it's more expensive 1 Link to comment Share on other sites More sharing options...
Soma Posted April 11, 2013 Share Posted April 11, 2013 get() will get the page regardless of its status. It's a explicit call. $pages->get(5766) will always get the page with id 5766 whether it's hidden unpublished or red or blue. So include=hidden won't do anything here. 1 Link to comment Share on other sites More sharing options...
diogo Posted April 11, 2013 Share Posted April 11, 2013 actually, include=hidden does sort of work with get: // 7|2|27|1000 are hidden echo $page->find('parent=/'); // 1001|1003|1005 echo $page->get('parent=/'); // 1001 echo $page->find('parent=/, include=hidden'); // 2|7|27|1000|1001|1003|1005 echo $page->get('parent=/, include=hidden'); // 1001 //but echo $page->find('parent=/, sort=-sort, include=hidden'); // 7|2|27|1000|1005|1003|1001 echo $page->get('parent=/, sort=-sort, include=hidden'); // 7 confused? Ya, me too... edit: I guess get() gives priority to non hidden pages unless you explicitly sort them. 1 Link to comment Share on other sites More sharing options...
kongondo Posted April 11, 2013 Share Posted April 11, 2013 include hidden works as any other selector. In the examples above: $page->find("parent=$page->children, include=hidden"); $page->find("parent!=$page, include=hidden"); $page->find('include=hidden'); $gc = $pages->find("parent=$gp->children, include=hidden"); Is this true for get() as well? I thought so, but just tried it, and surprisingly it returns the first page that is not hidden. So. I guess not. But you can have the same result by doing: $page->find('include=hidden')->first(); although it's more expensive Thanks Diogo. $pages-> confused me too in my tests. get() will get the page regardless of its status. It's a explicit call. $pages->get(5766) will always get the page with id 5766 whether it's hidden unpublished or red or blue. So include=hidden won't do anything here. Thanks Soma. Maybe this (@Ryan) should be exclusively stated in the docs, thanks) Link to comment Share on other sites More sharing options...
kongondo Posted April 11, 2013 Share Posted April 11, 2013 (edited) actually, include=hidden does sort of work with get: // 7|2|27|1000 are hidden echo $page->find('parent=/'); // 1001|1003|1005 echo $page->get('parent=/'); // 1001 echo $page->find('parent=/, include=hidden'); // 2|7|27|1000|1001|1003|1005 echo $page->get('parent=/, include=hidden'); // 1001 //but echo $page->find('parent=/, sort=-sort, include=hidden'); // 7|2|27|1000|1005|1003|1001 echo $page->get('parent=/, sort=-sort, include=hidden'); // 7 confused? Ya, me too... edit: I guess get() gives priority to non hidden pages unless you explicitly sort them. OK.....seems there is something going on there. Strange...Did you test this on PW 2.3? EDIT: OK, but why? Edited April 11, 2013 by kongondo Link to comment Share on other sites More sharing options...
diogo Posted April 11, 2013 Share Posted April 11, 2013 (edited) It is 2.3, but it's not that strange if this is the intention edit: I guess get() gives priority to non hidden pages unless you explicitly sort them. EDIT: i don't know Edited April 11, 2013 by diogo Link to comment Share on other sites More sharing options...
Soma Posted April 11, 2013 Share Posted April 11, 2013 $page->find() or $page->get() does nothing... however if you use a selector in get(selector) it behave different and return first found entry and it's not specific, so include=all or include=hidden will have a effect. But I meant $pages->get(id) or $pages->get("/path/") is explicit and will get the page regardless of it's state, it's a explicit API call. 1 Link to comment Share on other sites More sharing options...
diogo Posted April 11, 2013 Share Posted April 11, 2013 Soma, I understand that $pages->get(id) is an explicit call, but get() is also useful to get what would be the first result of a find() without pulling everything from the database, just like doing $pages->find("limit=1"). Or, at least this is what I thought... Link to comment Share on other sites More sharing options...
Soma Posted April 11, 2013 Share Posted April 11, 2013 Yeah nothing special here with get and selector that is not explicit calling a page, it behaves like a find with limit=1. The sorting is something I wondered too, sometimes you have to define sort=sort to get the manually sorted (also with find()), but then it's all normal and behaves as it should. Behind the scenes $pages->get(selector) will call $pages->find() at the end. You can also use $pages->findOne(selector) and will return the first matches page and return a Page not PageArray. Link to comment Share on other sites More sharing options...
ryan Posted April 13, 2013 Share Posted April 13, 2013 confused? Ya, me too... edit: I guess get() gives priority to non hidden pages unless you explicitly sort them. I'm assuming those $page variables were actually supposed to be $pages? That first set of functions you called in your example have no sort defined. if you don't specify a "sort" in your selector to these functions, the order is either undefined, or by relevance. Functions where sort is inclusive are family functions connected with a page, like $page->children(), $page->child(), $page->siblings(), etc. You can expect those to use a predictable order. But a $pages->find() or $pages->get() with no "sort=" in it means you can't expect any particular order. Except when you are trying to partial match a string, it would attempt to sort them by relevance. If someone had a selector like yours, I would guess they probably wanted this instead: echo $pages->get('/')->children("include=hidden"); // all // or echo $pages->get('/')->child("include=hidden"); // first Link to comment Share on other sites More sharing options...
diogo Posted April 13, 2013 Share Posted April 13, 2013 Yes, $pages of course The selector I used was just for testing. It was the way that I had to form a decent array with find in a default installation Link to comment Share on other sites More sharing options...
Kay Lohn Posted December 7, 2014 Share Posted December 7, 2014 Hi, I would highly appreciate some help with selecting/ displaying grandchildren or nested pages My page structure is: Home |- Projects |- Nature |- Featured Image // Hidden & Unpublished, has a checkbox 'featured', checked |- Another Image // Hidden & Unpublished, has a checkbox 'featured', unchecked |- Another Image //Hidden & Unpublished, has a checkbox 'featured', unchecked |- People |- Featured Image // Hidden & Unpublished, has a checkbox 'featured', checked |- Another Image // Hidden & Unpublished, has a checkbox 'featured', unchecked |- Another Image //Hidden & Unpublished, has a checkbox 'featured', unchecked |- Another Image // Hidden & Unpublished, has a checkbox 'featured', unchecked |- Another Image //Hidden & Unpublished, has a checkbox 'featured', unchecked |- Animals |- Featured Image // Hidden & Unpublished, has a checkbox 'featured', checked |- Another Image // Hidden & Unpublished, has a checkbox 'featured', unchecked |- Another Image //Hidden & Unpublished, has a checkbox 'featured', unchecked ...... and so on ... ...... |- About |- Contact I am having problems displaying recent 3 projects' Featured Images on the home page. <?php $parent_page = wire('pages')->get('/projects/'); // Have used $pages->get('/projects/'); too $parent_page_children = $parent_page->children(); Debugger::dump($parent_page_children); // Debugger::dump($parent_page_children); (Using Tracy) dumps 1 PageArray foreach ($parent_page_children as $children) { Debugger::dump($children); // Debugger::dump($children); (Using Tracy) dumps 6 pages if ($children->numChildren) { foreach ($children->children("is_featured=1, include=all, sort=-date, limit=3") as $child) { Debugger::dump($child); // Debugger::dump($child); (Using Tracy) dumps 6 pages, currently 6 checked as Featured (Need only three) ?> <a href="<?php echo $child->link_to_page->url; ?>"> <img src="<?php echo $child->my_image->url; ?>" alt="<?php echo $child->image_desc; ?>"/> </a> <?php }; }; }; ?> Currently I have 6 pages with featured checkbox checked for testing. The code above displays all 6 instead of limiting to recent 3 sorted by -date.. How can I get recent three to display on my homepage? Again, any help would be highly appreciated. Thanks. Link to comment Share on other sites More sharing options...
Macrura Posted December 7, 2014 Share Posted December 7, 2014 if i was using pages for images, I would keep the images template published and not hidden, but i wouldn't make a php file for it.you can easily find your featured images by using this: $featured_images = $pages->find("template=image, featured=1"); 2 Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted December 7, 2014 Share Posted December 7, 2014 @Kay Lohn: Your "...limit=3" selector fires several times - as many, as there are children under "Projects". And each time it limits maximum number of featured photoes under that category. So you can output a maximum of (3 x NumberOfProjectsChildrenPages) featured photo pages. As Macrura suggested there are better/simplier ways to do what you intend to, like: <?php foreach ($pages->find("template=photo_page_template, include=hidden, sort=-date, limit=3")) { ?> <a href="<?php echo $child->link_to_page->url; ?>"> <img src="<?php echo $child->my_image->url; ?>" alt="<?php echo $child->image_desc; ?>"/> </a> <?php }; ?> Where photo_page_template is the template of you photo pages. 1 Link to comment Share on other sites More sharing options...
Ivan Gretsky Posted December 7, 2014 Share Posted December 7, 2014 ...and just to contribute to the original topic. I use this function to get all subpages of a page: function getAllDescendants ($root, $prependRoot) { $descentants = new PageArray(); foreach ($root->children() as $child) { $descentants->add($child); if ($child->numChildren()) { $descentants->add(getAllDescendants($child)); } } if ($prependRoot) $descentants->prepend($root); return $descentants; } I include this function in _functions.php file which prepends every template file and use it like this: <?php $listingPages = getAllDescendants($pages->get('some selector'))->find("some selector"); foreach($listingPages as $listingItem) { ... }; ?> 2 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