Content locking (anti-concurrent editing)
Prevents multiple users from editing a content entity simultaneously by implementing pessimistic locking that automatically locks content when editing begins and releases it on save or navigation away.
content_lock
Install
composer require 'drupal/content_lock:8.x-2.4'
composer require 'drupal/content_lock:8.x-2.2'
Overview
The Content Lock module implements a pessimistic locking strategy to prevent edit conflicts on busy sites with dynamic content. When a user starts editing an entity, it is exclusively locked, preventing other users from making changes until the lock is released.
Locks are automatically released when the form is submitted or when the user navigates away. The module supports locking at the entity level, translation level (with Conflict module), and form operation level. Stale locks can be automatically released after a configurable timeout period via cron.
Administrators with the 'Break content lock' permission can forcefully release locks held by other users. The module provides comprehensive Views integration for displaying and managing locked content, including a pre-built view accessible at /admin/content/locked-content.
Features
- Pessimistic locking that exclusively locks content when a user begins editing, preventing simultaneous editing conflicts
- Automatic lock release when form is submitted, user logs out, or user session ends
- Configurable timeout for automatic release of stale locks via cron (default 30 minutes)
- Per-entity-type and per-bundle locking configuration with 'All' option for quick setup
- Translation-level locking support when Conflict module is installed, allowing concurrent editing of different translations
- Form operation-level locking with allowlist and denylist modes for granular control over which form operations trigger locking
- Break lock functionality allowing administrators to forcefully release locks held by other users
- Pre-built Views page at /admin/content/locked-content showing all currently locked nodes with bulk unlock action
- Comprehensive Views integration with fields, filters, sorts, and relationships for lock data
- Entity operations integration adding 'Break lock' option in entity listings for locked content
- Event-driven architecture with ContentLockLockedEvent and ContentLockReleaseEvent for extensibility
- Integration with Trash module to prevent unnecessary locking of trashed entities
- Verbose mode option to display informative messages when content is locked or accessed while locked
Use Cases
Preventing edit conflicts on editorial workflows
On a news site with multiple editors, enable content locking for the 'article' node type. When Editor A opens an article for editing, it becomes locked. If Editor B tries to edit the same article, they see a message indicating it is locked by Editor A. This prevents the frustrating scenario where Editor B's changes are lost because Editor A saved first.
Managing concurrent translation work
For a multilingual site with multiple translators, install the Conflict module and enable 'Lock only on entity translation level' for nodes. This allows the German translator to work on the German version while the French translator simultaneously edits the French version of the same content, without conflicts.
Selective form operation locking
Configure form operation locking in denylist mode and exclude the 'delete' operation. This allows users to delete content even while another user is editing it (useful for content managers who need to remove outdated content quickly), while still protecting the edit operation from concurrent access.
Monitoring and managing locks
Use the built-in 'Locked content' view at /admin/content/locked-content to monitor all currently locked nodes. Content managers with 'break content lock' permission can use the bulk operation to release multiple stale locks at once, or use the 'Break lock' link in entity operations.
Automatic lock cleanup via timeout
Set the lock timeout to 30 minutes in the settings. When users forget to close edit forms (navigating away without saving or canceling), the locks are automatically released by cron after 30 minutes, ensuring content doesn't remain locked indefinitely.
Tips
- Always set a timeout value to automatically release forgotten locks - the recommended default is 30 minutes (1800 seconds)
- Use the 'All' (*) bundle option when first enabling locking for an entity type, then refine to specific bundles if needed
- Grant the 'break content lock' permission to site administrators and content managers who need to resolve lock conflicts
- For customizing lock messages, consider using the String Overrides module (https://www.drupal.org/project/stringoverrides)
- Implement hook_content_lock_entity_lockable() to programmatically exclude specific entities from locking based on custom business logic
- Subscribe to ContentLockLockedEvent and ContentLockReleaseEvent to integrate with notification systems or logging
- The content_lock service can be injected into custom code to programmatically check, acquire, or release locks
Technical Details
Admin Pages 3
/admin/config/content/content_lock
Main configuration page for setting up content locking behavior, selecting protected entity types and bundles, and configuring timeout settings.
/admin/content/locked-content
Views page displaying all currently locked nodes with information about lock owner, timestamp, and language. Provides bulk operations to break locks and individual entity operations.
/admin/lock/break/{entity_type}/{entity}/{langcode}/{form_op}
Confirmation form to break a content lock on a specific entity. Dynamically generated for each enabled entity type.
Permissions 2
Hooks 1
hook_content_lock_entity_lockable
Determine whether an entity is lockable. Called from isLockable() to allow modules to programmatically control which entities can be locked. If this hook returns FALSE for an entity, any existing locks will be ignored.
Troubleshooting 5
Configure a reasonable timeout value (e.g., 30 minutes) in the Content Lock settings. Locks will be automatically released by cron after this period. Ensure cron is running regularly on your site.
The 'Lock only on entity translation level' option requires the Conflict module to be installed. Install and enable the Conflict module (https://www.drupal.org/project/conflict) to enable this feature.
Content Lock automatically disables caching for views that include lock data. If you're still experiencing issues, verify the view's cache settings are set to 'None' and clear all caches.
By design, users without the 'break content lock' permission cannot delete content locked by others. Grant the 'break content lock' permission or configure form operation locking to exclude the delete operation from locking.
Ensure the form is properly submitting (not just navigating away). The lock release happens in the form submit handler. Check for JavaScript errors that might prevent form submission.
Security Notes 3
- The 'break content lock' permission should be granted carefully as it allows users to override locks set by other users
- Content Lock prevents deletion of locked content by users without break permission, protecting against accidental data loss
- The module uses database-level locking (content_lock table) and Drupal's lock service to prevent race conditions when acquiring locks