Problem/Motivation

When a paragraph reference is removed from a paragraphs field and the parent entity is saved, the removed paragraph entity can remain in the database as an orphaned entity.

For example:

Article A has a field_paragraphs field referencing Paragraph B.

Paragraph B is removed from the field on Article A.

Article A is saved.

Paragraph B is no longer referenced by the current revision of Article A, but the paragraph entity remains in the database.

This can happen frequently on sites where editors regularly add, reorder, and remove paragraphs. Over time, this can result in a large number of orphaned paragraph entities and related database records.

It can also pollute entity usage statistics and make it difficult to distinguish paragraphs that are actually in use from paragraphs that are no longer referenced by any current or historical revision.

This case is different from the scenario addressed by https://www.drupal.org/project/paragraphs/issues/2935630, where the parent entity itself is deleted and hook_entity_delete() can be used to cascade-delete its paragraphs.

Here, the parent entity is still present and is simply being updated with one or more paragraph references removed.

Steps to reproduce

Create an Article with a paragraphs field.

Add a paragraph to the field and save the Article.

Confirm that the Article references the paragraph.

Remove the paragraph from the field.

Save the Article.

Inspect the paragraph entity and/or entity usage data.

The removed paragraph remains in the database even though it is no longer referenced by the current revision of the Article.

Proposed resolution

Detect paragraph references that are removed when a parent entity is updated and delete paragraphs that are no longer referenced by any revision of the parent entity.

The implementation should:

Compare the paragraph references before and after the parent entity is saved.

Identify paragraph entities that were removed from the field.

Check whether each removed paragraph is still referenced by any revision of the parent entity.

Only delete the paragraph when no revision of the parent entity references it anymore.

Ensure that paragraphs still referenced by an older revision are retained.

The behaviour should be limited to genuinely orphaned paragraphs. Paragraphs that are still referenced by another revision must not be deleted.

This would provide synchronous cleanup at save time for paragraphs that become orphaned as a result of editing a paragraphs field, complementing the existing orphan cleanup mechanism.

Remaining tasks

Implement detection of paragraph references removed during entity updates.

Verify references across all revisions of the parent entity before deleting a paragraph.

Delete paragraphs that are no longer referenced by any revision.

Add test coverage for removing paragraphs from a field.

Add test coverage ensuring paragraphs referenced by older revisions are preserved.

Add test coverage for multiple removed paragraphs and multiple revisions.

User interface changes

None.

API changes

None expected.

Data model changes

No schema changes are expected.

The change would remove orphaned paragraph entities and their associated entity-reference data when they are no longer referenced by any revision of the parent entity.

Comments

pavel ruban created an issue. See original summary.

pavel ruban’s picture

Issue summary: View changes