Custom sorting on structure fields

I’m currently trying to perform a custom sorting on a structure field. I want to build a page, which shows an overview of products grouped by their size.

So far, so good. I am just struggling with the sorting, because the size is given in letters (S, M, L, XL). Sorting them descending would work, if the XL size wouldn’t be there.

What’s the cleanest way to sort them, using the sortBy method?

The content in the file looks like this:

Products:

- 
  number: AM70
  size: M
  active: "1"

If there are multiple products, how can I order them so they appear in the correct ascending size (as mentioned, from S to XL)?

There’s probably a more brilliant way, but this should work:

<?php
function sortBySize(&$item, $key) {
  $sizes = array('S'=>'0','M'=>'1','L'=>'2','XL'=>'3');
  $item['order'] = $sizes[$item['size']];
}
$products = $page->products()->yaml();
array_walk($products, 'sortBySize');
$products = a::sort($products, 'order', 'asc');

dump($products);

Alternative:

function cmp($a, $b)
{

    $sizes = array('S'=>'0','M'=>'1','L'=>'2','XL'=>'3');

    if ($sizes[$a['size']] == $sizes[$b['size']]) {
        return 0;
    }
    return ($sizes[$a['size']] < $sizes[$b['size']]) ? -1 : 1;
}

$products = $page->products()->yaml();

usort($products, "cmp");

dump($products);

Another alternative would be to store the sizes as numbers (1,2,3) and then convert the numbers to letter sizes in your template using a category map. This would allow you to work with a collection (using the structure method) instead of working with an array.

Would using the filterBy() function, to filter out just the products you want, in sequence, work?:

$allProds = $page->products()->toStructure();

$sProds = $allProds->filterBy('size', 'S');
$mProds = $allProds->filterBy('size', 'M');
$lProds = $allProds->filterBy('size', '==',  'L');
$xProds = $allProds->filterBy('size', 'XL');

In the end, I’ve actually used this way as I can use the structure field and don’t need to work with arrays. Thanks for the tip, @texnixe :slight_smile:

I was stupid, there is in fact a much better solution:

$products = $page->products()->structure()->map(function($item) {
    $sizes = ['S'=>'0','M'=>'1','L'=>'2','XL'=>'3'];
    $item->order = $sizes[$item->size()->value()];

    return $item;
})->sortBy('order', 'asc');

foreach($products as $product) {
  echo $product->size();
}
1 Like

That’s a very clean way!