Closed chrismlusk closed 3 months ago
Well, maybe I spoke too soon. This just happened again, but the duplicates are from level two blocks. No idea what's leading to this.
Two days ago, when the site was last edited, everything was rendering just fine. Today, blocks are duplicated. The entry has not been edited, and nothing has been deployed (so, no settings changes).
OK, after some more digging, I think this is an eager-loading issue — and it's probably my fault.
I'm working with a large page-builder field, and while I do follow Neo's instructions for eager loading, I believe the issue is that I do not eager load everything at the top level.
My code:
{% set blocks = entry.neoField.with([
'blockTypeHandle:children.childBlockTypeHandle:children.childBlockTypeHandle:fieldHandle',
...
]).collect() %}
{% for block in blocks %}
{% do block.useMemoized(blocks) %}
{% endfor %}
{% for block in blocks %}
{% if block.level == 1 %}
...
{% endif %}
{% endfor %}
I avoid eager loading every possible thing because there are plenty of blocks that are one-offs or rarely used. I only add eager loading at this top level for common blocks.
But then, in the templates of the one-off blocks that are not eager loaded, I'll do something like:
{% set grid = block.children
.with([
'grid2Up:children.demo:demoEntry',
'grid4Up:children.demo:demoEntry',
])
.collect().first() %}
In this block template in the project with the duplicate blocks, when I remove the .with
method, the query returns the correct number.
What I find odd, however, is that this isn't always the case. Like I mentioned in the original issue, this only seems to periodically happen.
In fact, after looking again, the duplication does happen on blocks that are eager loaded at the top level, too.
Any ideas what I'm getting wrong? Or have I stumbled my way into a legitimate bug?
No need to do e.g. 'grid2Up:children.demo:demoEntry'
- just 'demo:demoEntry'
is all you need.
Does the block query work as expected if you simplify that?
It works in that the correct number of blocks are rendered, but the demoEntry
field is no longer eager loaded.
Also, in this example, grid2Up
is a child block. Since Neo eager loading works like Matrix fields, I assumed that would need to be included?
Whoops, I misread that part of your comment, didn't realise it was a child block query. And that's probably not related if you're also seeing block duplication at the top level.
If possible, could you please send your composer files and database backup to plugins@spicyweb.com.au, along with information about an entry this is happening with (preferably at the top level if it's still happening there), and a template file or files containing a minimal reproduction of the block duplication on that entry, and we'll have a look.
Thanks, I'll work on creating a minimal reproduction.
In the meantime, so I do not need to include children
or the descendant block types in the eager loading path?
{% set blocks = entry.neoField.with([
// Do this
'grandchildBlockTypeHandle:fieldHandle',
// Not this?
'blockTypeHandle:children.childBlockTypeHandle:children.grandchildBlockTypeHandle:fieldHandle',
...
]).collect() %}
I removed the path of descendent block types, and I see that it does work.
But without children
in the path, if you dump block.children
from within one of the block templates, it shows that it's a BlockQuery. If the Neo field's content is correctly eager loaded, shouldn't that query be executed already?
block.children
is a BlockQuery
in that case, but initially getting every block in the field (not just the top level ones) and then executing the block.useMemoized(blocks)
loop means that the block.children
query will use the blocks
instead of querying the database. So the child blocks have already been loaded from the database, even if the query for them is executed in a template in the same way as a non-eager-loaded/memoized query.
Ah ok! That makes sense. I saw db/BlockQuery
and assumed I was not doing something correctly 🤦🏼
So, it seems that me trying to optimize something that is already optimized has either created or stumbled on my original issue. Either way, removing children
and the descendant block types from my eager loading paths reliably gets me the results I expect.
Thanks for the help!
Bug Description
Front-end queries are outputting grandchild blocks twice in a row. Everything appears normal when editing an entry.
I've experienced this from time to time for a few years on a particular project, and I have followed multiple issues filed here and in the Craft repo that describe seemingly related problems — many of which are hard to reproduce or have been addressed. Because I haven't been able to add any new detail to what is happening, I just resolve the issue by deleting the parent block and re-adding the content.
However, while working on a new project, I might have narrowed down the variables that are contributing to the problem.
The child blocks in this structure have no fields in their field layout — they are used to create limitations for which type of grandchildren are allowed. I find this helpful when a design renders the same layout — but authors need guardrails that enforce which type of data is allowed to be selected.
~So, when the duplication on the front end happens, these are the blocks where this happens.~
~I have plenty of other blocks with a more simple parent-child structure:~
~I have not had any duplication issues with these blocks.~
Any help debugging would be greatly appreciated! Let me know if sending any files or more detail would be helpful.
Steps to reproduce
Unfortunately I can't find a way to reliably reproduce this. What I have noticed is that this has happened when updating propagation method or changing an entry's status in one site but not another.
Neo version
4.0.8
Craft CMS version
4.8.6
What is the affected Neo field's propagation method?
Only save to site created in
Does this issue involve templating, and if so, is eager-loading used?
This is not a templating issue