diff --git a/preprocess.info.yml b/preprocess.info.yml
index bbca3f5..78f4d73 100755
--- a/preprocess.info.yml
+++ b/preprocess.info.yml
@@ -1,7 +1,7 @@
 name: Preprocess
 type: module
 description: Provides a plugin type for preprocessing.
-core_version_requirement: ^9 || ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
 php: 7.1
 package: Theming
 
diff --git a/preprocess.module b/preprocess.module
index 3439790..e7e8b82 100755
--- a/preprocess.module
+++ b/preprocess.module
@@ -1,5 +1,12 @@
 <?php
 
+/**
+ * @file
+ */
+
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\preprocess\Hook\PreprocessHooks;
+
 /**
  * @file
  * Handles preprocessing of all theme hooks implemented as templates.
@@ -8,33 +15,23 @@
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function preprocess_help(string $route_name): string {
-  return $route_name === 'help.page.preprocess' ?
-    sprintf('<pre>%s</pre>', file_get_contents(__DIR__ . '/README.md')) :
-    '';
+  return \Drupal::service(PreprocessHooks::class)->help($route_name);
 }
 
 /**
  * Implements hook_preprocess().
  */
+#[LegacyHook]
 function preprocess_preprocess(&$variables, $hook): void {
-  /** @var Drupal\preprocess\PreprocessManagerInterface $manager */
-  $manager = Drupal::service('preprocess.manager');
-  $variables = $manager->preprocess($hook, $variables);
+  \Drupal::service(PreprocessHooks::class)->preprocess($variables, $hook);
 }
 
 /**
  * Implements hook_theme_registry_alter().
  */
+#[LegacyHook]
 function preprocess_theme_registry_alter(array &$theme_registry): void {
-  $implementation = 'preprocess_preprocess';
-  foreach ($theme_registry as $theme => $item) {
-    $preprocessor_key = array_search($implementation, $item['preprocess functions'] ?? [], TRUE);
-    if ($preprocessor_key === FALSE) {
-      continue;
-    }
-
-    unset($theme_registry[$theme]['preprocess functions'][$preprocessor_key]);
-    $theme_registry[$theme]['preprocess functions'][] = $implementation;
-  }
+  \Drupal::service(PreprocessHooks::class)->themeRegistryAlter($theme_registry);
 }
diff --git a/preprocess.services.yml b/preprocess.services.yml
index 682db11..f58680f 100755
--- a/preprocess.services.yml
+++ b/preprocess.services.yml
@@ -5,3 +5,7 @@ services:
   preprocess.manager:
     class: Drupal\preprocess\PreprocessManager
     arguments: ['@preprocess.plugin.manager', '@theme.registry', '@module_handler', '@theme.manager']
+
+  Drupal\preprocess\Hook\PreprocessHooks:
+    class: Drupal\preprocess\Hook\PreprocessHooks
+    autowire: true
diff --git a/src/Hook/PreprocessHooks.php b/src/Hook/PreprocessHooks.php
new file mode 100644
index 0000000..1decac1
--- /dev/null
+++ b/src/Hook/PreprocessHooks.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Drupal\preprocess\Hook;
+
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Hook implementations for preprocess.
+ */
+class PreprocessHooks {
+  /**
+   * @file
+   * Handles preprocessing of all theme hooks implemented as templates.
+   */
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public static function help(string $route_name): string {
+    return $route_name === 'help.page.preprocess' ? sprintf('<pre>%s</pre>', file_get_contents(__DIR__ . '/README.md')) : '';
+  }
+
+  /**
+   * Implements hook_preprocess().
+   */
+  #[Hook('preprocess')]
+  public static function preprocess(&$variables, $hook): void {
+    /** @var Drupal\preprocess\PreprocessManagerInterface $manager */
+    $manager = \Drupal::service('preprocess.manager');
+    $variables = $manager->preprocess($hook, $variables);
+  }
+
+  /**
+   * Implements hook_theme_registry_alter().
+   */
+  #[Hook('theme_registry_alter')]
+  public static function themeRegistryAlter(array &$theme_registry): void {
+    $implementation = 'preprocess_preprocess';
+    foreach ($theme_registry as $theme => $item) {
+      $preprocessor_key = array_search($implementation, $item['preprocess functions'] ?? [], TRUE);
+      if ($preprocessor_key === FALSE) {
+        continue;
+      }
+      unset($theme_registry[$theme]['preprocess functions'][$preprocessor_key]);
+      $theme_registry[$theme]['preprocess functions'][] = $implementation;
+    }
+  }
+
+}
diff --git a/tests/modules/preprocess_test/preprocess_test.info.yml b/tests/modules/preprocess_test/preprocess_test.info.yml
index 4097c64..cf6a685 100755
--- a/tests/modules/preprocess_test/preprocess_test.info.yml
+++ b/tests/modules/preprocess_test/preprocess_test.info.yml
@@ -2,4 +2,4 @@ name: Preprocess - TEST
 type: module
 description: 'Support module for testing preprocessing.'
 package: Testing
-core_version_requirement: ^9 || ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
diff --git a/tests/themes/test_preprocess_theme/test_preprocess_theme.info.yml b/tests/themes/test_preprocess_theme/test_preprocess_theme.info.yml
index 77cf9cf..6adaef6 100755
--- a/tests/themes/test_preprocess_theme/test_preprocess_theme.info.yml
+++ b/tests/themes/test_preprocess_theme/test_preprocess_theme.info.yml
@@ -2,7 +2,7 @@ name: Test preprocess theme
 type: theme
 description: Theme for testing theme-provided preprocessors
 base theme: stable
-core_version_requirement: ^9 || ^10 || ^11
+core_version_requirement: ^10.1 || ^11 || ^12
 
 dependencies:
   - stable:stable
