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

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

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By louisstephens
      From my last post, I was given a good idea on how to count the repeater items, and it worked wonderfully. I got my code working well and the columns (based on the count) all work well as well. Now, I have a head scratcher on my hands. 
      <?php $buttonsIncluded = $page->special_custom_buttons->find('special_custom_buttons_include=1'); $buttonsIncludedCount = count($buttonsIncluded); $buttonsIncludedCountAdditional = $buttonsIncludedCount +1; echo $buttonsIncludedCount; ?> <div class="row"> <?php foreach($buttonsIncluded as $button): ?> <?php if($button->custom_buttons_include): ?> <?php if($buttonsIncludedCountAdditional == 2): ?> <div class="col-6"> <a href=""><?php echo $button->custom_buttons_text; ?></a> </div> <?php elseif($buttonsIncludedCountAdditional == 3): ?> <div class="col-4"> <a href=""><?php echo $button->custom_buttons_text; ?></a> </div> <?php elseif($buttonsIncludedCountAdditional == 4): ?> <div class="col-3"> <a href=""><?php echo $button->custom_buttons_text; ?></a> </div> <?php endif; ?> <?php endif; ?> <?php endforeach; ?> </div> All of this is included in a larger foreach statement that is pulling in other data (like body copy etc etc) from a Page Table field. As you can see in my code above, I am adding "1" to the count, so I can have space in the grid layout for a new button.
      So, right now: it looks something like: 
      [repeater button] [repeater button] [repeater button] [space for new button] What I really need to do is to pull in the button from the Page Table and add it into the new space so it looks like:
      [repeater button] [repeater button] [repeater button] [button from Page Table] Is this even possible todo, or is there a better way to go about this? 
       
      *Edit*
      So, I really just overlooked something quite easy here. Since the grid is based on 12 columns, I could just take 12 and divide by $buttonsIncludedCountAdditional which would give me the remaining col width to use outside the foreach loop. I was trying to make this too complicated.
    • By louisstephens
      Is it possible to use count() to return a number of repeater items don't have a checkbox checked? In my current set up, I have a repeater on the page "dev_repeater" with a checkbox called "dev_repeater_exclude". I need to get a count of the current items that do not have it checked so I can pass it to my css grid to alter the column width.
    • By pwFoo
      I played with the Selectors object and would like to use it for a special use case...
      That is a custom Selectors object with dummy data converted to an php array to see the structure (Selectors object is a WireArray with "fields" added)
      Array ( [0] => Array ( [0] => Array ( [field] => seg1 [value] => val1 [not] => [group] => [quote] => [forceMatch] => ) [1] => Array ( [field] => seg2 [value] => val2 [not] => [group] => [quote] => [forceMatch] => ) ) )  
      But instead of "seg1" the field name is "field" with value "seg1" (= my field name).
       
      So I can't search the Selectors WireArray (= custom WireArray with added Selectors objects) with PW "find('seg1=val1')", Is there a way to search with "find()" or build a simple wrapper to make the elements searchable / filterable with find()?
    • By awebcreature
      Hi all,
      I have a small project which need to get records from Immowelt.de through API.  These records must be on specific user who has entered them. I find the documentation of this API but i don't find something about such selection of user related records. All parameters are for all records in immowelt.de database without user related selection. 
      https://www.immowelt.de/ImmoweltAG/InternetProdukte/api-immowelt.pdf
      Anyone with experience with this Immowelt.de API?  
    • By Arunesh Dutta
      Hello all
      I am newbie.Wanted to know does processwire will allow to display external website content and other sources to my website using API powered by processwire