Filtering / sorting metaobjects in liquid?

I’ve got a metaobject for a locations. And I’m creating a list page that shows all of them. Think: these are our physical stores, and here’s info about each (photo, address, etc)

I’ve got a for loop that works, but when I try to use a sort filter, it blows up and returns nothing.

Most basic version (and it works):

{% assign locationList = shop.metaobjects.locations.values %}

{% paginate locationList %}
    {% for location in locationList %}
		<li>{{ location.name }}</li>
	{% endfor %}
{{ paginate | default_pagination }}
{% endpaginate %}

This works, and spits out a list.

If I change that first item to include any kind of sort, it returns zero results.

{% assign locationList = shop.metaobjects.locations | sort %}

Any variation of sort, sort_natural, with or without more filtering (e.g. | sort: "name" ) doesn’t seem to work.

What I’m trying to actually achieve: I’m trying to do a smarter sort. I’ve got a name field, and a sort_name field, plus a bunch of others. And I’m trying to make the list sort by the sort_name, so that I can have “The First Place” under “F” not “T”

edit: code typo above

1 Like

Can you try this ?

{% assign locationList = shop.metaobjects.locations.values | sort: "name" %}

whoops. I have a typo in my code above. I did have the .values at the end of my variable.

{% assign locationList = shop.metaobjects.locations.values %}

this returns my five test locations.

{% assign locationList = shop.metaobjects.locations.values | sort: "name" %}

this returns zero.

I figured out a solution - it’s doesn’t answer my question about applying filters, but it does answer the question about sorting.

if you list out metaobjects, like so:

{% assign locationList = shop.metaobjects.locations.values %}

How is this list sorted? It’s not creation date, nor is it the selected display field in the metaobject. Turn out it’s actually sorting by the object’s handle.

So if I’ve got five stores:

Name Handle
The First Store the-first-store
The Second Store the-second-store
A Third Store Name a-third-store-name
Main Store main-store
Aux Store aux-store

They’ll sort, automatically, like:

  1. A Third Store Name
  2. Aux Store
  3. Main Store
  4. The First Store
  5. The Second Store

Change the handles on those, get rid of the articles, so now they’re like this:

Name Handle
The First Store first-store
The Second Store second-store
A Third Store Name third-store-name
Main Store main-store
Aux Store aux-store

And now they sort differently:

  1. Aux Store
  2. The First Store
  3. Main Store
  4. The Second Store
  5. A Third Store Name

And this is what I was trying to accomplish.

There’s stuff that needs adding to the documentation, i think. Because it (and the ai chat bot) says that we can apply array filters to metaobjects. But it doesn’t seem like we can in this case. But you can manipulate the object handle to revise your sorting.

I ran into a similar issue recently with a Testimonial metaobject that has an integer field order.

At first, this didn’t return anything:

{% assign testimonials = shop.metaobjects.testimonial.values | sort: 'order' %}

This worked as expected:

{% assign testimonials = shop.metaobjects.testimonial.values | sort_natural: 'order' %}
2 Likes

Pretty certain that the sort filter doesn’t work on metaobject lists at all. I could get the ‘first’ filter to work, but that was the only array filter that would work for me.

But you can cheat. Here’s an alternative way to do it.

This relies on you having that ‘order’ field with an integer, it won’t work with a text-sort field. Use the CSS ‘order’ property.

{% assign testimonials = shop.metaobjects.testimonial.values %}
<div class="container">
  {% for item in testimonials %}
    <div class="item" style="order:{{ item.order.value }};">
      <h3>{{ item.title.value }}</h3>
      <p>{{ item.content.value }}</p>
    </div>
  {% endfor %}
</div>

<style>
  .container { display: flex; }
  .container .item { display:flex; }
</style>

So, when it writes the loop, it gives each item an order. Then the browser will sort them when the CSS loads. Using order means the container needs to be display: flex (or grid) rather than display: block.

If you’re using a slider or other script, you should look up its sort function, as it might have something specific.

Thanks! This work as expected for MetaobjectValuesDrop.