What happened?
Description
I'm migrating a large site from Craft 4 to 5. There were a lot of Matrix fields with blocks that used the same handle. These were renamed on migration to avoid conflicts e.g. copy -> copy2.
There's quite a lot of template code with conditionals that rely on .type() filter specific matrix blocks.
e.g {{ entry.pageContent.type('copy').all() }}
Since 5.6.0, an entry type's name/handle can be overridden per field usage (e.g. when adding an entry type to a Matrix field), via craft\services\Entries::getEntryType() / EntryType::$original. This override is reflected everywhere the field resolves its own entry types — e.g. Entry::getType()->handle inside a Matrix field context, and the CP's entry type chip for that field.
However, craft\elements\db\EntryQuery::type() does not seem to honor this override. For a string value, it resolves the handle via Entries::getEntryTypeByHandle(), which only checks each entry type's real/global handle column.
Result: filtering entry.someMatrixField.type('overriddenHandle') returns nothing, even though the CP and .type.handle both show overriddenHandle as the entry type's handle for that field. The real (global, often auto-renamed-on-upgrade) handle must be used instead.
Steps to reproduce
- Create an entry type Foo, real handle
foo.
- Create a second entry type Bar, real handle
bar.
- Add entry type Bar to a Matrix field, overriding its per-usage handle to
foo (so it displays as foo for that field only).
- Create an entry in that Matrix field using entry type Bar.
- In a template:
{{ entry.myMatrixField.type('foo').all() }} → returns null.
{{ entry.myMatrixField.type('bar').all() }} → returns the expected entries.
- Meanwhile
{{ entry.type.handle }} on those same entries prints foo, matching the CP and step 5's expectation, not step 6's.
Expected behavior
.type('foo') should match, since that's the handle the field/CP presents as authoritative for that usage.
Actual behavior
.type() only ever matches an entry type's real global handle, returning zero results for the override handle, with no warning that the override isn't query-able.
The upgrade migration auto-renamed colliding block types (e.g. copy, copy2, copy3) and applied the original shared name as a per-field handle override to preserve the old UX in the CP. Existing templates that filtered by the pre-upgrade handle now returns nothing on these fields.
Craft CMS version
5.10.14
PHP version
8.4
Operating system and version
No response
Database type and version
No response
Image driver and version
No response
Installed plugins and versions
What happened?
Description
I'm migrating a large site from Craft 4 to 5. There were a lot of Matrix fields with blocks that used the same handle. These were renamed on migration to avoid conflicts e.g.
copy->copy2.There's quite a lot of template code with conditionals that rely on .type() filter specific matrix blocks.
e.g
{{ entry.pageContent.type('copy').all() }}Since 5.6.0, an entry type's name/handle can be overridden per field usage (e.g. when adding an entry type to a Matrix field), via craft\services\Entries::getEntryType() / EntryType::$original. This override is reflected everywhere the field resolves its own entry types — e.g. Entry::getType()->handle inside a Matrix field context, and the CP's entry type chip for that field.
However, craft\elements\db\EntryQuery::type() does not seem to honor this override. For a string value, it resolves the handle via Entries::getEntryTypeByHandle(), which only checks each entry type's real/global handle column.
Result: filtering entry.someMatrixField.type('overriddenHandle') returns nothing, even though the CP and .type.handle both show overriddenHandle as the entry type's handle for that field. The real (global, often auto-renamed-on-upgrade) handle must be used instead.
Steps to reproduce
foo.bar.foo(so it displays as foo for that field only).{{ entry.myMatrixField.type('foo').all() }}→ returnsnull.{{ entry.myMatrixField.type('bar').all() }}→ returns the expected entries.{{ entry.type.handle }}on those same entries printsfoo, matching the CP and step 5's expectation, not step 6's.Expected behavior
.type('foo')should match, since that's the handle the field/CP presents as authoritative for that usage.Actual behavior
.type()only ever matches an entry type's real global handle, returning zero results for the override handle, with no warning that the override isn't query-able.The upgrade migration auto-renamed colliding block types (e.g. copy, copy2, copy3) and applied the original shared name as a per-field handle override to preserve the old UX in the CP. Existing templates that filtered by the pre-upgrade handle now returns nothing on these fields.
Craft CMS version
5.10.14
PHP version
8.4
Operating system and version
No response
Database type and version
No response
Image driver and version
No response
Installed plugins and versions