ethanbeyer Posted November 5, 2016 Share Posted November 5, 2016 Hello, I've been working on building a find query and I think I need to be able to do an OR search on multiple selectors, all of which have a number of possible values. The first way I did this was with three queries: // Categories if($page->Categories->count > 0) { foreach($page->get("Categories") as $category) { $category_array[] = $category->name; } $category_string = implode("|", $category_array); $same_categories = $pages->find("template={$page_type}, Categories={$category_string}")->filter("id!={$page->id}"); } // Tags if($page->Tags->count > 0) { foreach($page->get("Tags") as $tag) { $tag_array[] = $tag->name; } $tag_string = implode("|", $tag_array); $same_tags = $pages->find("template={$page_type}, Tags={$tag_string}")->filter("id!={$page->id}"); } // ConnectedClient if(in_array('ConnectedClient', $page->fields)) { $same_client = $pages->find("template={$page_type}, ConnectedClient={$page->ConnectedClient}")->filter("id!={$page->id}"); } if($same_categories->count > 0) $matches->import($same_categories); if($same_tags->count > 0) $matches->import($same_tags); if($same_client->count > 0) $matches->import($same_client); But for some reason, only the first "$matches" seems to stick. So to me, it would make sense to be able to structure a find query like this: $search = $pages->find(" template=post|project, [Categories=one|two|three]|[Tags=yes|no|maybe]|[ConnectedClient=1065] ")->filter("id!={$page->id}"); Does this make sense? I need to find all pages that match [Tags=yes OR no OR maybe] OR [Categories= one OR two OR three] OR [ConnectedClient=1065]. I realize it might turn into a SQL-needed scenario, but given the flexibility of Processwire, the ability to string together a query like this would be super nice. Is there a way? Link to comment Share on other sites More sharing options...
kongondo Posted November 5, 2016 Share Posted November 5, 2016 Yes, there is a way ...there has been for a while actually. It's called OR:groups $search = $pages->find("template=post|project, (categories=one|two|three), (tags=yes|no|maybe), (connectedClient=1065), id!={$page->id}"); That should find results if any of the selectors in the brackets find a match AND the template='blah blah' and id!=1234 are also true . 7 Link to comment Share on other sites More sharing options...
LostKobrakai Posted November 6, 2016 Share Posted November 6, 2016 They are also documented here: https://processwire.com/api/selectors/#or-groups 1 Link to comment Share on other sites More sharing options...
kongondo Posted November 6, 2016 Share Posted November 6, 2016 @LostKobrakai.....uh, that's the exact link I specified in my post 2 Link to comment Share on other sites More sharing options...
ethanbeyer Posted November 7, 2016 Author Share Posted November 7, 2016 Thank you both - @kongondo and @LostKobrakai! I knew there had to be a way to do that, but wasn't sure even how to google it. I'm sure I read right past that part of the docs. Here's what I needed the Or Groups for: "related posts"! I've got two page-types that can be related via Categories, Tags or a Connected Client, and I wanted to be able to show other Posts or Projects that had the same Category, Tag or Client attached. Previous versions of the following function were always finding related posts only when there was an exact match of Categories+Tags. But with your help, I was able to rewrite the function to the following: public function getRelatedPages( $base_page_id, $page_type ) { // set values $pages = wire("pages"); $page = $pages->get($base_page_id); $search = array(); $matches = new WireArray; // Categories if($page->Categories->count > 0) { foreach($page->get("Categories") as $category) { $category_array[] = $category->name; } $category_string = implode("|", $category_array); $search[] = "(Categories={$category_string})"; } // Tags if($page->Tags->count > 0) { foreach($page->get("Tags") as $tag) { $tag_array[] = $tag->name; } $tag_string = implode("|", $tag_array); $search[] = "(Tags={$tag_string})"; } // ConnectedClient if(isset($page->ConnectedClient)) { $search[] = "(ConnectedClient={$page->ConnectedClient})"; } $search_string = implode(", ", $search); $matches = $pages->find($search_string)->sort("random")->filter("id!={$page->id}, template={$page_type}, limit=3"); // Debug // $this->dd($search); // Output the final matches return ($matches->count > 0) ? $matches : NULL; } Thanks again! 3 Link to comment Share on other sites More sharing options...
Robin S Posted November 7, 2016 Share Posted November 7, 2016 7 hours ago, ethfun said: But with your help, I was able to rewrite the function to the following: Nice one! But just a small thing: you set $search to an empty WireArray and then immediately re-set it to an empty array: $search = new WireArray; $search = array(); You only need the latter. 2 Link to comment Share on other sites More sharing options...
ethanbeyer Posted November 9, 2016 Author Share Posted November 9, 2016 @Robin S oh you're so right! I updated the code in my post. 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