Custom sorting on a multiselect field?

Hello. I’m trying to think if this is even feasible/logical… I have a site that holds property records. The content manager can select one or many statuses for a property (for sale, for lease, fully leased, etc.). The client would like all the properties with a status of fully lease to appear last. It seemed easy enough until I dug into it. Here’s the field in question…

prop_status:
  label: Property status
  type: multiselect
  options:
    Sale
    For Lease
    Built-to-Suit
    Ground Lease
    Fully Leased

I can’t simply sort based on the prop_status field. It’s not in any order that would place ‘Fully Leased’ last. So I thought about the custom sorting method, but ran into some errors (undefined array key). This made me back up and wonder if it’s even possible to sort based on a field that could hold many values. I’d imagine no. You can’t accurately sort on a field that may contain multiple values. Right?

So what is the solution? I think in this very specific case a property, once marked as fully leased is fully leased and nothing else so the fully leased option could be a separate field, like a toggle. Then I’d be able to simply sort on it.

But I don’t wanna do that now, there’s a ton of records already setup. So is there a way to “move” records that contain the prop_status of ‘Fully Leased’ to the bottom of the collection?

Any insight would be appreciated. Thanks.

You can do it in analogy to the custom sorting example, by assigning e.g. a sort order 2 if “Fully Leased” is in the array of values, and 1 if not, example code:

$products = $page->children()->listed();
$products = $products->map(function($item) {

    //set order number based on whether or not the prop_status array has a value of "Fully leased"
    $item->order = in_array('Fully Leased', $item->prop_status()->split()) ? 2 : 1;

    return $item;
});
$products = $products->sortBy('order', 'asc');
1 Like

@texnixe, Thanks for the reply. I’m always impressed with your quick responses and vast Kirby know-how. Amazing. So this solution worked, but admittedly I don’t know why? What’s goin’ on here? And could we potentially set the preferred order of all values of that prop_status field? So show properties with ‘For Lease’ first, ‘For Sale’ second, etc.?

Possible, yes, but I don’t know if that would make sense, given that the field can have multiple values? What would be your desired logic? Based on which value is set as the first?

Well, here I only check for one condition: is the given value in the array? If yes, give it an order number of 2, otherwise the order number is 1.

The order of importance would be… For Lease, Ground Lease, Sale, Built-to-Suite, Fully Leased. So show any properties that contain For Lease first, etc. Those leased properties are most important so they want to stick 'em at the top of the list. Properties that are sold/fully leased are least important so stick 'em on the bottom of the list.

$products = $page->children()->listed();
$products = $products->map(function($item) {
    // array with sort order of values
    $sortOder =     $sizes = ['For Lease'=>'0','Ground Lease'=>'1','Sale'=>'2','Built-to-Suite'=>'3', 'Fully Lease'=>'4'];
    // get first prop from array of props
    $prop = $item->prop_status()->split()[0] ?? 'here we need a fallback value in case field is not filled';
     // get order value from $sortOrder array based on index
    $item->order = $sortOrder[$prop];

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

Since the field is not required, it obviously can be left empty; therefore you have to set a fallback value either from one of the values ‘For lease’ etc, or add another item to the $sortOrder array.

This works, but not 100% and I think that’s because we’re using a field that has multiple values. There’s a ‘Sale’ property that appears before one that’s ‘Sale, For Lease’. See attached.

I’m guessing that’s happening because the prop_status value is “Sale, For Lease” instead of “For Lease, Sale”.

ss2

Hmmm… so overall I’m assuming that sorting on a field that has multiple values is not fully accurate. Although your first suggestion seemed to be a way to make it work. Maybe I can expand on that.

I was assuming you wanted to assign the sort value based on the first item of the selected ones. If it’s just a question if a given value is present at all, then that’s possible as well.

$products = $page->children()->listed();
$products = $products->map(function($item) {
    // array with sort order of values
    $sortOder =     $sizes = ['For Lease'=>'0','Ground Lease'=>'1','Sale'=>'2','Built-to-Suite'=>'3', 'Fully Lease'=>'4'];
    foreach( $sortOrder as $key => value) {
      if (in_array($key, $item->prop_status()->split())) {
        $item->order = $value;
        return $item;
      }
    }
});
$products = $products->sortBy('order', 'asc');
1 Like

Excellent!