How to output getResources multiple-levels deep?

I have a template that calls getResources on a top-level parent. It only returns 1 level deep because they are all containers and I need only the list of those container resources. So this would return an array of those containers like IDs 15, 16, 17. In my examples, 15 and 16 have their own children resources, 17 does not. I’m trying to exclude 17 from further processing of templates.
I send these results to a &tpl chunk. This works fine, I’ve used &debug and I see the array with three container parents.

In the chunk I do another getResources call to see if the parent is empty by using &limit=1, I assume if it returns one resource, then I can display stuff. If it were to return empty, I can skip that container/parent.

The basic code layout of the chunk/tpl is this:

[[!getResources?
&toPlaceholder=`the_listing`
&limit=`1`
&parents=`[[+id]]`
&depth=`0`
]]
[[!+the_listing:empty=`EMPTY`:notempty=`
<div>
[[!getResources?
    &tpl=`sub_items_grid`
    &parents=`[[+id]]`
    &depth=`0`
]]
</div>
`]]

The trick here is goofiness with the :empty and :notempty modifiers.
Oddly, if there is content inside the :empty modifier, anything at all, like :empty=`blabla` , then the content after :notempty RUNS.
But if I have nothing in the empty part, then nothing AT ALL is output. So like :empty=``:notempty=`div.....` In this situation, nothing outputs at all.

This is just super confusing. My test scenario is that two of the parents have children, and it should output the grid of those children. One of the containers has no children, so I would think the :empty content would display instead.

If any content is in :empty, it just works, but also outputs the empty container. If :empty is left blank, nothing outputs at all and my page is blank. Even though getResources is returning an array with content for sure.

I’ve tried every trick with cache/uncache. But I think maybe it’s the case that :empty and :notempty modifiers simply can’t be used with getResources placeholders at all?

It makes zero sense to me that if :empty is blank, nothing outputs, but if I put anything in there at all, then all the content in the :notempty attribute runs instead.

To summarize:

[[!+the_listing:empty=``:notempty=`html`]]
Produces no output at all. Note that this is looped three times, two of the resources should not be empty, and one is.
[[!+the_listing:empty=`nothing found`:notempty=`html`]]
My inner getResources call runs 3 times including the empty parent. The page has output but includes the empty parent which I don’t want.

All I’m trying to do is skip the parent resource that has no children. My assumption is that if getResources finds nothing, it would send back an empty array, which should trigger :empty just fine.

I don’t know how else to explain this. I’m sure it’s some bug with using placeholders or I don’t know what else. The content in :empty never shows up no matter what I put there. The content in :notempty only shows up when :empty does have some content. So weird!

Why do you need to use the toPlaceholder approach at all?

Also, I don’t see how notempty usage makes any sense here. If the placeholder is empty and you want something to be output, use empty. Why do you even have notempty there?

I’m pretty sure you can’t combine the two modifiers empty and notempty like that. If you want to go the modifier route, try:

[[!+the_listing:is=``:then=`<empty code here>`:else=`<notempty code here>`]]

I’m still not sure what you’re trying to do, though. Is there a reason your resource 17 is declared as parent but has no child resources? Otherwise you could filter your getResources call to get only container resources:

&where=`{"isfolder:=":"1"}`

For more precise context, the top level parent is the archive page, it will show headings for years, with a grid of sub-items.

The years are themselves containers. So I have:

-archive-page
  - 2020
  - 2019
    - some item
    - some item
  - 2018

For the sake of argument, this is how the site was built ages ago, not by me. It’s an art gallery so the years are important. I’m sure there was a reason not to just create a TV for the year or go by publish date or something. It is what it is.

When they open the archive-page/ there is a getResources call to grab all the 0-level containers. This gives me 2020, 2019, 2018. This works fine, I can output &debug and see the three of them in the array.
I send this to the &tpl=tpl_archive_listing

This is where it gets hairy for me. They do TWO getResources calls here. The first one sets a &limit=1 probably to reduce performance hit. It sends these results to the placeholder, because in the placeholder is where it does another getResources call to find ALL the resources under the 2020 parent.

So the first one just checks “if there are any under the year container” and the 2nd one inside the placeholder actually does the full query and sends the results to a standard &tpl=show_the_grid.

The part that doesn’t work is the placeholder. It should be receiving one of two results:
1 - getResources found one resource with the &limit=1 query.
2 - getResources founds no resources.

Either way, it should send this result to the placeholder. And this is where we check :empty to basically “skip over” the one that found no children, or go to :notempty for the result that has one child found.

I’ve tried variations of just one or the other modifier, switching to if/then/else, using other modifiers like eq etc.

My problem is that I have no idea what type of data the placeholder is. I’ve tried to output it as-is, nothing is actually output. I don’t know if it returns an object, an array, a false/true, empty string, null, etc.
For example if the :empty modifier uses PHP’s empty() test, it could goof things up if it’s an object, or null or undefined var, etc.
I don’t know what the data type is or how I can test it for “found data” and “didn’t find data”.

Of course, this could be written all wrong in the first place.
If getResources had a query attribute like &hasChildren=`1` then it would exclude the empty parent from the getgo and I wouldn’t need to test like this.

Otherwise this is pretty simple. I just want to get some resources. Then only run my template on the resources that also happen to have children.

That’s backwards, I actually don’t need anything output at all if it’s empty. I’m just trying to “skip” the empty resource/container.

But if I use :notempty all by itself, nothing at all gets output!

This goes back to wondering what exactly the data type of the placeholder is.

If I simply try to output it [[+placeholder]] nothing outputs. So I don’t know. String, object, array, false?

This is the full template, redacted some html for length.

[[!getResources?
&toPlaceholder=`viewing_room`
&limit=`1`
&showHidden=`1`
&parents=`[[+id]]`
&depth=`0`
]]

[[!+viewing_room:empty=``:notempty=`
  <!-- skipping some html -->
  [[!getResources?
      &tpl=`viewing-room-grid`
      &limit=`100`
      &showHidden=`1`
      &parents=`[[+id]]`
      &depth=`0`
      &tvPrefix=`tv.`
  ]]
`]]

Note, if I use :notempty by itself, there is zero output at all.
If I have both :empty and :notempty, there is zero output if it’s :empty=’’.
If there is anything in :empty, it outputs everything including the empty parent I don’t want.

Thus both empty and notempty just don’t seem to be functional.

Ok, I found a solution that really is quite simple.

I downloaded the getResources snippet to get a better understanding how it works.

It would seem that the use of the placeholder is not a direct replacement for a template, but rather just a way to capture the output so you can place it where you like.

In my case I didn’t need a &tpl chunk specifically, so I added an @INLINE and just output the [[+id]] by itself.

Now, when using the placeholder, it either contains the ID of the resource, or empty. Magically, the :notempty modifier started working as normal.

In summary, at least for getResources, if you use a placeholder, just be sure to set up some other template output via &tpl or template wrappers or something. The default behavior of placeholder is to output the resource attributes (array), but for some reason when it didn’t find a resource, the output just broke everything somehow and didn’t work at all with modifiers.
A simple &tpl=`@INLINE [[+id]]` fixed it. At least for my use case, lol

So… that doesn’t actually work the way you (or the previous builders) think it will.

The inner getResources call will get processed no matter what the outer condition says. That approach is actually hurting performance, rather than improve it.

I wrote about these parsing order subtleties back in 2011 and Jason coined the term “mosquito tags” explaining a workaround in 2012, but the short summary is basically that fully built inner tags will get processed before the outer conditions. To avoid that, build tags in such a way that only after outer processing is done MODX can process the inner code.

As in this case you’re simply trying to show nothing when there’s nothing to return, my suggestion would be to just remove the conditional entirely. getResources will return nothing if no results are found, which will be just as fast as the check with a limit of 1 if there’s nothing to find.

Also please make the getResources call (and placeholders set by it) are cached (remove the exclamation mark) - the output of those snippets will by definition not change until a resource is changed, which wipes the cache, so this is again one of those inadvertant things that ends up hurting performance more than it could possibly improve. Some more self-promotion from 2011 to determine when something can be cached, here.

1 Like

Ah yes, I remember all this stuff from years back. Didn’t come to me.

I have all the rest of the HTML to deal with that I removed. That was the point of the conditional, because they don’t want to output any of that. I could probably change that to prefix and suffix wrappers or something. But I need to make sure even those wrappers are not output in the event it doesn’t find anything.

A vestige of tshooting I presume.

It makes more sense now, so I just need to handle making sure there is no output at all if nothing is found. No template wrappers, etc.

Right - that makes sense.

getResources also offers &tplWrapper and &wrapIfEmpty properties to handle that scenario: https://docs.modx.com/current/en/extras/getresources#templating-properties