mindplay.dk Posted August 22, 2012 Share Posted August 22, 2012 I often need to find the closest parent Page of a particular type, and I found that something equivalent to jQuery's closest() function was not available. It's a simple addition to the Page class: /** * Return this page's closest parent matching the given selector. * * If no parent matches the given selector, this function returns a NullPage. * * @return Page * */ public function closest($selector) { $parent = $this->parent(); while($parent && $parent->id) { if ($parent->matches($selector)) { return $parent; } $parent = $parent->parent(); } return new NullPage(); } Please consider including this in the next release. 4 Link to comment Share on other sites More sharing options...
apeisa Posted August 22, 2012 Share Posted August 22, 2012 Excellent idea! Link to comment Share on other sites More sharing options...
Soma Posted August 22, 2012 Share Posted August 22, 2012 Couldn't the $page->parents() be used to do this? $found = $page->parents->find("template=overview"); $theone = $page->parents->find("template=overview")->first(); 2 Link to comment Share on other sites More sharing options...
ryan Posted August 22, 2012 Share Posted August 22, 2012 What might be good is if we just add $selector support to the $page->parents() function so that you could do: $page->parents($selector). Though, keeping consistency with jQuery, adding closest() might make sense as it returns a single item rather than an array (as parents() would). I'd never used closest() in jQuery before, but this page describes the difference (scroll down a bit): http://api.jquery.com/closest/ … I think it seems like a good idea. Link to comment Share on other sites More sharing options...
Pete Posted August 22, 2012 Share Posted August 22, 2012 I've used closest() a few times rather than parent()->parent() repetitively, or if there was ever a chance the layout would change slightly on the page but I knew that somewhere back up the tree a particular element would always exist in relation to the current one. It probably wouldn't be used all that much in PW since another layer of pages would rarely be added between the current page and the parent page, but saying that I'm sure I've run into this before myself so it may as well go i and I'll try and find where I've seen that code where I needed to do something similar. A bit off topic, but ryan: have you at any point emailed anyone at jQuery about PW? I think they'd be interested in the concept Link to comment Share on other sites More sharing options...
mindplay.dk Posted August 22, 2012 Author Share Posted August 22, 2012 Actually, my first take was an extension of parents() adding a $selector argument - it turns out that's probably not very useful, as this would potentially give you multiple parents. When would you need only certain pages from the trail of parents, skipping some of them? Seems like an edgy use-case. And if you do want filtered parents, you can already do $page->parents->filter('template=xyz') Also, if you're looking for one specific parent, there's no need to traverse the parents all the way to the top, if the parent you're looking for is closer than that - hence the function-name, closest() ... Link to comment Share on other sites More sharing options...
Soma Posted August 22, 2012 Share Posted August 22, 2012 I want a $page->nextUntil(); and $page->prevUntil(); ...and if possible a $page->parentsUntil(); 1 Link to comment Share on other sites More sharing options...
Soma Posted August 22, 2012 Share Posted August 22, 2012 Actually, my first take was an extension of parents() adding a $selector argument - it turns out that's probably not very useful, as this would potentially give you multiple parents. $found = $page->parents->find("template=basic-page")->reverse()->first(); This would be the equivalent of closest return only 1 page, and performance-wise also fast as it won't need to query for 1000s pages anyway. Would be nice addition to have a shorter version if needed anyway. Just got me curious. For what task are you using closest method so often? Link to comment Share on other sites More sharing options...
mindplay.dk Posted August 23, 2012 Author Share Posted August 23, 2012 Just got me curious. For what task are you using closest method so often? Finding a parent with a particular template, typically... very useful if your site is divided into major areas, e.g.: area 1 page 1 page 2 area 2 page 3 page 4 page 5 page 6 Suppose you're on page 5 and need a title or image for that area of the site... $page->closest('template=area')->image->... etc. Link to comment Share on other sites More sharing options...
Soma Posted August 23, 2012 Share Posted August 23, 2012 Ah thanks for your response. That's where I often use the $page->rootParent->title for sections and alike, given the structure. Doesn't work of course if a section is nested. Link to comment Share on other sites More sharing options...
mindplay.dk Posted August 23, 2012 Author Share Posted August 23, 2012 I'm not a fan of rootParent, and I think there's a reason why jQuery has no equivalent to that - the exact type of page you're going to get, is unpredictable. Not in the sense that you won't always get the parent below the root of course, but in the sense that the root-parent could change - because pages can be moved around. And in some cases that's what you want - e.g. for breadcrumbs... but in the "site area" situation, the site could grow, and what currently happens to be a root-parent, could become a sub-area of another new area, some day... Link to comment Share on other sites More sharing options...
Soma Posted August 23, 2012 Share Posted August 23, 2012 Yeah that's what I meant. Though never came across having to structurally change a website drastically like this anyway. Not very good regarding SEO and searchengines, so a structure defined will stay the way it is anyway. Link to comment Share on other sites More sharing options...
apeisa Posted August 23, 2012 Share Posted August 23, 2012 When using multisite module "closest" would also be very handy. There the rootParent is actually the "root" etc. Of course parents("selector-here") would work too. Also I have several cases where I count for how many parents page has and based on that return ->eq(1) or ->eq(2). I think in many cases closest would have been helpful. Link to comment Share on other sites More sharing options...
mindplay.dk Posted August 23, 2012 Author Share Posted August 23, 2012 Yeah that's what I meant. Though never came across having to structurally change a website drastically like this anyway. During development of a big project? Oh yes, you did. Link to comment Share on other sites More sharing options...
ryan Posted August 23, 2012 Share Posted August 23, 2012 This all makes sense, I'll plan to get the closest() method added. The only thing I'm having a little trouble with is the term "closest", as to me it would imply not just parents, but siblings, children, etc. I realize it's just referring to parents in jQuery, but still question their choice of the term. Would it not be better for us just to support a $selector argument on the parent() method, like $page->parent($selector)? Seems like it would do exactly the same thing, but maybe be a little more readable? Maybe I just haven't used this particular method in jQuery enough. But I like the goal behind the closest() method, regardless of what we call it. I tend to use rootParent quite a lot in my own sites, for any number of things. But then again, all my sites are structured in a manner that the first level pages are always the main section pages… and that never changes. So rootParent and me are good friends. Link to comment Share on other sites More sharing options...
Soma Posted August 23, 2012 Share Posted August 23, 2012 How about closestParent($sel) ? Link to comment Share on other sites More sharing options...
slkwrm Posted August 23, 2012 Share Posted August 23, 2012 Soma, I find it too long. What about closestP($sel)? It's like a gangsta rapper's nickname Nobody will guess what it means. 2 Link to comment Share on other sites More sharing options...
Soma Posted August 23, 2012 Share Posted August 23, 2012 Too long? There is also a rootParent()! And if closestP() then leave out the P anyway. Or closestParent() and like outputFormatting() has a of(), why not make a cp() too? I use closest a lot in jquery once I understood what it does and it wasn't suggesting to me it would be for parents bubbling up the dom tree. So a little like Ryan said. I don't think it will hurt Link to comment Share on other sites More sharing options...
slkwrm Posted August 24, 2012 Share Posted August 24, 2012 Just kidding Seriously, closestParent is a nice name as it's self-explanatory, no need to guess. Link to comment Share on other sites More sharing options...
ryan Posted August 24, 2012 Share Posted August 24, 2012 closestParent() makes the most sense to me. Though I'm still wondering about just: parent($selector); because the parent() function already implies closest parent (given that it returns the direct parent of the page). So if you provide a selector to it, then it's like saying: "closest parent that has [something]." I also like that extending the existing parent() function in this way wouldn't involve adding a new function to the API. It would also make it consistent with how the child($selector) function works. jQuery uses parent(selector) for something that isn't applicable to ProcessWire. jQuery's parent() can return multiple items, and the selector filters those. So they didn't have a choice to use the parent() function for this purpose. In our context, we don't actually need a separate function like they do. 2 Link to comment Share on other sites More sharing options...
mindplay.dk Posted August 27, 2012 Author Share Posted August 27, 2012 There's something to be said for consistency with jQuery though - since it's basically ubiquitous and familiar to any developer. I would not be opposed to enhancing parent() though, I'm starting to think maybe that makes the most sense - since it already basically works like we're describing, as far as selecting a single parent... And the API would be backwards compatible, since not passing a selector would mean "anything goes", consistent with the rest of the PW API. (come to think of it, sometimes after not using JQ for a few months, I'll instinctively try .parent() for what we're discussing - it seems logical... but maybe that's just me...) Link to comment Share on other sites More sharing options...
diogo Posted August 27, 2012 Share Posted August 27, 2012 Though I'm still wondering about just: parent($selector); because the parent() function already implies closest parent (given that it returns the direct parent of the page). So if you provide a selector to it, then it's like saying: "closest parent that has [something]. I would agree with this if the jQuery inspiration wouldn't be advertised on PW's homepage. In jQuery, something like parent($selector), would mean that you are selecting only $selector from all the results returned by parent(). This could bring some confusion to jQuery users starting with PW. I noticed that parents() works on PW to get all the ancestors of a page. I would say parents($selector) makes all the sense. 1 Link to comment Share on other sites More sharing options...
ryan Posted August 27, 2012 Share Posted August 27, 2012 I'm thinking we'd add the same thing to both parents() and parent(), except that parents() would return all matching, while parent() would return the first (closest) one. That way you always know you'll get a PageArray() from parents() and a Page from parent(). I'm not too concerned about maintaining consistency with jQuery, as their context is still very different from ours… different enough that strict adhesion to their API syntax would ultimately be confusing if taken too far in our context. ProcessWire takes inspiration from jQuery where it makes sense, but cloning their API is not the goal. Rather, we want to provide the clearest API for ProcessWire within our context, regardless of what jQuery is doing. The environments they operate in are very different. In terms of how you work with it, ProcessWire probably has more in common with YUI3 than jQuery, given the more specific single vs. multiple types in YUI3. But I still prefer jQuery as our syntax starting point, rather than ending point. Link to comment Share on other sites More sharing options...
mindplay.dk Posted August 28, 2012 Author Share Posted August 28, 2012 I would agree with this if the jQuery inspiration wouldn't be advertised on PW's homepage. In jQuery, something like parent($selector), would mean that you are selecting only $selector from all the results returned by parent(). This could bring some confusion to jQuery users starting with PW. Very good point, unfortunately. Link to comment Share on other sites More sharing options...
ryan Posted August 29, 2012 Share Posted August 29, 2012 Not really worried about that. We advertise jQuery "inspiration" not "duplication". But like I say the goal has never been to clone their API… nor would it be logical to, given the very different contexts. Instead, I think the goal should be to make ProcessWire's API as simple, easy and logical as possible for the place that ProcessWire works in. I actually thought that jQuery had quite a sweet spot in their API right around 1.2.6 (or thereabouts). Since that time, I think the balance has shifted a bit towards complexity in complexity vs. power balance. But then again, I'm not a full time jQuery user, so there's a lot in their API that I rarely use. 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