Problem/Motivation
In Drupal 11, hook_module_implements_alter no longer guarantees hook execution order due to the new hook system (HookCollectorPass). The entity_form_steps module relies on its hook_form_alter running after field_group's hook_form_alter, ensured via entity_form_steps_module_implements_alter(). When the ordering fails, $form['#fieldgroups'] is not populated when EntityFormSteps::alterForm() executes.
This causes a cascade of failures:
setAccess()cannot hide fields on inactive steps because theisset($form['#fieldgroups'][$stepName])check fails, so fields from all steps remain visible.setValidation()cannot populate#limit_validation_errorsfor the current step's fields.#limit_validation_errorsremains as[](empty array), which causes Drupal'sFormBuilder::handleInputElement()to skip all input processing.- The entity is saved with NULL values for fields that were on previous steps, causing database integrity constraint violations (e.g.,
Column 'title' cannot be null).
The user sees: "The content could not be saved. Contact the site administrator if the problem persists."
Steps to reproduce
- Install Drupal 11.3.x with
entity_form_steps1.1.7 andfield_group. - Create a content type with a text field (e.g.,
field_notes). - Configure the form display with two steps:
- Step 1:
titlefield, with a "Continue" button. - Step 2:
field_notesfield, with a "Save" button.
- Step 1:
- Go to
node/add/{content_type}. - Fill in the title on step 1 and click "Continue".
- Fill in the notes on step 2 and click "Save".
- Error: "The content could not be saved". The title is NULL because the form values from step 1 were not processed.
Root cause: entity_form_steps_module_implements_alter() moves the module's form_alter to the end of the implementations list. In Drupal 11's new hook system, this ordering mechanism is no longer reliable. When entity_form_steps_form_alter runs before field_group_form_alter, $form['#fieldgroups'] does not exist yet.
Proposed resolution
Add a fallback in EntityFormSteps::alterForm() that populates $form['#fieldgroups'] by calling field_group_attach_groups() when field groups have not been attached yet. This is a defensive check that works regardless of hook execution order:
if (!isset($form['#fieldgroups']) && function_exists('field_group_attach_groups')) {
$storage = $form_state->getStorage();
if (!empty($storage['form_display'])) {
field_group_attach_groups($form, [
'entity_type' => $entity->getEntityTypeId(),
'bundle' => $entity->bundle(),
'entity' => $entity,
'context' => 'form',
'display_context' => 'form',
'mode' => $storage['form_display']->getMode(),
]);
}
}
The patch also includes a test module and 4 functional tests covering: field hiding between steps, saving values across steps, editing, and back navigation.
Remaining tasks
- Review the proposed fix.
- Consider migrating from
hook_module_implements_alterto Drupal 11's#[Hook]attribute withorderparameter as a long-term solution.
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| fieldgroup-hook-ordering-tests-only.patch | 10.75 KB | facine | |
| fieldgroup-hook-ordering-fix-with-tests.patch | 13.32 KB | facine |
Comments