FormAlter as Plugin
Provides a plugin-based system for form alterations, replacing traditional hook_form_alter() implementations with object-oriented plugins.
pluginformalter
Install
composer require 'drupal/pluginformalter:8.x-1.8'
composer require 'drupal/pluginformalter:8.x-1.7'
Overview
FormAlter as Plugin is a developer utility module that modernizes how Drupal forms are altered. Instead of using the traditional procedural hook_form_alter() approach, developers can create object-oriented plugins with annotations to modify forms. This approach brings better code organization, dependency injection support, and clearer separation of concerns.
The module supports three types of form alterations: standard Drupal forms (by form_id or base_form_id), Paragraphs widget forms (by paragraph_type), and Inline Entity Form forms (by entity_type and bundle). Each plugin type comes with its own annotation and manager service, allowing for precise targeting of specific forms.
Additionally, the module integrates with the Webprofiler module to display which plugins are altering each form in the debug toolbar, making development and debugging easier.
Note: As of Drupal 11.2, this module triggers deprecation warnings because Drupal core now supports OOP Hooks natively. The module will stop functioning in Drupal 12.0.0, and developers should migrate to core's OOP Hooks instead.
Features
- Plugin-based form alteration system replacing hook_form_alter() with object-oriented approach
- Support for targeting forms by form_id or base_form_id with wildcard matching
- Paragraphs module integration for altering paragraph type widget forms
- Inline Entity Form module integration for altering IEF entity forms, reference forms, and table fields
- Weight-based plugin ordering to control the sequence of form alterations
- Multiple plugins can alter the same form with predictable execution order
- Webprofiler integration showing all form alter plugins in the debug toolbar
- Full dependency injection support through ContainerFactoryPluginInterface
- String translation trait included in base class for localization support
Use Cases
Organizing Form Alterations by Domain
Create separate FormAlter plugins for each functional area of your application. For example, create UserLoginFormAlter for login modifications, NodeFormAlter for content editing, and CommerceCheckoutFormAlter for e-commerce. Each plugin encapsulates its logic cleanly with dependency injection.
Altering All Node Forms
Use base_form_id targeting to alter all node forms at once. Create a plugin with @FormAlter(id = "node_form_base_alter", base_form_id = {"node_form"}) to add common functionality like custom validation or field modifications across all content types.
Conditional Form Alterations
Combine the plugin system with conditional logic inside the formAlter() method. The plugin is instantiated only when the target form is rendered, and you can add additional runtime conditions within your implementation.
Targeting Specific Paragraphs Types
When working with the Paragraphs module, create ParagraphsFormAlter plugins to customize specific paragraph type forms. For example, modify the image paragraph widget to add custom JavaScript behaviors or validation.
Extending Inline Entity Forms
Use InlineEntityFormAlter plugins to customize how entities are embedded in forms. Target specific entity types and bundles, or modify the table fields display for entity reference lists.
Controlling Alteration Order
When multiple plugins alter the same form, use the weight property to control execution order. Lower weights execute first. This is essential when one alteration depends on another's changes.
Debugging Form Alterations
When Webprofiler is enabled, the module displays all FormAlter plugins affecting each form in the debug toolbar. This helps identify which plugins are modifying forms and trace unexpected behavior.
Tips
- Plugin classes must be placed in src/Plugin/FormAlter/ directory to be discovered
- Use wildcard patterns (e.g., 'node_*_form') in form_id to target multiple forms
- The base class FormAlterBase includes StringTranslationTrait and DependencySerializationTrait for convenience
- Implement ContainerFactoryPluginInterface (included in FormAlterBase) to inject services into your plugins
- Plugins support both form_id and base_form_id targeting; base_form_id alterations run before form_id alterations
- As of Drupal 11.2+, consider migrating to core's OOP Hooks feature instead of this module
- Clear caches after adding or modifying plugins for changes to take effect
Technical Details
Hooks 1
pluginformalter_form_alter_info_alter
Alter the form alter plugin definitions discovered by any of the three plugin managers.
Troubleshooting 5
Ensure your plugin is in the correct namespace (Drupal\yourmodule\Plugin\FormAlter), has the correct annotation (@FormAlter, @ParagraphsFormAlter, or @InlineEntityFormAlter), and clear all caches.
Adjust the weight property in your plugin annotations. Lower weights execute first. Use pluginformalter_form_alter_info_alter hook to modify weights at runtime if needed.
These warnings indicate the module is deprecated in favor of Drupal core's OOP Hooks. Plan migration to core's hook_form_alter OOP implementation before upgrading to Drupal 12.
Ensure both the pluginformalter and webprofiler modules are enabled. Clear caches to ensure the service provider decorates the forms data collector correctly.
Verify you're using the @ParagraphsFormAlter annotation (not @FormAlter) and that the paragraph_type matches exactly. The paragraph_type should be the machine name of your paragraph type.