Jump to content

Siblings excluding current page


sw_double
 Share

Recommended Posts

Hello.

I'm really enjoying going into ProcessWire after using Drupal, CodeIgniter and FuelPHP for a while.

Anyway my first question is with this bit of code

$items = $page->siblings("template=portfolio-item, sort=random, path!={$page->path}");

As you can see, I'm trying to get siblings of the page, excluding current one.

But instead it returns ONLY current page, as if there was no exclamation mark in the path selector.

What's the problem here?

Update:

Okay, have found solution here http://processwire.com/talk/topic/1230-limit-siblings-after-removing-page/

Still curious about path selector behaviour though.

Link to comment
Share on other sites

Welcome to the forums sw_double!

I'll have to dig a bit deeper to find out why that doesn't work. By the looks of it it really should.

Meanwhile, this does the trick for you:

$items = $page->siblings("template=portfolio-item, sort=random, id!=$page");

Edit: Ah, I see you found the solution yourself already. I'm still interested in the actual cause, will come back later...

Link to comment
Share on other sites

Hi sw_double and welcome here :)

Not sure if this is causing the current output, but i think you can't say "sort=random", unless random would be a field defined on the portfoilo-item template. Maybe i'm wrong, but I haven't found this in the docs / cheatsheet.

Can you try with these lines?

//Find the siblings... leave away sort=random and path != {$page->path}
$items = $page->siblings("template=portfolio-item");

//If $items still contains the current page (not sure if this is by default...) -> remove it from $items
$items->remove($page);

//Get one random page
$random_item = $items->getRandom();

//Get multiple random pages
$count = count($items);
$random_items = $items->getRandom($count);
//or even better...
$random_items = $items->shuffle();

The cheatsheet is your best friend when it comes down to finding useful methods/properties :)

http://processwire.com/api/cheatsheet/

Cheers

Link to comment
Share on other sites

Not sure if this is causing the current output, but i think you can't say "sort=random", unless random would be a field defined on the portfoilo-item template. Maybe i'm wrong, but I haven't found this in the docs / cheatsheet.

You can say sort=random, both for database operations ($pages->find/get) and PageArray operations (find/get/sort). See https://github.com/r...Finder.php#L490 and https://github.com/r...Array.php#L681.

I tried that "path!=..." selector out and was able to reproduce the problem as described.

  • Like 1
Link to comment
Share on other sites

Thank you guys for quick response and warm welcome.

There might be a bug with path!= selector.

Little additional question.

I want to get say five closest siblings (which would be two prevs, self and two nexts OR if the page is first then it would be self and four nexts etc). Is there any shortcut for this logic in the API? Anything like ->closest(5) or at least ->next(2)?

If not please consider it a feature request as it feels like common logic required.

  • Like 1
Link to comment
Share on other sites

I think it's already on ryan's radar after a similar discussion about closest parents with selectors and I'm sure he'll also weigh in on this idea too as it seems like at the very least you wouldn't want the two to be called "closest" and do two different things!

You almost want it to be $pages->closest("id=$page")->siblings(5); or something like that.

Link to comment
Share on other sites

There might be a bug with path!= selector.

Yes, looks like it. The method handling 'path' and 'url' in selectors (https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/core/PageFinder.php#L572) doesn't check which operator was used, but assumes it was '='. At least it should raise an exception if an unsupported operator was used.

I think Ryan will spot this from here.

I want to get say five closest siblings (which would be two prevs, self and two nexts OR if the page is first then it would be self and four nexts etc). Is there any shortcut for this logic in the API? Anything like ->closest(5) or at least ->next(2)?

There are methods next() and prev() for a page. They only give you one page in each direction (if one exists) but it shouldn't bee too hard to implement what you we're asking for using those. But do consider Ryan's comment in the source: "Be careful with this function when the page has a lot of siblings. It has to load them all, so this function is best avoided at large scale, unless you provide your own already-reduced siblings list (like from pagination).

Link to comment
Share on other sites

You can't use any operator except '=' when querying path or url from the database (like when using $pages->find). This is because the path doesn't actually exist in the database, so there's nothing to perform comparisons on. It is generated at runtime based on a page combining its name with the names of its parents. It worked with '=' because we pulled a few tricks to convert a path into a big left join statement, in an attempt to match it. And this actually works very well. But it doesn't translate quite as well to other operators. 

I should have had the engine throw an exception when you used an operator it didn't support for that. Instead it just switched it to an '='. So I've updated it so that it now throws an exception instead. 

I've also added a new module to the core, called PagePaths. When you grab the latest dev branch, do a 'check for new modules' and you should see it. Once you install that, it goes and sets up a table with all the page paths and a means of querying them. This enables you to use any operator when querying path or url, including all the partial text matching ones like %=, *=, ~=, ^=, $=. As a side effect, this module also brings potential performance improvements to other queries, as  it eliminates the need for the left join trick I mentioned above. (Though in my initial tests, it doesn't seem to be a measurable improvement). I will probably have this module installed by default for new installations of 2.3. But won't have it auto-install to existing installations. That's because it has to generate an index of all pages in your site--a potentially resource consuming process. For instance, Antti's 100k page site probably won't work with this, as it's no small task to go and build an index for 100k pages after the fact. But if you aren't running a massive site already, this module is one you probably want on most sites, so I went ahead and included it in the core. 

  • Like 4
Link to comment
Share on other sites

  • 5 years later...

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Similar Content

    • By Mika
      Hello, can I use the selector to extract only pages with page titles longer than 10 characters?
      I'm looking for a way to search directly without using the php foreach statement, as shown below.
              $result = $this->pages->find("template!=admin, has_parent!=2, include=all");
              foreach ($result as $page) {
                  if (strlen($page->title) > 10) {
                      $this->table[] = $page;
                  }
              }
       
    • By Guy Incognito
      I'm trying to build a search selector that includes a checkbox multiple option field (clinicdetails_specialisms). The whole selector works fine if I don't include the checkbox field. With it included I get errors like "Error: Exception: SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters (in wire/core/PageFinder.php line 627)".
      This is the selector as it currently stands.
      subscription_status=active,(template=user,clinicdetails_description|clinicdetails_short_description|clinicdetails_clinic_name|clinicdetails_first_name|clinicdetails_last_name*=$query),(clinicdetails_specialisms.title=$query) I've also tried setting the specialisms field in one string rather than groups and have also tried with/without the '.title' property.
      Oddly the selector works if specialisms is the only field being searched. It seems to fail when mixed with other selectors.
      Can anyone advise what stupid mistake I'm making!
    • By Ksenia
      Hello! 
      I have a weird situation going on with my selector field, which I can't really get. 
      I create an array of titles as filter using this logic:
      firstname=Mike|Steve id=123|124|125 title*=Red|Blue|Green This is the field I am logging: 

      It goes in a for loop till it looks like what you see on the screen.
      So, my code regarding the selector string looks like this:
      $output = ""; foreach ($allorganisations as $item){ $output .= "$item | "; echo "<div style='color:red;'>//output String://</div>"; echo $output; } $selector_org .= ", title=$output"; I also log the output just after the matched pages are selected to be sure:
      $matches = $pages->find($selector_org); echo $output; foreach ($matches as $match) { echo " <li><a href='$match->url'>$match->title</a></li>"; } But you can see that it doesn't select all four needed pages, only selects one of them.
      Yet when I copy this exact selector text and manually put it in my selector, it works great... I even copy extra space and "|" and all that, it is supposed to be identical. I am very confused, what is the difference between the code? 
      foreach ($allorganisations as $item){ $output .= "Institute for Scientific Research in Cosmic Anthropoecology | Institute for Scientific Research in Cosmic Anthropoecology | Stanford Research Institute | Institute for Scientific Research in Cosmic Anthropoecology | Stanford Research Institute | Institute of Clinical and Experimental Medicine | Institute for Scientific Research in Cosmic Anthropoecology | Stanford Research Institute | Institute of Clinical and Experimental Medicine | Cosmists | "; echo "<div style='color:red;'>//output String://</div>"; echo $output; } $selector_org .= ", title=$output"; } ------>
      If you see where I'm going wrong, please enlighten me. I am very puzzled with this behaviour . :--)
      Best,
      Ksenia
    • By Saleena Jhon
      Hello There, I have saw a post that was covering event-calendar with php, ajax and js. That was showing a monthly overview when I click on a "month" button or when I switch the month. And show the events on one particular date when I pick a day. Also, most events are kind of exhibitions and so they have a start date and an end date much later, and occur on each day in-between as well. So on the template I put two date picking fileds date_start and date_end. Is there an elegant way to select the events using the API? If yes, kindly help me out.
      Thanks in Advance
      Regards: 
       
    • By opalepatrick
      I am working on my first Process Module. I am creating forms. Fairly straightforward. However, I really can't work out how to create multiple fieldsets?
      $fieldset = $this->modules->get('InputfieldFieldset'); $fieldset->label = 'Customer Source'; $field = $this->modules->get('InputfieldPage'); $field->inputfield = 'InputfieldSelect'; $field->findPagesSelector = 'parent_id=1449, include=hidden'; $field->labelFieldName = 'yff-lead'; $field->name = 'yfflead'; $field->columnWidth = 16; $fieldset->add($field); $field = $this->modules->get('InputfieldPage'); $field->inputfield = 'InputfieldSelect'; $field->findPagesSelector = 'parent_id=1452, include=hidden'; $field->labelFieldName = 'customer-type'; $field->name = 'customertype'; $field->columnWidth = 16; $fieldset->add($field); //Rinse and Repeat $fieldset->label = 'Contacts'; $field = $this->modules->get('InputfieldPage'); $field->inputfield = 'InputfieldSelect'; $field->findPagesSelector = 'parent_id=1538, include=hidden'; $field->labelFieldName = 'salutation'; $field->name = 'salutation'; $field->columnWidth = 16; $fieldset->add($field); I can create the first fieldset (Customer Source) but then get into trouble as the second fieldset overwrites the first. I understand why, but trying to use the open and close fieldset routine has flummoxed me. Any help appreciated.
×
×
  • Create New...