Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

[5.x]: Block added through a draft gets an empty first revision on multi-site, so reverting deletes its nested content

Đang mở
#20,151 1 bình luận 0 reaction 1 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@i-just đang làm issue này rồi.

Từ ngày 29/10/2026.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
45/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
php
Lĩnh vực
backend, databases

Hướng nghiên cứu

Start by tracing NestedElementManager::duplicateNestedElements() through Elements::duplicateElement() and the propagation saves described in the report. Then read Entry::beforeSave() and Revisions::createRevision() to follow when the initial revision is created and reused. Reproduce the multi-site setup and confirm the fix by checking that revision 2 retains the nested entry after reverting.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

bug repo:cms
What happened?
Description

On a multi-site install, when a new nested entry is added to a versioned Matrix field through a draft (any edit of a live entry), Craft saves that nested entry's first revision before its own nested entries are copied. The owner's revision reuses that empty revision, and so does every later owner revision until the nested entry changes. Reverting the owner to any of those revisions deletes the nested content from the canonical entry.

Reproduced on a fresh craftcms/craft project (Craft 5.11.5.1, no plugins, no modules) with:

  • 2 sites in one group.
  • Channel section "Pages", versioning on, propagation "All sites", enabled for both sites.
  • Entry type page: title + Matrix field blocks (view mode "Cards", "Enable versioning for entries in this field" on, propagation "All sites"), entry type block.
  • Entry type block: title + Matrix field innerBlocks (view mode "Blocks", versioning off, propagation "All sites"), entry type child.
  • Entry type child: title + Plain Text field body.

The same steps in a section enabled for one site only don't reproduce it: the block's revision is then created after its inner entry and is complete.

What happens on save, traced with a backtrace on Revisions::EVENT_BEFORE_CREATE_REVISION:

  1. Saving the live entry applies its provisional draft. NestedElementManager::duplicateNestedElements() copies the new block (owned by the draft) with duplicateElement() (NestedElementManager.php:1164), passing 'propagating' => false in $newAttributes (NestedElementManager.php:1104).
  2. Elements::duplicateElement() saves the block for the first site, then clones it for each other site and sets $siteClone->propagating = true (Elements.php:2046), but Craft::configure($siteClone, $newAttributes) (Elements.php:2072) sets it back to false.
  3. So the second site's save (Elements.php:2102) is a non-propagating save of an existing entry with no revisions. Entry::beforeSave() ("Make sure the entry has at least one revision", Entry.php:2934) creates a revision from the DB, while the block exists in one site only and has no nested entries yet. The revision note is "Revision from {date}".
  4. The block's nested entries are copied afterwards, in afterPropagate(). The next revision request for the block (from Entry::afterPropagate(), then from the owner's revision) is short-circuited in Revisions::createRevision() (Revisions.php:109): the block's dateUpdated equals the empty revision's dateCreated, so the empty revision is returned and reused.

Element IDs on the fresh install show the order:

ID Element
#15 new block "Block B" (canonical)
#16 its revision, note "Revision from Oct 28, 2026, 3:11:48 PM PDT", no inner entry
#17 its inner child entry "Child B"
#18 owner revision 2 ("Applied “Draft 1”"), which owns #16

After "Revert content from this revision" on revision 2, #17 is soft-deleted and the live block #15 has no inner entry.

We also tested the fix for #19594 (commit 53cba141) on 5.11.5.1: it doesn't change this. The nested entry's owners get their dateUpdated bumped, but to the same second, and the comparison uses the in-memory block.

Workaround (verified on our own project): turning off "Enable versioning for entries in this field" on the outer Matrix field. Blocks then get no revision of their own, and the owner revision snapshots them after their nested entries exist.

Steps to reproduce
  1. On a multi-site install, set up the section and fields above.
  2. Create a page with one block ("Block A", with an inner entry with some body text) and save it. Revision 1 is complete.
  3. Edit the live page, add a second block ("Block B"), add its inner entry with some body text, save the block's slideout, then save the page (revision 2).
  4. View revision 2: "Block B" has no inner entry.
  5. Revert to revision 2 ("Revert content from this revision").
Expected behavior

Revision 2 contains "Block B" with its inner entry, and reverting to it keeps that content.

Actual behavior

Revision 2's copy of "Block B" has no inner entry, and reverting to it deletes the inner entry (and its body text) from the live page.

Craft CMS version

5.11.5.1 (Pro, trial)

PHP version

8.5.11

Operating system and version

Linux (Docker, Alpine 3.24.2)

Database type and version

MySQL 8.4

Image driver and version

Imagick 3.8.1 (ImageMagick 7.1.2-30)

Installed plugins and versions

None (fresh craftcms/craft project)

Ngôn ngữ chính
PHP
Star
3.6k
Fork
710
Merge trung bình
11 giờ 26 phút
Pull request đã merge (30 ngày)
324

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của craftcms/cms

Tất cả issue của craftcms/cms

Issue tương tự

Thêm issue về PHP

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.