Skip to content

fix for primary owner not getting eager loaded and the fallback failing too#16960

Closed
i-just wants to merge 2 commits into5.xfrom
bugfix/getting-nested-elements-primary-owner
Closed

fix for primary owner not getting eager loaded and the fallback failing too#16960
i-just wants to merge 2 commits into5.xfrom
bugfix/getting-nested-elements-primary-owner

Conversation

@i-just
Copy link
Copy Markdown
Contributor

@i-just i-just commented Mar 26, 2025

Description

If you run a query that gets both nested and root entries, the primary owner for nested elements won’t get loaded if the first entry returned by the query:

  • is not a nested element
  • is a nested element that’s owned by an element type different to other nested element owners returned by the query

This will then lead to the getSupportedSites() returning wrong sites, and an attempt to save a nested element that was grabbed this way will fail with an Attempting to save an element in an unsupported site error.

Steps to reproduce:

  • clean v5 install of 5.6.2 or above

  • create 2 sites (siteA and siteB)

  • create entry type article, all default settings, no fields needed except for the default title

  • create a section blog that uses the article entry type

  • create matrix field (matrix) that uses the article entry type; propagation method set to none

  • create a global set (myGlobalSet) that has the matrix field in it’s field layout

  • create an entry in the blog section

  • edit myGlobalSet and for siteB only add an entry to the matrix field; save

  • create a template file with the following code:

{% set entries = craft.entries.siteId(2).type('article').all() %} {# use the ID of `siteB` #}

{% for entry in entries %}
    {{ entry.title }}<br>
    ID: {{ entry.id }}<br>
    Supported Sites:{{ dump(entry.getSupportedSites)}} <br>
    Field ID: {{ entry.fieldId }}
    <hr>
{% endfor %}
  • access the template via browser and note that for the blog entry, the “supported sites” lists both siteA and siteB and for the entry from the matrix field from the global, the “supported sites” is listed correctly as siteB

  • now create a second entry (must be created after adding the entry to the global set) in the blog section

  • access the template again and note that for the first blog entry, the “supported sites” lists both siteA and siteB; for the entry from the matrix field from the global, the “supported sites” is listed wrongly as the primary site (siteA) and for the second blog entry, the “supported sites” also correctly lists both sites

The problem:
The problem is that the eagerLoadingMap in the NestedElementTrait takes the ownerType of the first source element. If the first source element is a root entry, then there’s no owner, and therefore no owner type, so the map is false, and nothing gets eager loaded.

If the first source element is nested but its owner is of a different type than the owners of other source elements (e.g., the first source element’s owner is a Category, but there are other source elements in the set that are owned by Global Set or Entry, etc.), then the eager loading map will only look through the Categories, and so other source element owners won’t be eager loaded as expected.

The fallback we have to get the primary owner if it wasn’t eager loaded will then fail because the primaryOwnerId is lost (set to null) in the process of eager loading. If the primaryOwner wasn’t found during eager loading, it’ll still be set as eager loaded as a null owner which will remove the primaryOwnerId from the nested element we were getting it for which will cause the fallback for getting the primaryOwner to fail.

(related to this change)

Solution:
When we reach the fallback for getting the nested element’s primary owner, and we can’t get the owner type, we should try to deduct it from the primaryOwnerId we had at the start of the method and only bail if we can’t get it that way too.

Related issues

n/a - from a query that @olivierbon was working on in support

@brandonkelly
Copy link
Copy Markdown
Member

This solution isn’t working for me in a similar test:

  • fresh Happy Lager install
  • assign the Contact Methods field to the global set
  • add a nested entry to the global set

Template:

{% for entry in craft.entries.field('contactMethods') %}
  <li>{{ entry.id }} - {{ entry.label }}, owner: {{ entry.getPrimaryOwner() }}</li>
{% endfor %}

Output:

254 - Main Office, owner: Happy Lager Chicago
2168 - Label, owner:
255 - Sales, owner: Happy Lager Chicago
256 - Fax, owner: Happy Lager Chicago

(getPrimaryOwner() isn’t returning anything for the nested entry within the global set.)

But regardless, the eager-loading added by 8cb3e36 is still important, so I don’t think this is the right approach.

Instead I’ve PR’d support for eager-loading elements of multiple element types at once (#16972). Combined with removing the elementType key from owner/primaryOwner eager-loading maps, I’m now getting the expected output:

254 - Main Office, owner: Happy Lager Chicago
2168 - Label, owner: Footer Content
255 - Sales, owner: Happy Lager Chicago
256 - Fax, owner: Happy Lager Chicago

@i-just can you confirm that you’re also seeing the expected output on your test with that PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants