liquid icon indicating copy to clipboard operation
liquid copied to clipboard

list.product_reference.size

Open chucklin72 opened this issue 3 years ago • 29 comments

I have a custom metafield of a product list. When I display the list {{ product.metafields.custom.mylist }} ["gid://shopify/Product/7668926775542","gid://shopify/Product/7491343778038"]

but {{ product.metafields.custom.mylist.size }} shows nothing

is list !== array?

chucklin72 avatar Jul 03 '22 15:07 chucklin72

We are having the same issue. Plus, giving the array to the Size filter always returns 0, whether the size is 0 or not

LeafedFox avatar Aug 08 '22 12:08 LeafedFox

Having the same problem, can iterate over the array but size returns nothing.

If the product reference list metafield has never been used, i can check if it's nil: {% if product.metafields.custom.mylist == nil %} But if the metafield has been used, but the data was removed, it isn't nil. The value console logs as []. But {% if product.metafields.custom.mylist.value.size > 0 %} doesn't work. This makes it impossible to check if there is data entered in the metafield.

I've been unable to find a workaround for this.

osea-malibu avatar Sep 20 '22 14:09 osea-malibu

Is it that the "list" is only the storage of the data but the metafield is only storing string? maybe it only works with JSON.parse( product.metafields.custom.mylist)?

chucklin72 avatar Sep 20 '22 15:09 chucklin72

This worked for me:

{%- assign product_list = product.metafields.custom.mylist | split: ',' | uniq -%} {{ product_list.size }}

mjolliffe avatar Oct 07 '22 13:10 mjolliffe

Still running into this issue as well but with collection lists (metafield type list.collection_reference). This issue was confirmed by Shopify support staff. Hoping this gets some attention from the maintainers soon.

t3pfaffe avatar Nov 15 '22 13:11 t3pfaffe

upon till today this is still an issue, i.e. metafields of type list is not an array either has a size method. Following works for now, i.e. manually converting it into an array of strings, then use its size.

{% assign productIngredients = product.metafields.custom.ingredient_details.value %}
{% assign productIngredientsArray = product.metafields.custom.ingredient_details | split: ',' %}  // might want the uniq filter too
{% assign productIngredientsTotal = productIngredientsArray.size %}

bendhu avatar Jan 15 '23 09:01 bendhu

Using .count instead of .size solves this issue for me.

annatwp avatar Feb 02 '23 05:02 annatwp

Using .count instead of .size solves this issue for me.

Interesting, It seems ProductListDrop is not a type of array.

alvinkonda avatar Feb 03 '23 09:02 alvinkonda

@annatwp solution worked for me

pablogiralt avatar Feb 11 '23 09:02 pablogiralt

This trick might work to get the size, but this prevents to access an object such as a product reference. I described the issue here: https://github.com/Shopify/liquid/issues/1643#issuecomment-1410660908 I really wonder why this is not fixed yet, very annoying that we can have list but can't navigate them with liquid array filters.

MaxDesignFR avatar Mar 08 '23 17:03 MaxDesignFR

Same here! Omg I'm going crazy with this issue.

Size isn't working either as a filter or using [dot]notation. It acts as if it doesn't have any item. Can't use conditional logic, can't loop over it, it's just like it's not an array...

But on the other hand when it gets JSON stringified it shows as an array on the console.

Here's some of the debugging I did:

Screenshot 2023-06-05 at 12 15 28 Screenshot 2023-06-05 at 12 09 35 Screenshot 2023-06-05 at 12 10 26

Hopefully this gets solved fast!

masserra avatar Jun 05 '23 15:06 masserra

@masserra use .value so artists.size.value

cinghaman avatar Jun 05 '23 15:06 cinghaman

@masserra use .value so artists.size.value

I had tried {{ artists.value | size }} before, but it didn't work either.

Don't understand the why of using size.value, although I just tried it ({% if artists.size.value > 1 %}) and it didn't work either. Also this would not solve the for loop as it needs to be able to read the array as an array and until that happens size or anything else won't work.

masserra avatar Jun 05 '23 16:06 masserra

This worked for me:

{%- assign product_list = product.metafields.custom.mylist | split: ',' | uniq -%} {{ product_list.size }}

upon till today this is still an issue, i.e. metafields of type list is not an array either has a size method. Following works for now, i.e. manually converting it into an array of strings, then use its size.

{% assign productIngredients = product.metafields.custom.ingredient_details.value %}
{% assign productIngredientsArray = product.metafields.custom.ingredient_details | split: ',' %}  // might want the uniq filter too
{% assign productIngredientsTotal = productIngredientsArray.size %}

This is the only thing that worked for me to be able to use size..

BUT... then all I get is an array of metaobject GID reference strings ("gid://shopify/Metaobject/2167308566") which I can't find a way to access!

So... even though this was obviously a hack, this is definitely not the solution.

masserra avatar Jun 05 '23 16:06 masserra

Solution:

OK!! Finally found the cleanest hack to make the array behave like an actual array, a double reverse filter: {% assign metaobjects = metafields.namespace.key.value | reverse | reverse %}

To come back to my real world example would look like: {% assign artists = metafields.custom.artists.value | reverse | reverse %}

Key points that need to be reviewed:

  • The use of value is completely unintuitive. When logging the JSON stringified object/array there's nothing there to suggest the use of value. On top of that it's poorly documented if not completely undocumented.
  • Using value on its own doesn't even take you anywhere. The returned array won't work with the Shopify liquid standards such as size filter or for loops. You won't get an array of actual type array until we apply hacks such as the double reverse filter.
  • Due to the very unintuitive nature of value in conjunction with the array not behaving as expected we find ourselves completely lost throwing value everywhere until we realize it's a liquid bug.

masserra avatar Jun 07 '23 16:06 masserra

Note to the Shopify Liquid Team:

It's almost been 1 year since this issue has been opened, everywhere I look I see people struggling not only with the use of value but also with the fact that "list !== array" as @chucklin72 suggested. It's very confusing and it's clearly a liquid bug since double reverse filter finally turns the list into the expected array type.

The longer this goes on unsolved the more codebases might end up having a breaking change once you finally tackle the issue..

masserra avatar Jun 07 '23 17:06 masserra

I can't believe your solution is actually working!! Great finding @masserra You nailed it.

So something like this is now possible:

{%  assign my_product = product.metafields.custom.product_list.value | reverse | reverse %}
Product title: {{ my_product[1].title }}

A standard for loop works normally as well, but in some situations it is not a practical way to code:

{% for value in product.metafields.custom.product_list.value %}
    Product title: {{ value.title }}
{% endfor %}

I can't agree more with you with the issues you highlighted. Shopify simply ignores us here, I don't mean to be rude or offensive, but why did they not address this at least once, it is puzzling...

As for the metafields value, I belive this is the doc for liquid. I must say this is quite a gymnastic for the mind (especially metaobjects), not always easy to get it right the first time, but I suppose they've had a good reason to do it, and the changes they did to metafields are overall very good.

Now, I wonder if this "trick" is a good idea for production. Could it not backfire? As long as there is no breaking change introduced (which is something I've never seen Shopify do yet), I don't mind using this trick, this can make code simpler and cleaner.

MaxDesignFR avatar Jun 07 '23 18:06 MaxDesignFR

@MaxDesignFR 🙌 🙌 Thank you for that liquid doc, it completely escaped me. Although, what I also mean by "unintuitive" is that JSON stringifying the object doesn't expose the correct tree structure, it suggests that the list can be accessed straight away and that no other attribute (value) needs to be used to access the list 1 more step down the tree.

I spoke to a Shopify admin on discord and they said it's all about priorities as they have many other higher important issues to tackle, which I understand actually, they've indeed been pushing quite a lot of new exciting features lately 🫶

In regards to being production ready I don't see why it might not be. I'll choose this one over any other solution (for now) as this one at least is a clean & explicit hack that feels familiar to other devs and doesn't go around the problem too much, a simple comment and every dev will be in sync. Plus it enables us to use only Shopify's documented liquid standards and no undocumented ones such as .count.

masserra avatar Jun 08 '23 12:06 masserra

If size is 0 then I try count. Seems to be working for me.

AJayHubs avatar Jul 06 '23 21:07 AJayHubs

We have a metaobject that has a field that accepts products (list) and this is how I solved the counting issue:

assign gift_count = promo.product | split: ',' | size

iconjenchua avatar Aug 30 '23 06:08 iconjenchua

{{ metafields.custom.array.value.count }} worked for me, God knows why.

yotamcuralife avatar Apr 21 '24 09:04 yotamcuralife