Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- Fixed a bug where Content Block fields’ nested fields could be listed multiple times in element index column settings, when the same field was used by multiple entry types. ([#19197](https://github.com/craftcms/cms/pull/19197))
- Fixed a bug where the `site`/`siteId` params weren’t being respected on eager-loaded `localized` queries. ([#18588](https://github.com/craftcms/cms/issues/18588))
- Fixed a bug where it wasn’t possible to enter decimal values after tabbing into a Money field. ([#19156](https://github.com/craftcms/cms/issues/19156))
- Fixed a bug where the search inputs on the Entry Types and Fields settings index pages were case-sensitive on PostgreSQL. ([#19158](https://github.com/craftcms/cms/issues/19158))
Expand Down
73 changes: 65 additions & 8 deletions src/base/Element.php
Original file line number Diff line number Diff line change
Expand Up @@ -6238,24 +6238,81 @@ private function contentBlockAttributeHtml(string $attribute): string
{
$parts = explode('.', $attribute);
$uid = StringHelper::removeLeft(array_shift($parts), 'contentBlock:');
$layoutElement = $this->getFieldLayout()?->getElementByUid($uid);

if (!$layoutElement instanceof CustomField) {
return '';
$field = null;
$layoutElement = $this->getFieldLayout()?->getElementByUid($uid);
if ($layoutElement instanceof CustomField) {
try {
$field = $layoutElement->getField();
} catch (FieldNotFoundException) {
}
}

try {
$field = $layoutElement->getField();
} catch (FieldNotFoundException) {
return '';
if (!$field instanceof ContentBlockField) {
$field = $this->_contentBlockFieldFromLayoutElementUid($uid);
}

if (!$field instanceof ContentBlockField) {
return '';
}

$block = $this->getFieldValue($field->handle);
return $block->getAttributeHtml(implode('.', $parts));
return $block?->getAttributeHtml(implode('.', $parts)) ?? '';
}

/**
* Returns the Content Block field referenced by a table attribute key.
*
* Content Block table attributes are deduplicated across the layouts of an element source (see
* [[\craft\services\ElementSources::getTableAttributesForFieldLayouts()]]), so the layout element
* UID in the key may belong to a different entry type’s layout than this element’s. This resolves
* it to the matching instance — by field UID and effective handle — in this element’s own layout.
*
* (Separate from [[_getFieldFromAlternativeLayouts()]], which matches on the raw handle override
* and so can’t resolve Content Blocks that keep their default handle.)
*
* @param string $layoutElementUid
* @return ContentBlockField|null
*/
private function _contentBlockFieldFromLayoutElementUid(string $layoutElementUid): ?ContentBlockField
{
// Find the Content Block field + effective handle that the UID refers to,
// in any of this element type’s layouts
$fieldUid = null;
$handle = null;
foreach (Craft::$app->getFields()->getLayoutsByType(static::class) as $fieldLayout) {
$layoutElement = $fieldLayout->getElementByUid($layoutElementUid);
if (!$layoutElement instanceof CustomField) {
continue;
}
try {
$field = $layoutElement->getField();
} catch (FieldNotFoundException) {
continue;
}
if ($field instanceof ContentBlockField) {
$fieldUid = $field->uid;
$handle = $field->handle;
}
break;
}

if ($fieldUid === null) {
return null;
}

// Return the matching Content Block instance in this element’s own layout
foreach ($this->getFieldLayout()?->getCustomFields() ?? [] as $field) {
if (
$field instanceof ContentBlockField &&
$field->uid === $fieldUid &&
$field->handle === $handle
) {
return $field;
}
}

return null;
}

private function generatedFieldAttributeHtml(string $attribute): string
Expand Down
18 changes: 15 additions & 3 deletions src/services/ElementSources.php
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,8 @@ public function getTableAttributesForFieldLayouts(array $fieldLayouts): array
/** @var CustomField[][] $groupedFieldElements */
$groupedFieldElements = [];
$groupedFieldInstances = [];
/** @var CustomField[] $groupedContentBlocks */
$groupedContentBlocks = [];

foreach ($fieldLayouts as $fieldLayout) {
foreach ($fieldLayout->getTabs() as $tab) {
Expand All @@ -667,9 +669,11 @@ public function getTableAttributesForFieldLayouts(array $fieldLayouts): array
(!$user || $user->admin || ($layoutElement->getUserCondition()?->matchElement($user) ?? true))
) {
if ($field instanceof ContentBlock) {
foreach ($this->getTableAttributesForFieldLayouts([$field->getFieldLayout()]) as $key => $attribute) {
$attributes["contentBlock:{$field->layoutElement->uid}.$key"] = $attribute;
}
// Combine it with any other instances of the same Content Block field
// (from other layouts) that share the same handle, so its nested fields
// are only listed once
$key = $field->uid . ' - ' . ($layoutElement->handle ?? $field->handle);
$groupedContentBlocks[$key] ??= $layoutElement;
} elseif ($layoutElement->handle === null) {
// The handle wasn't overridden, so combine it with any other instances (from other layouts)
// where the handle also wasn't overridden
Expand All @@ -696,6 +700,14 @@ public function getTableAttributesForFieldLayouts(array $fieldLayouts): array
}
}

foreach ($groupedContentBlocks as $layoutElement) {
/** @var ContentBlock $field */
$field = $layoutElement->getField();
foreach ($this->getTableAttributesForFieldLayouts([$field->getFieldLayout()]) as $key => $attribute) {
$attributes["contentBlock:$layoutElement->uid.$key"] = $attribute;
}
}

foreach ($groupedFieldElements as $fieldElements) {
$field = $fieldElements[0]->getField();
$labels = array_unique(array_map(fn(CustomField $layoutElement) => $layoutElement->label(), $fieldElements));
Expand Down