Jump to content
sw_double

Siblings excluding current page

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.

Share this post


Link to post
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...

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
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

Share this post


Link to post
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.

Share this post


Link to post
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).

Share this post


Link to post
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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By schwarzdesign
      I'm working on a news feed that will show the most recent news in a full teaser grid, and all older news as a simpler archive-type list view. My selectors so far:
      $news_full = $page->children("template=news, limit={$page->feed_count_full}"); $news_archive = $page->children("template=news, start={$page->feed_count_full}, limit=9999"); The $page->feed_count_full field controls how many items to show in the teaser grid (I've confirmed it contains the correct value, and the $news_full selector works as intended).
      This works, but I don't like the limit in the second selector. Unfortunately, if I leave it out (i.e. I only specify a start, not a limit), the start is ignored and I get all news instead. Not a big problem as we will never have more than 9999 news, but it still bothers me, as semantically speaking I don't want to set a limit in this case.
      Is this the intended behaviour of start/limit selectors? Is there a cleaner way to specify an offset (start selector) without a limit?
      ProcessWire Version 3.0.123
      Thanks!
    • By louisstephens
      So I was tinkering around with the "select fields" field type and added it to a repeater. My thoughts were I could have a user select a field (textarea, text, etc etc) that I defined and give it a name (another field in the repeater) and create their own form on the page. To be honest, I am now a little lost with rendering the form and mailing the results as potentially the form will be unique and custom every time.  The only way I know to handle the output is by going about it this way:
      $forms = $page->form_select_fields; foreach($forms as $form) { if($form->name === "form_input") { //output input with custom name } elseif($form->name === "form_textarea") { //output input with custom name } } Is there a better way to go about rendering the elements from the repeater? As far as the custom sending goes, I am really at a loss since it would be pretty dynamic. Has anyone used this type of approach, and if so, how did you handle this without going insane?
    • By Harmen
      I want to add a few pages to an AsmSelect Page field inside a repeater using the following code:
      $trialsPage = wire("pages")->get(28422); // Get the page $trialsPage->of(false); $newTrial = $ordersPage->trial_repeater_orders->getNewItem(); // Add item to repeater foreach ($selectedProducts as $selectedProduct){ $productPage = $pages->get("template=product, reference=$selectedProduct"); $newTrial->trial_selected_products->add($productPage); } $newTrial->save(); $trialsPage->save(); However, when I check the page where the field is located it doesn't have the new values as expected. The selected pages exist, the field is in the right location, made sure that the output formatting is turned off: $page->of(false); But it still doesn't work with a variable. No matter what I try, it doesn't work.
      It only works when I replace $selectedProduct with a hardcoded string. Am I doing something wrong here?
    • By louisstephens
      So I have been diving into hooks lately, and I am enjoying them thus far. However, I guess I am a bit stumped on how to achieve what I want too. I am trying to set up a hook that would create a new child page when the parent page is saved. However, when you save the parent page a second time, I just need to update the child page without creating multiple child pages. What would be the best way to go about this?
      So after rereading my post, I believe it is a bit vague so I will try to explain more. 
      The Goal:
      Create a page with a template "one". Once the page is created/saved => create a new child page with the template of "two" If the parent is saved anytime after, do nothing to the child page (limit the parent page to one child page) The parent page is really just being used to output content, whereas the child page is being used to pull out the some fields from the parent to be used elsewhere. I might have made this too complicated in my head.
    • By Peter Knight
      Is there a way to make JPGs progressive by default via the API?
      I've added the following to my site/config.php file but user-uploaded images are often displayed as non progressive.
      $config->imageSizerOptions = array( 'upscaling' => true, // upscale if necessary to reach target size? 'cropping' => true, // crop if necessary to reach target size? 'autoRotation' => true, // automatically correct orientation? 'interlace' => true, // use interlaced JPEGs by default? (recommended) 'sharpening' => 'soft', // sharpening: none | soft | medium | strong 'quality' => 95, // quality: 1-100 where higher is better but bigger 'hidpiQuality' => 60, // Same as above quality setting, but specific to hidpi images 'defaultGamma' => 0.5, // defaultGamma: 0.5 to 4.0 or -1 to disable gamma correction (default=2.0) ); Thanks
×
×
  • Create New...