MediaWidgetAlter::formAlter() (invoked via hook_form_alter()) appends a submit handler to the submit button of every form whose form object is an EntityFormInterface:
#[Hook('form_alter')]
public function formAlter(array &$form, FormStateInterface $form_state, string $form_id): void {
$form_object = $form_state->getFormObject();
if (!$form_object instanceof EntityFormInterface) {
return;
}
$form['actions']['submit']['#submit'][] = [static::class, 'widgetFormSubmitCallback'];
}
This has two problems:
1. Too broad. It attaches to entity forms that have no synthesizable media widget at all. The handler no-ops in that case (it returns early unless polly_media_entity_to_speech is set),
so it's functionally harmless on most forms — but it still mutates the form.
2. It breaks forms that don't set their own button #submit and instead rely on the form-level handler. Once a submit button defines any #submit handlers, Drupal's
FormSubmitter::executeSubmitHandlers() uses only the button's handlers and ignores the form-level $form['#submit'] (which normally contains the form object's ::submitForm). So by adding
a handler to the button, polly_media suppresses the form's own submit handler.
My own victim was core's taxonomy term overview form (Drupal\taxonomy\Form\OverviewTerms). In Drupal 11 this form became an EntityForm (it was a FormBase in Drupal 10). It builds
its own actions and does not put a #submit on the Save button — it depends entirely on the form-level ::submitForm. After polly_media appends widgetFormSubmitCallback to that button,
OverviewTerms::submitForm() never runs. Result: reordering taxonomy terms silently does nothing — the form submits, redirects normally, no error, but term weights are never saved.
This is a Drupal 11 regression for sites running polly_media, triggered purely by OverviewTerms changing from FormBase to EntityForm.
Steps to reproduce
1. Install polly + polly_media and enable the synthesize option on at least one media reference widget.
2. Go to a vocabulary's term overview (/admin/structure/taxonomy/manage/{vid}/overview).
3. Drag to reorder terms, click Save.
Expected: weights are saved, terms keep the new order.
Actual: "The configuration options have been saved." does not appear, order reverts, taxonomy_term_field_data.weight stays unchanged. OverviewTerms::submitForm() is never called because
only the polly callback is registered as the button's submit handler.
Any custom/contrib EntityForm that builds its own actions without a button-level #submit is affected the same way.
Proposed resolution
Two complementary changes in MediaWidgetAlter:
1. Scope the attachment to forms that actually render a synthesizable media widget. fieldWidgetCompleteFormAlter() already determines this (third-party setting allow_synthesis, entity
form, fieldable entity, permission). Set a flag there:
$form_state->set('polly_media_synthesize_widget', TRUE);
1. and have formAlter() bail unless the flag is set. Because fieldWidgetCompleteFormAlter() runs while fields are built (inside the form object's buildForm()) and hook_form_alter() runs
after buildForm() returns, the flag is reliably available.
2. Attach where Drupal will actually run it, without overriding existing handlers:
if (!$form_state->get('polly_media_synthesize_widget')) {
return;
}
$callback = [static::class, 'widgetFormSubmitCallback'];
if (isset($form['actions']['submit']) && isset($form['actions']['submit']['#submit'])) {
// Button has its own handlers; Drupal uses only those.
$form['actions']['submit']['#submit'][] = $callback;
}
else {
// No button-level handlers; the form-level handlers are used.
$form['#submit'][] = $callback;
}
This keeps current behaviour for normal content entity edit forms (their Save button already carries ['::submitForm', '::save'], so the callback is appended there and still runs after
::save), stops polly_media from touching unrelated forms, and never suppresses a form's own submit handler.
The fix lives entirely in MediaWidgetAlter::formAlter() and ::fieldWidgetCompleteFormAlter(), which are the same methods invoked on both Drupal 10.3 (via the procedural #[LegacyHook]
bridge in polly_media.module) and Drupal 11 (via the #[Hook] attribute), so a single change covers both supported core versions.
Issue fork polly-3600850
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
hanoiiComment #5
andyf commentedMany thanks @hanoii! Took the opportunity to add the first tests for the polly_media module.
Comment #7
hanoiiAwesome, if you can release a new beta, that'd be great.
Comment #8
andyf commentedDone, should be published imminently.