Problem/Motivation
Drupal 12 removes the theme hook includes mechanism, deprecated in 11.3: "Providing includes for theme hook ... is deprecated in drupal:11.3.0 and is removed from drupal:12.0.0. Use initial preprocess for template_preprocess instead."
WebformThemeHooks::theme() attaches $template['file'] = 'includes/webform.theme.template.inc' to every one of webform's theme hooks. On Drupal 12 that file is therefore never loaded, so none of the 31 template_preprocess_*() functions it defines is ever discovered or run.
The visible result is that every webform renders as an empty form: webform.html.twig emits its <form> tag with no children at all, no elements, no actions, not even the hidden form_build_id and form_token, and without the action, method, id or accept-charset attributes. Nothing is logged, because nothing calls a function that no longer exists.
Behind that sits a second removal in the same area. Those preprocess functions call procedural functions Drupal 12 also removes: template_preprocess_webform() calls template_preprocess_form(), whose body moved to Drupal\Core\Form\FormPreprocess::preprocessForm(), and webform_share calls template_preprocess_html() and template_preprocess_page(), whose bodies moved to Drupal\Core\Theme\ThemePreprocess. Both classes are @internal but are registered as services under their own class names. So fixing only the discovery would move the failure rather than remove it; both halves are needed.
Steps to reproduce
On core 12.x-dev, with the other Drupal 12 compatibility fixes applied so that webform installs, visit any webform. The page returns 200 and the form is empty.
The missing accept-charset is the quickest way to recognize it, since core sets that attribute unconditionally: a form without it never went through the form preprocess at all.
Proposed resolution
Add Drupal\webform\Theme\WebformPreprocess with one method per preprocess function, and have theme() declare initial preprocess for each hook that has one, keeping the file key alongside it. initial preprocess exists from Drupal 11.2, and on 10.3 the unknown key is simply ignored, so one declaration covers the whole supported range with no version comparison. The removed procedural functions are called through their service classes where they no longer exist.
The change record suggests going further and moving each preprocess body into the class, dropping file entirely. This does not do that, for two reasons: webform still supports Drupal 10.3, where initial preprocess does not exist and the procedural functions are still the only mechanism; and four callers inside webform call those functions directly. That cleanup belongs in a follow-up once webform requires 11.2 or later.
One deliberate difference: core 12's preprocessForm() also sets novalidate unless enable_html5_validation is on, which the function it replaces did not. Replicating it would change behavior on the currently supported releases, so it is left out.
Remaining tasks
Three unrelated Drupal 12 findings turned up alongside this and are not addressed here. WebformSubmissionViewController::view() passes the current user to Renderer::addCacheableDependency(), and AccountProxy does not implement CacheableDependencyInterface, which is deprecated in 11.3 and throws in 13.0. The default:webform selection plugin is still declared with an @EntityReferenceSelection annotation. And webform-element-help.html.twig uses Twig's spaceless filter, deprecated since twig/twig 3.12. Happy to file those separately if you prefer.
User interface changes
None.
API changes
None. A new class, and a theme hook key added alongside the existing one.
AI-Generated: Yes (Claude Code was used to help draft this issue summary and to write the change on the merge request. I reviewed it. It was verified against core 12.x-dev on a contrib project's next-major CI lane, not against webform's own test suite, which has no Drupal 12 lane: seven test classes that previously could not run on Drupal 12 now run, with 989 passing, 0 failures, 0 errors and 0 skips.)
Issue fork webform-3618889
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 #4
cilefen commentedDoesn't #3603992: Automated Drupal 12 compatibility fixes for webform 6.x-dev do this automatically? Can we use the automatically generated code?
composer.json doesn't indicate Drupal 12 compatibility, so this isn't a defect in Webform. I am marking this as a task.