Unique value filter in loops or a List (Set) with unique values (array_unique())

Goal:
I would like to get only unique values from a loop.

For the moment, I have a loop that returns something like this:
2025 2025 2025 2025 2026 2026 2027 2027
and I would like to get only unique values:
2025 2026 2027

Or in other words, I need an equivalent of array_unique() function. Is there a filter for loops or anything else that could help me achieve it?

Context:
I want to create a simple filter for events (The Events Calendar) depending on a year. I have a loop that gets all the years of events:

<loop type="tribe_events" sort_field="_EventStartDate" sort_type="date" order="asc">
	<field name="_EventStartDate" date_format="Y"></field>
</loop>

and below that, a filtered list of events with custom data attribute:

<loop type="tribe_events" sort_field="_EventStartDate" sort_type="date" order="asc">
	<article data-year="{Field name='_EventStartDate' date_format='Y'}">
		...
	</article>
</loop>

In the first loop, I plan to add JS for showing or hiding events from the lower loop based on a year clicked.

Remarks:

  • I use LiveCanvas which recommends html-like syntax with lowercase and explicit syntax when referencing fields.

You can achieve this using List to keep a list of unique items.

Create an empty list before the loop.

<List name=items></List>

Inside the loop, create an item and append it to the list if it’s not already included.

<Set name=item><Field name=date /></Set>

<If list=items compare=not_includes value="{Get item}">
  <List name=items push>
    <Item><Get name=item /></Item>
  </List>
</If>

To check if an item exists in a list: If tag: Comparisons when the subject is a list.

To add an item to an existing list, I found an undocumented feature using the List tag with push attribute. Similarly the Map tag has the merge attribute to update an existing map. I’ve made a note to explain this in the docs.


As a quick test, I tried the following.

<List name=items></List>

<Loop items=2025,2025,2025,2025,2026,2026,2027,2027>
  <If list=items compare=not_includes value="{Field}">
    <List name=items push>
      <Item><Field /></Item>
    </List>
  </If>
</Loop>

<Get list=items />

Result:

["2025","2026","2027"]
1 Like

LiveCanvas which recommends html-like syntax with lowercase and explicit syntax when referencing fields.

In that context, it sounds like the push attribute might not work because it has no value, similar to Field tag’s shortcut for name. Maybe try push="" as workaround.


In any case, I think it would be useful for the List tag to have more array operations.

  • push - Append item(s) to end of list
  • pop - Remove the last item
  • shift - Remove the first item
  • unshift - Prepend item(s) to start of list

They could support the short syntax (attribute with no value); and long syntax with attribute name and value, like action=push.

1 Like

Thank you @eliot , push worked!

However, I couldn’t use + syntax in LiveCanvas (LC). For some reason, it doesn’t work. I added json attribute. It also works without json attribute, but wrapped in [] brackets.

To sum it up, in LC:
1: this doesn’t work; result: []

<!-- 1 -->
<list name="testList"></list>

<loop items="2025,2025,2025,2025,2026,2026,2027,2027">
	<if list="testList" compare="not_includes" value="{Field}">
		<list name="testList" push="">
      		<item><field></field></item>
	    </list>
    </if>
</loop>

<get list="testList"></get>	

2: This works; result: ["2025","2026","2027"]

<!-- 2 -->
<list name="testListTwo" json=""></list>

<loop items="2025,2025,2025,2025,2026,2026,2027,2027">
	<if list="testListTwo" compare="not_includes" value="{Field}">
		<list name="testListTwo" json="" push="">
      		['<field></field>']
	    </list>
    </if>
</loop>

<get list="testListTwo"></get>

3: This also works; result: ["2025","2026","2027"]

<!-- 3 -->
<list name="testListThree"></list>

<loop items="2025,2025,2025,2025,2026,2026,2027,2027">
	<if list="testListThree" compare="not_includes" value="{Field}">
		<list name="testListThree" push="">
      		['<field></field>']
	    </list>
    </if>
</loop>

<get list="testListThree"></get>

If anyone is interested, this is the code with the events calendar fields, that I finally used (using LC recommended syntax):

<list name="eventsYearsList" json=""></list>

<loop type="tribe_events" sort_field="_EventStartDate" sort_type="date" order="asc">
	<if list="eventsYearsList" compare="not_includes" value="{Field name='_EventStartDate' date_format='Y'}">
		<list name="eventsYearsList" json="" push="">
      		['<field name="_EventStartDate" date_format="Y"></field>']
	    </list>
    </if>
</loop>

<loop list="eventsYearsList">
	<button class="event-toggler btn btn-action">
		<field></field>
	</button>
</loop>