Robin S Posted May 7, 2017 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
szabesz Posted May 8, 2017 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
SwimToWin Posted October 1, 2017 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..
Peter Knight Posted December 1, 2018 Posted December 1, 2018 I’ve often wondered how to do this. Especially when building with responsive grid systems. Thanks!
Robin S Posted December 1, 2018 Author 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
a-ok Posted August 21, 2019 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
Robin S Posted August 21, 2019 Author 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
maxf5 Posted December 20, 2019 Posted December 20, 2019 Isn't there this onboard method? https://processwire.com/api/ref/wire-array/slices/
Robin S Posted December 20, 2019 Author 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
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