Custom table orphans
Many modules keep their own tables with entity IDs in them: logs, metadata, hierarchy links, statistics. When the entity is deleted, core has no idea those rows exist, so they stay forever. Drupal Cleanup lets any module declare such tables in a small YAML file, and then removes rows whose entities are gone, both in the cron sweep and right after content is deleted.
No PHP is needed, and your module needs no dependency on Drupal Cleanup: without it, the file is ignored.
Declaring a table
Add MODULE.drupal_cleanup.yml to your module's root folder. Each top-level entry becomes its own task, with the ID custom_table_orphans:MODULE__KEY:
mymodule_log:
label: 'My module log rows for deleted content'
table: mymodule_log
key: id
references:
- { column: nid, entity_type: node }
- { column: uid, entity_type: user }
match: any| Key | Meaning |
|---|---|
label |
Optional. Shown in the admin UI and Drush. |
table |
The table name, without the database prefix. |
key |
The table's single-column primary key, used to back up and delete in chunks. |
references |
One or more columns holding entity IDs, and the entity type each one points at. |
match |
any (default): a row is an orphan when any reference is dead. all: only when every reference is dead. |
A reference is dead when its column is not NULL and no entity with that ID exists. NULL never counts as dead, so with match: all, a row with any NULL reference is kept.
queues and files are reserved top-level keys (see the queue and working-files pages). Rebuild caches after adding or editing the file.
Choosing references carefully
Only declare a column if the row is worthless once that entity is gone. For example, a hierarchy table might hold both the item's own node and its parent document's node. If a live item should keep its row even after its parent document is deleted, declare only the item's own column.
Reference columns should have the same type as the entity ID (usually an integer), so the check can join them directly.
When a declaration is wrong
If the table, the key column, a reference column or the entity type doesn't exist, the task reports why and does nothing, for example table mymodule_log does not exist or misconfigured: column mymodule_log.nid does not exist. Check with:
drush cleanup:listA missing table is common on sites where your module creates it lazily; the task simply starts working once the table exists.
Cleanup right after content is deleted
When content is deleted through the entity API, rows in declared tables that pointed at it are removed at the end of the same request: after the response is sent, or when the Drush command finishes. All deletes in one request become one backed-up run with batched queries, so a bulk delete of thousands of nodes makes a single backup, not thousands.
A problem at that point is logged and never undoes or blocks the delete; the cron sweep picks up whatever is left. Turn this off with Clean up immediately when content is deleted at Configuration » System » Cleanup if you prefer to leave everything to cron.
Running it
drush cleanup:run --task=custom_table_orphans:mymodule__mymodule_log --dry-run
drush cleanup:run --task=custom_table_orphans:mymodule__mymodule_logEach run backs up the exact rows it removes first; drush cleanup:restore {backup-id} puts them back.
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion