Dynamic Loops with variable part

Hi,

just wondering if its possible to change parts of a loop during creation.

What do I mean:

With the old Custom Content plugin it was possible to create a code like (Not sure about the correct syntax, but translated to L&L it looked like)

<Set my_var>taxonomy=category terms=any</Set>
<Loop type=post {Get my_var} ></Loop>

to create this loop

<Loop type=post taxonomy=category terms=any ></Loop>

This was pretty helpfull to reduce the runtime of loops when having dynamic loops with multiple taxonomies as it was possible to reduce the loop to the taxonomies with values instead of having to search in all.

Maybe I missed something, but I was not able to get this to run in L&L.

You could check out the special tag-attributes attribute that was released in 3.0.0 but never ended up making its way into the documentation. I’ll see about adding it.

Otherwise, you could also achieve similar functionality by setting a template variable or you could conditionally set a query variable. Lots of different approaches depending on what makes sense in your particular use case.

The tag_attributes sounds exactly what I was looking for. But I can’t get it to work with the Loop tag.

The other options are not real ones for the use-case I have.

This is the use case:

I have a loop looping through content type post. Each post could have up to two of three taxonomies assigned. Then I like to query another content type who could have one of those three taxonomies assigned.
I have no issues to get the loops running and get the data I need - its more a question of performance.

I can loop a list of the existing taxonomies and query the second content type each time with a single taxonomy (what eliminates to query taxonomies without value) or I can query the content with multiple taxonomies at once even the taxonomy has no values for this query.

With the first approach the runtime varies from obejct to object depending on how many times the list needs to be looped.
With the second approach the runtime is more steady but in cases only one taxonomy needs to queried slightly slower than approach one - but if multiple taxonomies needs to be queried way faster than approach one.

The difference is about 0.0020 sec - 0.0200 sec what does not seems to be much but sums up if you run 200 queries.

So the idea was to build the queries with such a tag approach during the loop through the potential taxonomies. This would combine the speed benefits from approach one when only one taxonomy needs to be looped with the one from approach two when multiple taxonomies are looped.

I just did a bit of testing and it looks like tag-attributes only works on regular HTML tags (which I believe was where it was initially designed to work) and doesn’t seem to work on dynamic tags. It seems like it just gets ignored/removed when you use it on a dynamic tag. I can imagine some instances where you’d want this to work on dynamic tags so I’ll run this by a dev and see what can be done about this.

I’m not sure I fully understand your use case, but if you want to share your template here (or maybe the template as you think it should work) maybe someone can suggest an alternative workaround to accomplish what you’re trying to do.

The use case looks like this:

I have one content type with up to three taxonomies assigned and a acf_select returning the taxonomies used (tax1, tax2, tax3) - this leads to following code.

Option A:

<Loop acf_select=my_taxonomies>
 <Set this_item><Field /></Set> //this_item could be tax1, tax2 or tax3
 <Loop type=taxonomy_term taxonomy="{Get this_item}_cat" post=current>

Now I have the taxonomy terms and can loop the three related content types to find the one having also one of the taxonomy terms.

      <Loop type=a taxonomy="{Get this_item}_cat" terms="{Field name}"></Loop>
        .....
      <Loop type=b taxonomy="{Get this_item}_cat" terms="{Field name}"></Loop>
       .....
   </Loop>
</Loop>

This return me then the data I need. In fact I just use the math tag to sum up the count of the - up to three - loop results for each content type.

The other option would be:

Option B:

<Loop acf_select=my_taxonomies>
  <Set this_item><Field />
    <Loop type=taxonomy_term taxonomy="{Get this_item}_cat" post=current>
      <Set my_list><If variable=my_list><Get my_list />,</If><Field name />
    </Loop>
</Loop>

Now I have a list of all terms in all taxonomies that I need for the search. Then I could do:

<Loop type=a taxonomy=tax1_cat terms="{Get my_list}" taxonomy_2=tax2_cat terms_2="{Get my_list}" taxonomy_3=tax3_cat terms_3="{Get my_list}" taxonomy_relation=or >

Both approaches returns the same result, but differ in runtimes.

Option A - is faster if only one taxonomy is looped and slower if multiple taxonomies are looped.
Option B - is returning a relativly steady runtime - somewhere between the values of Option A.

The idea is to use option B but not to run the loop through all three taxonomies - as I know from the term loop what taxonomies I need to search. So I could also set a variable with the taxonomies to loop like:

<Loop acf_select=my_taxonomies>
  <Set this_item><Field />
    <Loop type=taxonomy_term taxonomy="{Get this_item}_cat" post=current>
      <Set my_list><If variable=my_list><Get my_list />,</If><Field name />
     <Set my_loop><If variable=my_loop><Get my_loop /> taxonomy_<Get loop=count />="tax<Get loop=count />_cat" terms_<Get loop=count>=<Field name /></Set>
    </Loop>
</Loop>

This would combine the speed benefit of Option A if only looping one taxonomy and the benefit of Option B when looping multiple taxonomies.

Whoa, that’s some funky stuff you’re up to! Haha!

I can sorta see what you’re doing (thanks for simplifying this down and cutting out the extraneous bits) but I feel like I’m still a little overwhelmed by this. I’ll give it my best shot.

First, an easy improvement. In option B, you’re creating a comma-separated list of taxonomy terms. To do that, you’re overwriting a variable that includes a previously saved instance of itself and then you’re appending one more piece to it for every item in the loop. This seems inefficient to me. The way I’d approach creating a comma-separated list would be to simply move that Set tag outside the loop. That way you could do something like this:

<Set my_list>
  <Loop acf_select=my_taxonomies>
    <Loop type=taxonomy_term taxonomy="{Field}_cat" post=current>
      <Field name /><If not last>,</If>
    </Loop>
  <If not last>,</If>
  </Loop>
</Set>

Probably a lot more efficient this way.

One quirk I’ve noticed about HTML (not just L&L) is that when you have things on multiple lines, sometimes spaces can get added in. Most of the time this is fine, but when working with variables it can sometimes mean that unwanted spaces end up saved inside your variable. This might not affect your particular use case, but in case it does, you could also try just compacting that down to something like this. A pretty hard to read, but it’s the exact same as above, compacted:

<Set my_list><Loop acf_select=my_taxonomies><Loop type=taxonomy_term taxonomy="{Field}_cat" post=current><Field name /><If not last>,</If></Loop><If not last>,</If></Loop></Set>

And here’s a second recommendation. In the hybrid approach at the end, I see why you approached it that way because you want to only add query parameters when they’re actually necessary since otherwise you’d just be looping through stuff you don’t need to loop through.

There are probably a few different ways to approach this. The approach that I can see would be to conditionally loop through one, two, or three taxonomy terms depending on how many are selected in that outer loop. I might get this wrong so you’ll need to sanity check whether I’ve got your data structure right, but my basic idea would be something like this:

<Loop acf_select=my_taxonomies>
  <If total value=3>
    <Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" taxonomy_2=tax2_cat terms_2="{Get my_list}" taxonomy_3=tax3_cat terms_3="{Get my_list}" taxonomy_relation=or />
  <Else if total value=2>
    <Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" taxonomy_2=tax2_cat terms_2="{Get my_list}" taxonomy_relation=or />
  <Else if total value=1>
    <Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" />
  </If>
</Loop>

<Loop query=my_query>...

I’m not sure if this will increase the efficiency of your template, but it might be a different way of thinking about it that can help you figure out an approach that performs well with the current tools that exist in the language. Let me know how this goes!

Thanks for jumping on this.

<Set my_list>
  <Loop acf_select=my_taxonomies>
    <Loop type=taxonomy_term taxonomy="{Field}_cat" post=current>
      <Field name /><If not last>,</If>
    </Loop>
  <If not last>,</If>
  </Loop>
</Set>

Is a nice idea, but will not work. Each taxonomy is only returning one item and with you approach the list would look like this -

term1 term2 term3

instead of

term1,term2,term3

as the item is always the last one in the inner loop. I would have to use the IF-LAST from the acf_taxonomy loop (the outer loop).

<Loop acf_select=my_taxonomies>
  <If total value=3>
    <Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" taxonomy_2=tax2_cat terms_2="{Get my_list}" taxonomy_3=tax3_cat terms_3="{Get my_list}" taxonomy_relation=or />
  <Else if total value=2>
<Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" taxonomy_2=tax2_cat terms_2="{Get my_list}" taxonomy_relation=or />
  <Else if total value=1>
    <Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" />
  </If>
</Loop>

Also a good idea, but value=2 could be

    <Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" taxonomy_2=tax2_cat terms_2="{Get my_list}" taxonomy_relation=or />

or

    <Set query=my_query type=a taxonomy=tax1_cat terms="{Get my_list}" taxonomy_2=tax3_cat terms_2="{Get my_list}" taxonomy_relation=or />

or

    <Set query=my_query type=a taxonomy=tax2_cat terms="{Get my_list}" taxonomy_2=tax3_cat terms_2="{Get my_list}" taxonomy_relation=or />

so there would have to be a hell of IF-CLAUSES - eating up the speed advantage I gather.

Thanks - good point. Will try.

Should still work I would think. That’s why I added the <If not last>,</If> twice so that it would add commas after items in the inner loop or the outer loop.

Huh. But in your example, you were just using tax<Get loop=count />_cat to set the category name so that would always be linear (1 > 2 > 3) depending on the total number of items in the loop, right? Unless the example you gave was incomplete or I’m misunderstanding something. In any case, if those numbers exist somewhere and aren’t just a linear loop count, I would think you should still be able to pass those numbers to the tax{some number}_cat part of the template. But at this point, it seems like I’m getting way into the weeds on your data structure and my brain hurts haha!

Works! Does not have much impact on runtime - but every bit helps at the end.

Thanks.

I also thought about the idea you had. The model is a bit complex as I need the taxonomies for front end editing for the users. Otherways I would link the content with acf-post fields and do just a loop on ids. But htis would give a user just a flat list to select instead of an ordered one I could have with taxonomies.

Its basically a location → Items link. Think about a event-location. You could have up to three different areas at a localtion (Inside, garden & roof). Now you have three other contents representing items that could be at each location like food, music and beverage.

Each location can have one or more of the items and each item can be at one or more locations.

This is basically the matrix I use.

@PolarRacing L&L 3.2.0 dropped this morning and it now allows using the tag-attributes attribute on dynamic tags as well as static tags. Let me know if that works out for you!

2 Likes

Thanks a lot. I will give it a try tomorrow.

1 Like