Robin S Posted May 7, 2017 Share Posted May 7, 2017 PHP has a useful array_chunk function: it is used to split an array into a number of smaller arrays ('chunks') of a size you specify, which are returned to you in a new array (i.e. an array of arrays). ProcessWire doesn't provide a method for WireArrays that is the equivalent of array_chunk, but we can add a new method for this in hook. In /site/init.php... // Add a new 'chunk' method to WireArray, the equivalent of PHP's array_chunk $wire->addHookMethod('WireArray::chunk', function($event) { $wire_array = $event->object; $size = $event->arguments[0]; if( !((int) $size > 0) ) throw new WireException('WireArray::chunk requires an integer $size argument greater than zero'); $array = array(); $count = count($wire_array); for($n = 0; $n < $count; $n += $size) { $array[] = $wire_array->slice($n, $size); } $event->return = $array; }); Now we can use this new chunk() method on any WireArray to return an array of smaller WireArrays. Remember that many array-like objects in PW are WireArrays, including PageArrays, Pageimages and Pagefiles. An example using a PageArray of 'workshop' pages. We are running a series of workshops and there is only time for four workshops per day, so we want to divide the workshops into groups of no more than four and put each group under a heading... // Get all workshop pages $workshops = $pages->find("template=workshop"); // say this returns 12 pages // Split the workshops into PageArrays of no more than 4 pages each $chunked_workshops = $workshops->chunk(4); // an array of 3 PageArrays of 4 pages each foreach($chunked_workshops as $key => $chunk) { // $key is the zero-based index of the array $num = $key + 1; // Output a heading followed by the workshop links echo "<h3>Day $num</h3>"; echo $chunk->each("<p><a href='{url}'>{title}</a></p>"); // $chunk is a PageArray } Another example, this time using images. Say we want to divide the images into groups of three or less - maybe they are to be arranged into rows or we are giving the groups some special styling. // Say this page's 'images' field holds 8 images // Split the images into Pageimages objects of no more than 3 images each // 8 does not divide evenly by 3 so the last Pagesimages object will contain only 2 images $chunked_images = $page->images->chunk(3); foreach($chunked_images as $chunk) { echo "<div class='image-group'>"; // $chunk is a Pageimages object foreach($chunk as $image) { echo "<img src='{$image->size(300, 300)->url}'>"; } echo "</div>"; } 13 Link to comment Share on other sites More sharing options...
Zeka Posted May 7, 2017 Share Posted May 7, 2017 For sure it would be a great addition to WireArray API. Link to comment Share on other sites More sharing options...
szabesz Posted May 8, 2017 Share Posted May 8, 2017 On 2017-5-7 at 9:47 AM, Zeka said: For sure it would be a great addition to WireArray API. I do not think too many functions/methods should be implemented in the core, especially this unique one, although I get the usefulness of it as a shortcut. BTW, here's the docs of $wire->addHookMethod with another example https://processwire.com/api/ref/wire/add-hook-method/ And for those who want to get more OOP: https://processwire.com/docs/tutorials/using-custom-page-types-in-processwire/ 1 Link to comment Share on other sites More sharing options...
SwimToWin Posted October 1, 2017 Share Posted October 1, 2017 Hi Robin S, FYI - There is a simple way to get support for array_chunk in WireArrays, it's described here: https://processwire.com/talk/topic/17324-array_chunk-support/ I am posting this in the hope that you and others will find it useful.. Link to comment Share on other sites More sharing options...
Peter Knight Posted December 1, 2018 Share Posted December 1, 2018 I’ve often wondered how to do this. Especially when building with responsive grid systems. Thanks! Link to comment Share on other sites More sharing options...
Robin S Posted December 1, 2018 Author Share Posted December 1, 2018 An update to the hook in the first post for PW v3.0.117 or greater. // Add a new 'chunk' method to WireArray, the equivalent of PHP's array_chunk $wire->addHookMethod('WireArray::chunk', function(HookEvent $event) { /* @var WireArray $wire_array */ $wire_array = $event->object; $size = $event->arguments(0); if( !((int) $size > 0) ) throw new WireException('WireArray::chunk requires an integer $size argument greater than zero'); $chunks = new WireArray(); for($n = 0; $n < count($wire_array); $n += $size) { $chunks->add($wire_array->slice($n, $size)); } $event->return = $chunks; }); This returns the chunks as a WireArray so you have the option of using WireArray methods. So if needed you could do something like: $items = $pages->find("template=foo"); $chunks = $items->chunk(5); $three_random_chunks = $chunks->find("limit=3, sort=random"); 7 1 Link to comment Share on other sites More sharing options...
a-ok Posted August 21, 2019 Share Posted August 21, 2019 On 12/1/2018 at 10:43 PM, Robin S said: An update to the hook in the first post for PW v3.0.117 or greater. // Add a new 'chunk' method to WireArray, the equivalent of PHP's array_chunk $wire->addHookMethod('WireArray::chunk', function(HookEvent $event) { /* @var WireArray $wire_array */ $wire_array = $event->object; $size = $event->arguments(0); if( !((int) $size > 0) ) throw new WireException('WireArray::chunk requires an integer $size argument greater than zero'); $chunks = new WireArray(); for($n = 0; $n < count($wire_array); $n += $size) { $chunks->add($wire_array->slice($n, $size)); } $event->return = $chunks; }); This returns the chunks as a WireArray so you have the option of using WireArray methods. So if needed you could do something like: $items = $pages->find("template=foo"); $chunks = $items->chunk(5); $three_random_chunks = $chunks->find("limit=3, sort=random"); Is it possible to get this working for a repeater? I seem to get the error Exception: Method RepeaterPageArray::chunk does not exist or is not callable in this context Link to comment Share on other sites More sharing options...
Robin S Posted August 21, 2019 Author Share Posted August 21, 2019 11 hours ago, a-ok said: Is it possible to get this working for a repeater? A RepeaterPageArray is a type of WireArray so it should work as is. And it's working for me so double-check your code (e.g. invisible characters from forum copy/paste). 1 Link to comment Share on other sites More sharing options...
maxf5 Posted December 20, 2019 Share Posted December 20, 2019 Isn't there this onboard method? https://processwire.com/api/ref/wire-array/slices/ Link to comment Share on other sites More sharing options...
Robin S Posted December 20, 2019 Author Share Posted December 20, 2019 4 hours ago, maxf5 said: Isn't there this onboard method? https://processwire.com/api/ref/wire-array/slices/ That's not the same thing. They are basically the opposite of each other. The hook method above allows for a specified number of items in each sub-WireArray, with the number of resulting WireArrays not specified. WireArray::slices() allows for a specified number of sub-WireArrays, with the number of items in each sub-WireArray not specified. To illustrate: 2 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