Drupal 11.3 introduces an important shift for theme and module developers:
the long-standing automatic discovery of template_preprocess_HOOK() functions is now deprecated, along with the file and includes keys in hook_theme().
These patterns have been around since Drupal 7 and worked well in the procedural era. But with modern autoloading and class-based preprocessors, they’re no longer necessary — and now officially discouraged.
In this article, we’ll cover:
- What exactly is deprecated
- Why this change was made
- How to migrate your code to the new standard
- A complete before/after code example
What’s Being Deprecated?
| Old Mechanism | Status in 11.3 | Modern Replacement |
|---|---|---|
template_preprocess_HOOK() | Deprecated | Explicit class-based preprocess callbacks |
file in hook_theme() | Deprecated | Remove — autoloading handles includes |
includes in hook_theme() | Deprecated | Remove |
Why Remove These Features?
Historically, Drupal scanned all loaded PHP files and automatically detected functions named template_preprocess_{hook}. If those functions lived in separate include files, developers had to manually specify them via file or includes in hook_theme().
This “magic” discovery is now considered unpredictable and outdated. Drupal core is moving toward explicit, PSR-4 autoloaded, class-based callbacks, making code easier to trace and refactor.
How to Upgrade Your Code
❌ Before (deprecated approach)
function mymodule_theme() {
return [
'my_template' => [
'variables' => ['items' => NULL],
'file' => 'mymodule.preprocess.inc',
],
];
}
function template_preprocess_my_template(&$variables) {
$variables['items'][] = 'Legacy preprocess';
}
✅ After (modern, future-proof approach)
function mymodule_theme() {
return [
'my_template' => [
'variables' => ['items' => NULL],
'preprocess' => [
[\Drupal\mymodule\Theme\MyTemplatePreprocess::class, 'preprocess'],
],
],
];
}
// src/Theme/MyTemplatePreprocess.php
namespace Drupal\mymodule\Theme;
class MyTemplatePreprocess {
public static function preprocess(array &$variables) {
$variables['items'][] = 'OOP preprocess FTW';
}
}
Do You Need to Migrate Right Now?
| Scenario | Recommendation |
|---|---|
| Maintaining a public contrib module | ✅ Yes — update for Drupal 11.x compatibility |
| Running an internal Drupal 10 site | ⚠ Not urgent — but plan ahead before upgrading |
| Starting new theme or module work | 🚀 Use the new pattern from day one |
Final Thoughts
This move is part of Drupal’s broader transition away from procedural “magic” toward explicit, discoverable, class-based architecture. Preprocess functions still exist — but they must now be registered intentionally via callbacks instead of being auto-detected.
Got legacy code still relying on template_preprocess_* or file/includes? Now’s the perfect time to refactor.
Comments