diff --git a/customfilter.module b/customfilter.module
index b60b70e..75ce613 100644
--- a/customfilter.module
+++ b/customfilter.module
@@ -5,39 +5,16 @@
  * Allows the users with the right permission to define custom filters.
  */
 
-use Drupal\customfilter\Entity\CustomFilter;
-use Drupal\Core\Url;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\customfilter\Hook\CustomfilterHooks;
 use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Implements hook_help().
  */
+#[LegacyHook]
 function customfilter_help($route_name, RouteMatchInterface $route_match) {
-  switch ($route_name) {
-    case 'help.page.customfilter':
-      $output = '';
-      $output .= '<h3>' . t('About') . '</h3>';
-      $output .= '<p>' . t('The <em>customfilter</em> module allows users with the right permission to create custom filters. Those will be available as text format filters to be used in your content.</p>');
-      $output .= '<h3>' . t('Uses') . '</h3>';
-      $output .= '<dl>';
-      $output .= '<dt>' . t('Configure your custom filters and rules:') . '</dt>';
-      $output .= '<dd>' . t('<em>Filters</em> are made of <em>rules</em> and eventually <em>subrules</em>. Configure them on the <a href=":filters">filter administration page</a>.', [':filters' => Url::fromRoute('entity.customfilter.list')->toString()]) . '</dd>';
-      $output .= '<dt>' . t('Use them in your text formats:') . '</dt>';
-      $output .= '<dd>' . t('<em>Custom filters</em> can be used in the text formats to enhance your contents. Enable the filters you made by <a href=":formats">administrating text formats</a>.', [':formats' => Url::fromRoute('filter.admin_overview')->toString()]) . '</dd>';
-      $output .= '</dl>';
-      return $output;
-
-    case 'entity.customfilter.list':
-      $output = '<p>' . t('Custom filter provides the ability for creating user defined filters using regular expressions. Instead of creating filter modules, users can create their own filter for specific site purpose.') . '</p>';
-      $output .= '<p>' . t('A filter is a collection of replacement rules. Each filter will appear in the input format settings page. Click on the filter name to see its replacement rules.') . '</p>';
-      return $output;
-
-    case 'customfilter.rules.add':
-    case 'customfilter.rules.edit':
-    case 'customfilter.rules.add.subrule':
-      $output = '<p>' . t('For more information about the regular expressions syntax, see <a href="http://www.php.net/manual/en/regexp.reference.php">Regular expression details</a>.') . '</p>';
-      return $output;
-  }
+  return \Drupal::service(CustomfilterHooks::class)->help($route_name, $route_match);
 }
 
 /**
@@ -45,20 +22,7 @@ function customfilter_help($route_name, RouteMatchInterface $route_match) {
  *
  * This function add the filters from customfilter.
  */
+#[LegacyHook]
 function customfilter_filter_info_alter(&$info) {
-  $filters = CustomFilter::getFilters();
-  foreach ($filters as $filter) {
-    $id = 'customfilter_' . $filter->id();
-    $info[$id]['description'] = $filter->getDescription();
-    $info[$id]['weight'] = 0;
-    $info[$id]['status'] = FALSE;
-    $info[$id]['cache'] = $filter->getCache();
-    $info[$id]['settings'] = ['id' => $filter->id()];
-    $info[$id]['id'] = $id;
-    $info[$id]['module'] = 'customfilter';
-    $info[$id]['title'] = $filter->label();
-    $info[$id]['type'] = 2;
-    $info[$id]['class'] = 'Drupal\customfilter\Plugin\Filter\CustomFilterBaseFilter';
-    $info[$id]['provider'] = 'customfilter';
-  }
+  \Drupal::service(CustomfilterHooks::class)->filterInfoAlter($info);
 }
diff --git a/customfilter.services.yml b/customfilter.services.yml
index ce1f3cb..177f58c 100644
--- a/customfilter.services.yml
+++ b/customfilter.services.yml
@@ -2,3 +2,7 @@ services:
   customfilter.validator:
     class: Drupal\customfilter\CustomFilterValidator
     arguments: ['@plugin.manager.filter', '@entity_type.manager', '@string_translation']
+
+  Drupal\customfilter\Hook\CustomfilterHooks:
+    class: Drupal\customfilter\Hook\CustomfilterHooks
+    autowire: true
diff --git a/src/Form/CustomFilterRulesDeleteForm.php b/src/Form/CustomFilterRulesDeleteForm.php
index e7631e8..c627662 100755
--- a/src/Form/CustomFilterRulesDeleteForm.php
+++ b/src/Form/CustomFilterRulesDeleteForm.php
@@ -36,7 +36,7 @@ class CustomFilterRulesDeleteForm extends ConfirmFormBase {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, CustomFilter $customfilter = NULL, $rule_id = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ?CustomFilter $customfilter = NULL, $rule_id = NULL) {
     $this->customfilter = $customfilter;
     $this->rule = $this->customfilter->getRule($rule_id);
     return parent::buildForm($form, $form_state);
diff --git a/src/Form/RulesAddEditForm.php b/src/Form/RulesAddEditForm.php
index de9a5b8..bb5363c 100644
--- a/src/Form/RulesAddEditForm.php
+++ b/src/Form/RulesAddEditForm.php
@@ -31,7 +31,7 @@ class RulesAddEditForm implements FormInterface {
   /**
    * Create the form that list the rules.
    */
-  public function buildForm(array $form, FormStateInterface $form_state, CustomFilter $customfilter = NULL, $rule_id = '', $operation = '') {
+  public function buildForm(array $form, FormStateInterface $form_state, ?CustomFilter $customfilter = NULL, $rule_id = '', $operation = '') {
     $this->entity = $customfilter;
     $form = [];
     $item = [];
diff --git a/src/Form/RulesListForm.php b/src/Form/RulesListForm.php
index b2954b1..baaff05 100644
--- a/src/Form/RulesListForm.php
+++ b/src/Form/RulesListForm.php
@@ -32,7 +32,7 @@ class RulesListForm implements FormInterface {
   /**
    * Create the form that list the rules.
    */
-  public function buildForm(array $form, FormStateInterface $form_state, CustomFilter $customfilter = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, ?CustomFilter $customfilter = NULL) {
     $this->entity = $customfilter;
 
     $form['rules'] = [
diff --git a/src/Hook/CustomfilterHooks.php b/src/Hook/CustomfilterHooks.php
new file mode 100644
index 0000000..30544a8
--- /dev/null
+++ b/src/Hook/CustomfilterHooks.php
@@ -0,0 +1,79 @@
+<?php
+
+namespace Drupal\customfilter\Hook;
+
+use Drupal\customfilter\Entity\CustomFilter;
+use Drupal\Core\Url;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for customfilter.
+ */
+class CustomfilterHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_help().
+   */
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match) {
+    switch ($route_name) {
+      case 'help.page.customfilter':
+        $output = '';
+        $output .= '<h3>' . $this->t('About') . '</h3>';
+        $output .= '<p>' . $this->t('The <em>customfilter</em> module allows users with the right permission to create custom filters. Those will be available as text format filters to be used in your content.</p>');
+        $output .= '<h3>' . $this->t('Uses') . '</h3>';
+        $output .= '<dl>';
+        $output .= '<dt>' . $this->t('Configure your custom filters and rules:') . '</dt>';
+        $output .= '<dd>' . $this->t('<em>Filters</em> are made of <em>rules</em> and eventually <em>subrules</em>. Configure them on the <a href=":filters">filter administration page</a>.', [
+          ':filters' => Url::fromRoute('entity.customfilter.list')->toString(),
+        ]) . '</dd>';
+        $output .= '<dt>' . $this->t('Use them in your text formats:') . '</dt>';
+        $output .= '<dd>' . $this->t('<em>Custom filters</em> can be used in the text formats to enhance your contents. Enable the filters you made by <a href=":formats">administrating text formats</a>.', [
+          ':formats' => Url::fromRoute('filter.admin_overview')->toString(),
+        ]) . '</dd>';
+        $output .= '</dl>';
+        return $output;
+
+      case 'entity.customfilter.list':
+        $output = '<p>' . $this->t('Custom filter provides the ability for creating user defined filters using regular expressions. Instead of creating filter modules, users can create their own filter for specific site purpose.') . '</p>';
+        $output .= '<p>' . $this->t('A filter is a collection of replacement rules. Each filter will appear in the input format settings page. Click on the filter name to see its replacement rules.') . '</p>';
+        return $output;
+
+      case 'customfilter.rules.add':
+      case 'customfilter.rules.edit':
+      case 'customfilter.rules.add.subrule':
+        $output = '<p>' . $this->t('For more information about the regular expressions syntax, see <a href="http://www.php.net/manual/en/regexp.reference.php">Regular expression details</a>.') . '</p>';
+        return $output;
+    }
+  }
+
+  /**
+   * Implements hook_filter_info_alter().
+   *
+   * This function add the filters from customfilter.
+   */
+  #[Hook('filter_info_alter')]
+  public static function filterInfoAlter(&$info) {
+    $filters = CustomFilter::getFilters();
+    foreach ($filters as $filter) {
+      $id = 'customfilter_' . $filter->id();
+      $info[$id]['description'] = $filter->getDescription();
+      $info[$id]['weight'] = 0;
+      $info[$id]['status'] = FALSE;
+      $info[$id]['cache'] = $filter->getCache();
+      $info[$id]['settings'] = [
+        'id' => $filter->id(),
+      ];
+      $info[$id]['id'] = $id;
+      $info[$id]['module'] = 'customfilter';
+      $info[$id]['title'] = $filter->label();
+      $info[$id]['type'] = 2;
+      $info[$id]['class'] = 'Drupal\customfilter\Plugin\Filter\CustomFilterBaseFilter';
+      $info[$id]['provider'] = 'customfilter';
+    }
+  }
+
+}
