Problem/Motivation
The content_first_audit submodule processes heading audits using procedural hooks (hook_node_insert, hook_node_update,
hook_node_delete) that run synchronously on every node save. This approach has several limitations:
- No tracking or retry logic — if an audit fails (e.g. rendering error, database issue), the failure is silent and unrecoverable without manually re-saving the node.
- No bulk coverage — there is no way to audit existing content created before the module was installed, or to re-audit all content after analyzer improvements.
- Synchronous rendering on every save — full node render + DOMDocument parsing runs in the request lifecycle, adding latency to every node save.
- No admin visibility — administrators cannot see which nodes have been audited, which failed, or trigger re-processing.
Steps to reproduce
- Install
content_first_auditon a site with existing content. - Observe that only newly saved nodes get heading audits — existing content has no audit data.
- Cause a transient error during a node save (e.g. database timeout) — the audit silently fails with no way to retry.
Proposed resolution
Integrate content_first_audit with the Entity Registry module by:
- Creating a
ContentAuditConsumerplugin (#[EntityRegistryConsumer]) that implementsprocessItem()(load entity → get translation → render → XPath headings → analyze → upsert) anddeleteItem()(remove audit data for deleted translations). - Removing the procedural hooks (
hook_node_insert,hook_node_update,hook_node_delete) and the_content_first_audit_process_node()
helper — entity lifecycle tracking is now handled by Entity Registry. - Setting
processing_mode: 'async'so heading audits run via cron queue instead of synchronously on every save. - Adding a
deleteByEntityAndLanguage()method toAuditRepositoryInterface/AuditRepositoryfor per-translation cleanup. - Adding a migration update hook (
content_first_audit_update_10001) that seeds theentity_registrytracker table with PROCESSED records for all existing audit
data, so Entity Registry knows which nodes have already been audited.
Remaining tasks
- Review and commit the implementation.
- Test migration update hook on a site with existing audit data.
User interface changes
None in content_first_audit itself. Administrators can use the Entity Registry admin UI at /admin/config/system/entity-registry to see the Content Audit consumer status (pending/processed/failed counts), trigger bulk populate, reindex, or retry failed items.
API changes
AuditRepositoryInterface— new method:deleteByEntityAndLanguage(int $entity_id, string $entity_type, string $language): void- New dependency:
entity_registry:entity_registry - Removed:
hook_node_insert(),hook_node_update(),hook_node_delete(),_content_first_audit_process_node()
Data model changes
No schema changes to the content_first_audit table. The migration update hook (content_first_audit_update_10001) inserts records into the entity_registry table (provided by the Entity Registry module) with status PROCESSED for all existing audit entries, using cursor-based pagination in chunks of 1000.
Issue fork content_first-3578623
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
eduardo morales albertiComment #4
eduardo morales albertiReady to review
Comment #5
eduardo morales albertiComment #7
eduardo morales alberti