Architecture & Plugin System
When to Use
You need to understand how Custom Field's plugin system works to extend it with custom field types, widgets, or formatters, or to debug plugin discovery issues.
Pattern
Six plugin-discovery managers (defined in custom_field.services.yml):
plugin.manager.custom_field_type:
class: Drupal\custom_field\Plugin\CustomFieldTypeManager
# Discovers #[CustomFieldType] plugins in /Plugin/CustomField/FieldType/
plugin.manager.custom_field_widget:
class: Drupal\custom_field\Plugin\CustomFieldWidgetManager
# Discovers #[CustomFieldWidget] plugins in /Plugin/CustomField/FieldWidget/
plugin.manager.custom_field_formatter:
class: Drupal\custom_field\Plugin\CustomFieldFormatterManager
# Discovers plugins in /Plugin/CustomField/FieldFormatter/ -- note the attribute is
# CORE's Drupal\Core\Field\Attribute\FieldFormatter, not a custom_field one
plugin.manager.custom_field_feeds:
# Discovers #[CustomFieldFeedsType] plugins in /Plugin/CustomField/FeedsType/
plugin.manager.custom_field_link_attributes:
# Discovers link-attribute plugins used by link columns
plugin.manager.custom_field_component_prop_widget:
# NEW in 5.x -- class Drupal\custom_field\PluginManager\PropWidgetManager
# (src/PluginManager/, NOT src/Plugin/). Discovers #[PropWidget] plugins in
# Plugin/Components/PropWidget/, which map sub-fields onto SDC component props.
# Aliased to PropWidgetManagerInterface, so it autowires by interface.
Plus custom_field.tag_manager. Only the prop-widget manager is new in 5.x; the feeds, link-attributes and tag managers already existed in 4.x and were simply undocumented.
Main field type: CustomItem (plugin ID custom) -- single field type with dynamic columns defined via settings. Uses CustomItemList as list class.
Column separator constant: CustomItem::SEPARATOR = '__' -- used for extended properties like image__alt, link__title.
Key services:
plugin.manager.custom_field_type-- FieldType plugin managerplugin.manager.custom_field_widget-- Widget plugin managerplugin.manager.custom_field_formatter-- Formatter plugin managerplugin.manager.custom_field_feeds-- Feeds target plugin managerplugin.manager.custom_field_link_attributes-- Link attribute plugin managerplugin.manager.custom_field_component_prop_widget-- SDC prop widget plugin manager (5.x)custom_field.update_manager-- Handles schema updates for existing fieldscustom_field.generate_data-- Generates sample datacustom_field.tag_manager-- Tag handling
In 5.x both services also autowire by interface: type-hint \Drupal\custom_field\Service\UpdateManagerInterface or \Drupal\custom_field\Service\GenerateDataInterface in a constructor and the container resolves it.
Hook classes (OO #[Hook] only -- 5.x deleted every .module file and the procedural #[LegacyHook] shims with them):
GeneralHooks-- General hooksFormHooks-- Form alterationsThemeHooks-- Theme preprocessingTokenHooks-- Token definitionsViewsHooks-- Views integrationEntityHooks-- Node insert/update maintenance of the taxonomy index, plusentity_view_display_presave. In 5.x the node hooks declare#[Hook('node_update', order: Order::Last)], replacing thehook_module_implements_alter()reordering 4.x used
Other integrations shipped in the main module (not sub-modules):
- Entity Usage tracking --
src/Plugin/EntityUsage/Track/:CustomField(pre-existing), plusCustomFieldLinkandCustomFieldTextnew in 5.x custom_field_multivalueform element --src/Element/MultiValue.php,#[FormElement('custom_field_multivalue')], new in 5.x
Common Mistakes
- Calling plugin managers statically -- Inject via dependency injection, don't use
\Drupal::service()in classes - Assuming core field plugin discovery -- Custom Field has its own plugin namespaces under
/Plugin/CustomField/, not/Plugin/Field/ - Not clearing cache after adding plugins -- Plugin definitions are cached; run
drush crafter creating new plugins
See Also
- Reference:
/modules/contrib/custom_field/src/Plugin/CustomFieldTypeManager.php - Reference:
/modules/contrib/custom_field/custom_field.services.yml - Custom Field Overview