entity_registry
Entity Registry provides a generic entity tracking infrastructure for Drupal. It automatically detects when content is created, updated, or deleted and dispatches those changes to consumer plugins that is defined, such as search indexes, audit systems, or external API syncs.
If you need a reliable, centralized way to keep external systems or internal indexes in sync with your Drupal content, Entity Registry gives you the framework so you only write the processing logic.
Features
- Consumer plugin system: Define what happens when content changes by creating a PHP class with a
#[EntityRegistryConsumer]attribute
extendingEntityRegistryConsumerBase. Implement two methods:processItem()anddeleteItem(). Override
shouldProcessItem()to filter which entities your consumer handles. - Automatic entity tracking: Every insert, update, and delete on tracked entity types is captured per translation, with no manual wiring
needed. - Processing phases: Each
processItem()call receives a$phaseargument indicating how it was triggered:save(on entity save),cron(via queue worker), orbatch(via admin UI or Drush). - Full status lifecycle: Each tracked item moves through PENDING, PROCESSED or FAILED, with automatic retry up to a configurable limit.
- Multilingual support: Each translation is tracked and processed independently.
- Admin bundle configuration: Administrators can restrict which entity types and bundles a consumer tracks via a per-consumer configuration form, without modifying plugin code.
- Bulk operations: Populate, Process, Queue, Retry Failed, Clear, and Rebuild are all available via the admin UI and Drush, with Batch API support for large datasets.
- Concurrency safety: Optimistic locking via atomic claim queries and distributed locks prevents double-processing.
- Admin dashboard: Overview page showing all consumers with live status counts (pending, processed, failed) and links to per-consumer detail pages.
- Drush integration: All bulk operations are available as Drush commands for use in scripts and CI pipelines.
When to use this module: Use Entity Registry when you have one or more systems that need to react to Drupal entity changes, including search engines, analytics pipelines, content audits, external API synchronization, cache warming, or any scenario where you need reliable, trackable processing of entity lifecycle events.
Post-Installation
- Navigate to Administration / Configuration / System / Entity Registry (
/admin/config/system/entity-registry). - The overview page lists all registered consumers. If no consumer modules are installed yet, the table will be empty. You need at least one consumer plugin (see below).
- Click Settings to configure global options:
- Enable cron processing: Whether items are processed on cron (default: enabled).
- Batch size: Number of items processed per consumer per cron run (default: 50).
- Chunk size: Size of database operation chunks for bulk inserts (default: 1000).
- For each consumer, the detail page provides:
- Populate: Create initial tracking records for all existing content.
- Process: Run batch processing for all pending items immediately.
- Queue all: Reset all tracked items to PENDING for reprocessing.
- Retry failed: Reset all FAILED items to PENDING.
- Clear: Delete consumer-stored data and mark all items PENDING.
- Rebuild: Delete all tracking records and re-discover matching entities from scratch.
Creating a Consumer Plugin
In your custom module, create a class at src/Plugin/EntityRegistryConsumer/MyConsumer.php extending EntityRegistryConsumerBase with the #[EntityRegistryConsumer] attribute. The attribute accepts only id and label.
Filtering logic goes in shouldProcessItem():
namespace Drupal\my_module\Plugin\EntityRegistryConsumer; use Drupal\entity_registry\Attribute\EntityRegistryConsumer; use Drupal\entity_registry\Plugin\EntityRegistryConsumerBase; use Drupal\Core\StringTranslation\TranslatableMarkup; #[EntityRegistryConsumer( id: 'my_consumer', label: new TranslatableMarkup('My Consumer'), )] final class MyConsumer extends EntityRegistryConsumerBase { public function shouldProcessItem( string $entity_type, int $entity_id, string $bundle, string $langcode, ): bool { // Only process article nodes. return $entity_type === 'node' && $bundle === 'article'; } public function processItem( string $entity_type, int $entity_id, string $langcode, string $phase, ): bool { // Your processing logic here. return TRUE; } public function deleteItem( string $entity_type, int $entity_id, string $langcode, ): bool { // Clean up when entity is deleted. return TRUE; } }
Clear caches after creating your plugin. It will appear automatically on the Entity Registry overview page.
Drush Commands
All bulk operations are available as Drush commands:
drush entity-registry:status [consumer_id](er-status): Show status for all or one consumer.drush entity-registry:process <consumer_id>(er-process): Process pending items. Supports--limitand
--batch-sizeoptions.drush entity-registry:queue <consumer_id>(er-queue): Mark all tracked items as PENDING.drush entity-registry:retry <consumer_id>(er-retry): Reset all FAILED items to PENDING.drush entity-registry:clear <consumer_id>(er-clear): Clear consumer-stored data and mark all items PENDING.drush entity-registry:rebuild <consumer_id>(er-rebuild): Delete all tracking records and re-discover matching entities.
Additional Requirements
Entity Registry requires Drupal 10.3 or 11 (core only, with no contributed module dependencies). PHP 8.1 or higher is required for attribute-based
plugin discovery.
Recommended modules/libraries
- Ultimate Cron: Provides fine-grained control over cron frequency when you need more
frequent processing than the default Drupal cron interval.
Similar projects
- Search API: A full search framework with indexing, backends (Solr, Elasticsearch,
database), and Views integration. Entity Registry is lower-level and more generic, tracking entity changes and dispatching them to arbitrary consumer plugins rather than
just search backends. Use Search API if you need search; use Entity Registry if you need a lightweight, general-purpose entity change tracking and processing pipeline. - Hook Event Dispatcher: Converts Drupal hooks to Symfony events. It dispatches events but does not provide tracking, status management, retry logic, or async queuing. Entity Registry adds the persistence and reliability layer on top of entity lifecycle events.
Supporting this Module
Entity Registry is maintained by Metadrop. If you find this module useful, consider:
- Contributing bug reports and feature requests in the issue queue
- Submitting patches or merge requests
- Writing and sharing your own consumer plugins
Modules that integrate with Entity Registry
The following modules use Entity Registry as their processing backbone and serve as real-world examples of consumer plugin implementations:
- Entity Mesh: Builds a graph of relationships between content entities by rendering each translation, extracting all internal links, iframes, and images, and storing the resolved source-target pairs in a dedicated table. The result is a queryable mesh of content dependencies across the site.
- Content First (Audit submodule): The
content_first_auditsubmodule registers a consumer that renders each node translation, extracts heading elements via XPath, and stores H1 count and hierarchy validity per entity and language. The data is exposed via a Views-based report and the Drupal status page.
Community Documentation
Documentation is available in the project's issue queue. Contributions to documentation, including walkthroughs, tutorials, and example consumer plugins, are
welcome.