Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

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

Abierto
#20,151 1 comentario 0 reacciones 1 asignado Ver en GitHub

Los mantenedores suelen responder en 1 día

@i-just ya está trabajando en esto.

Desde el 29/10/2026.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
45/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
php

Línea de trabajo

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.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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)

Lenguaje dominante
PHP
Estrellas
3.6k
Forks
710
Merge medio
12 h 44 min
PR fusionados (30 d)
335

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de craftcms/cms

Todos los issues de craftcms/cms

Issues similares

Más issues de PHP

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.