From 0bbdda654647b7123cd25d3f8ddfab0c4dbebe9b Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 10:17:56 -0500
Subject: [PATCH 01/53] Splitting entity related hooks into separate class,
 adding build_node_index and delete_node_index as private methods.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 190 ++++++++++++++++++
 .../taxonomy/src/Hook/TaxonomyHooks.php       |  83 --------
 2 files changed, 190 insertions(+), 83 deletions(-)
 create mode 100644 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
new file mode 100644
index 000000000000..ab2a5b6ef806
--- /dev/null
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -0,0 +1,190 @@
+<?php
+
+namespace Drupal\taxonomy\Hook;
+
+use Drupal\taxonomy\Entity\Term;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\Core\Url;
+
+/**
+ * Hook implementations for taxonomy.
+ */
+class TaxonomyEntityHooks {
+
+  /**
+   * A config factory for retrieving required config settings.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * A config factory for retrieving required config settings.
+   *
+   * @property \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs TaxonomyEntityHooks.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
+   *   The configuration factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   *   The entity type manager.
+   */
+  public function __construct(ConfigFactoryInterface $configFactory, EntityTypeManagerInterface $entityTypeManager) {
+    $this->configFactory = $configFactory;
+    $this->entityTypeManager = $entityTypeManager;
+  }
+
+  /**
+   * Builds and inserts taxonomy index entries for a given node.
+   *
+   * The index lists all terms that are related to a given node entity, and is
+   * therefore maintained at the entity level.
+   *
+   * @param \Drupal\node\Entity\Node $node
+   *   The node entity.
+   */
+  protected function build_node_index($node) {
+    // We maintain a denormalized table of term/node relationships, containing
+    // only data for current, published nodes.
+    if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+      return;
+    }
+
+    $status = $node->isPublished();
+    $sticky = (int) $node->isSticky();
+    // We only maintain the taxonomy index for published nodes.
+    if ($status && $node->isDefaultRevision()) {
+      // Collect a unique list of all the term IDs from all node fields.
+      $tid_all = [];
+      $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+      foreach ($node->getFieldDefinitions() as $field) {
+        $field_name = $field->getName();
+        $class = $field->getItemDefinition()->getClass();
+        $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
+        if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
+          foreach ($node->getTranslationLanguages() as $language) {
+            foreach ($node->getTranslation($language->getId())->$field_name as $item) {
+              if (!$item->isEmpty()) {
+                $tid_all[$item->target_id] = $item->target_id;
+              }
+            }
+          }
+        }
+      }
+      // Insert index entries for all the node's terms.
+      if (!empty($tid_all)) {
+        $connection = \Drupal::database();
+        foreach ($tid_all as $tid) {
+          $connection->merge('taxonomy_index')
+            ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
+            ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
+            ->execute();
+        }
+      }
+    }
+  }
+
+  /**
+   * Deletes taxonomy index entries for a given node.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $node
+   *   The node entity.
+   */
+  protected function delete_node_index(EntityInterface $node) {
+    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+      \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+    }
+  }
+
+  /**
+   * Implements hook_entity_operation().
+   */
+  #[Hook('entity_operation')]
+  public function entityOperation(EntityInterface $term): array {
+    $operations = [];
+    if ($term instanceof Term && $term->access('create')) {
+      $operations['add-child'] = [
+        'title' => t('Add child'),
+        'weight' => 10,
+        'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
+          'taxonomy_vocabulary' => $term->bundle(),
+        ], [
+          'query' => [
+            'parent' => $term->id(),
+          ],
+        ]),
+      ];
+    }
+    return $operations;
+  }
+
+  /**
+   * @defgroup taxonomy_index Taxonomy indexing
+   * @{
+   * Functions to maintain taxonomy indexing.
+   *
+   * Taxonomy uses default field storage to store canonical relationships
+   * between terms and fieldable entities. However its most common use case
+   * requires listing all content associated with a term or group of terms
+   * sorted by creation date. To avoid slow queries due to joining across
+   * multiple node and field tables with various conditions and order by
+   * criteria, we maintain a denormalized table with all relationships between
+   * terms, published nodes and common sort criteria such as status, sticky and
+   * created. When using other field storage engines or alternative methods of
+   * denormalizing this data you should set the
+   * taxonomy.settings:maintain_index_table to '0' to avoid unnecessary writes
+   * in SQL.
+   */
+
+  /**
+   * Implements hook_ENTITY_TYPE_insert() for node entities.
+   */
+  #[Hook('node_insert')]
+  public function nodeInsert(EntityInterface $node): void {
+    // Add taxonomy index entries for the node.
+    $this->build_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_update() for node entities.
+   */
+  #[Hook('node_update')]
+  public function nodeUpdate(EntityInterface $node): void {
+    // If we're not dealing with the default revision of the node, do not make any
+    // change to the taxonomy index.
+    if (!$node->isDefaultRevision()) {
+      return;
+    }
+    $this->delete_node_index($node);
+    $this->build_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_predelete() for node entities.
+   */
+  #[Hook('node_predelete')]
+  public function nodePredelete(EntityInterface $node): void {
+    // Clean up the {taxonomy_index} table when nodes are deleted.
+    $this->delete_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
+   */
+  #[Hook('taxonomy_term_delete')]
+  public function taxonomyTermDelete(Term $term): void {
+    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+      // Clean up the {taxonomy_index} table when terms are deleted.
+      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
+    }
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index fcbc82172927..e9e037c426e6 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -93,87 +93,4 @@ public function localTasksAlter(&$local_tasks): void {
     }
   }
 
-  /**
-   * Implements hook_entity_operation().
-   */
-  #[Hook('entity_operation')]
-  public function entityOperation(EntityInterface $term): array {
-    $operations = [];
-    if ($term instanceof Term && $term->access('create')) {
-      $operations['add-child'] = [
-        'title' => t('Add child'),
-        'weight' => 10,
-        'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
-          'taxonomy_vocabulary' => $term->bundle(),
-        ], [
-          'query' => [
-            'parent' => $term->id(),
-          ],
-        ]),
-      ];
-    }
-    return $operations;
-  }
-
-  /**
-   * @defgroup taxonomy_index Taxonomy indexing
-   * @{
-   * Functions to maintain taxonomy indexing.
-   *
-   * Taxonomy uses default field storage to store canonical relationships
-   * between terms and fieldable entities. However its most common use case
-   * requires listing all content associated with a term or group of terms
-   * sorted by creation date. To avoid slow queries due to joining across
-   * multiple node and field tables with various conditions and order by
-   * criteria, we maintain a denormalized table with all relationships between
-   * terms, published nodes and common sort criteria such as status, sticky and
-   * created. When using other field storage engines or alternative methods of
-   * denormalizing this data you should set the
-   * taxonomy.settings:maintain_index_table to '0' to avoid unnecessary writes
-   * in SQL.
-   */
-
-  /**
-   * Implements hook_ENTITY_TYPE_insert() for node entities.
-   */
-  #[Hook('node_insert')]
-  public function nodeInsert(EntityInterface $node) {
-    // Add taxonomy index entries for the node.
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_update() for node entities.
-   */
-  #[Hook('node_update')]
-  public function nodeUpdate(EntityInterface $node) {
-    // If we're not dealing with the default revision of the node, do not make any
-    // change to the taxonomy index.
-    if (!$node->isDefaultRevision()) {
-      return;
-    }
-    taxonomy_delete_node_index($node);
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_predelete() for node entities.
-   */
-  #[Hook('node_predelete')]
-  public function nodePredelete(EntityInterface $node) {
-    // Clean up the {taxonomy_index} table when nodes are deleted.
-    taxonomy_delete_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
-   */
-  #[Hook('taxonomy_term_delete')]
-  public function taxonomyTermDelete(Term $term) {
-    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
-      // Clean up the {taxonomy_index} table when terms are deleted.
-      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
-    }
-  }
-
 }
-- 
GitLab


From 1989963a674932b2d074e0ceace9ae1118365b11 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 10:26:07 -0500
Subject: [PATCH 02/53] Fixing PHPSTAN errors

---
 core/modules/taxonomy/src/Hook/TaxonomyHooks.php | 2 --
 1 file changed, 2 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index e9e037c426e6..38637cd81b42 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -2,8 +2,6 @@
 
 namespace Drupal\taxonomy\Hook;
 
-use Drupal\taxonomy\Entity\Term;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Hook\Attribute\Hook;
-- 
GitLab


From 096ae5514ef98cc7cfdf6d66b7697cc6d0a8574d Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 12:01:48 -0500
Subject: [PATCH 03/53] Updating baseline.

---
 core/.phpstan-baseline.php | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index d6347f6b7225..bb46e2ba72dd 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -40155,30 +40155,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodeInsert\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodePredelete\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodeUpdate\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:taxonomyTermDelete\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\taxonomy\\\\Plugin\\\\Validation\\\\Constraint\\\\TaxonomyTermHierarchyConstraintValidator\\:\\:create\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
-- 
GitLab


From 56025e14aff8e45deaba1832527e941b9de5ea48 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 12:10:55 -0500
Subject: [PATCH 04/53] Adding return types for delete_node_index and
 build_node_index.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index ab2a5b6ef806..dd02924e3366 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -51,7 +51,7 @@ public function __construct(ConfigFactoryInterface $configFactory, EntityTypeMan
    * @param \Drupal\node\Entity\Node $node
    *   The node entity.
    */
-  protected function build_node_index($node) {
+  protected function build_node_index($node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
     if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
@@ -98,7 +98,7 @@ protected function build_node_index($node) {
    * @param \Drupal\Core\Entity\EntityInterface $node
    *   The node entity.
    */
-  protected function delete_node_index(EntityInterface $node) {
+  protected function delete_node_index(EntityInterface $node): void {
     if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
       \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
-- 
GitLab


From 599aae7d8d1ab85b554a6c3eed8ea71f815060f0 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 10:17:56 -0500
Subject: [PATCH 05/53] Splitting entity related hooks into separate class,
 adding build_node_index and delete_node_index as private methods.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 190 ++++++++++++++++++
 .../taxonomy/src/Hook/TaxonomyHooks.php       |  83 --------
 2 files changed, 190 insertions(+), 83 deletions(-)
 create mode 100644 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
new file mode 100644
index 000000000000..ab2a5b6ef806
--- /dev/null
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -0,0 +1,190 @@
+<?php
+
+namespace Drupal\taxonomy\Hook;
+
+use Drupal\taxonomy\Entity\Term;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\Core\Url;
+
+/**
+ * Hook implementations for taxonomy.
+ */
+class TaxonomyEntityHooks {
+
+  /**
+   * A config factory for retrieving required config settings.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * A config factory for retrieving required config settings.
+   *
+   * @property \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs TaxonomyEntityHooks.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
+   *   The configuration factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   *   The entity type manager.
+   */
+  public function __construct(ConfigFactoryInterface $configFactory, EntityTypeManagerInterface $entityTypeManager) {
+    $this->configFactory = $configFactory;
+    $this->entityTypeManager = $entityTypeManager;
+  }
+
+  /**
+   * Builds and inserts taxonomy index entries for a given node.
+   *
+   * The index lists all terms that are related to a given node entity, and is
+   * therefore maintained at the entity level.
+   *
+   * @param \Drupal\node\Entity\Node $node
+   *   The node entity.
+   */
+  protected function build_node_index($node) {
+    // We maintain a denormalized table of term/node relationships, containing
+    // only data for current, published nodes.
+    if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+      return;
+    }
+
+    $status = $node->isPublished();
+    $sticky = (int) $node->isSticky();
+    // We only maintain the taxonomy index for published nodes.
+    if ($status && $node->isDefaultRevision()) {
+      // Collect a unique list of all the term IDs from all node fields.
+      $tid_all = [];
+      $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+      foreach ($node->getFieldDefinitions() as $field) {
+        $field_name = $field->getName();
+        $class = $field->getItemDefinition()->getClass();
+        $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
+        if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
+          foreach ($node->getTranslationLanguages() as $language) {
+            foreach ($node->getTranslation($language->getId())->$field_name as $item) {
+              if (!$item->isEmpty()) {
+                $tid_all[$item->target_id] = $item->target_id;
+              }
+            }
+          }
+        }
+      }
+      // Insert index entries for all the node's terms.
+      if (!empty($tid_all)) {
+        $connection = \Drupal::database();
+        foreach ($tid_all as $tid) {
+          $connection->merge('taxonomy_index')
+            ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
+            ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
+            ->execute();
+        }
+      }
+    }
+  }
+
+  /**
+   * Deletes taxonomy index entries for a given node.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $node
+   *   The node entity.
+   */
+  protected function delete_node_index(EntityInterface $node) {
+    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+      \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+    }
+  }
+
+  /**
+   * Implements hook_entity_operation().
+   */
+  #[Hook('entity_operation')]
+  public function entityOperation(EntityInterface $term): array {
+    $operations = [];
+    if ($term instanceof Term && $term->access('create')) {
+      $operations['add-child'] = [
+        'title' => t('Add child'),
+        'weight' => 10,
+        'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
+          'taxonomy_vocabulary' => $term->bundle(),
+        ], [
+          'query' => [
+            'parent' => $term->id(),
+          ],
+        ]),
+      ];
+    }
+    return $operations;
+  }
+
+  /**
+   * @defgroup taxonomy_index Taxonomy indexing
+   * @{
+   * Functions to maintain taxonomy indexing.
+   *
+   * Taxonomy uses default field storage to store canonical relationships
+   * between terms and fieldable entities. However its most common use case
+   * requires listing all content associated with a term or group of terms
+   * sorted by creation date. To avoid slow queries due to joining across
+   * multiple node and field tables with various conditions and order by
+   * criteria, we maintain a denormalized table with all relationships between
+   * terms, published nodes and common sort criteria such as status, sticky and
+   * created. When using other field storage engines or alternative methods of
+   * denormalizing this data you should set the
+   * taxonomy.settings:maintain_index_table to '0' to avoid unnecessary writes
+   * in SQL.
+   */
+
+  /**
+   * Implements hook_ENTITY_TYPE_insert() for node entities.
+   */
+  #[Hook('node_insert')]
+  public function nodeInsert(EntityInterface $node): void {
+    // Add taxonomy index entries for the node.
+    $this->build_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_update() for node entities.
+   */
+  #[Hook('node_update')]
+  public function nodeUpdate(EntityInterface $node): void {
+    // If we're not dealing with the default revision of the node, do not make any
+    // change to the taxonomy index.
+    if (!$node->isDefaultRevision()) {
+      return;
+    }
+    $this->delete_node_index($node);
+    $this->build_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_predelete() for node entities.
+   */
+  #[Hook('node_predelete')]
+  public function nodePredelete(EntityInterface $node): void {
+    // Clean up the {taxonomy_index} table when nodes are deleted.
+    $this->delete_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
+   */
+  #[Hook('taxonomy_term_delete')]
+  public function taxonomyTermDelete(Term $term): void {
+    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+      // Clean up the {taxonomy_index} table when terms are deleted.
+      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
+    }
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index fcbc82172927..e9e037c426e6 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -93,87 +93,4 @@ public function localTasksAlter(&$local_tasks): void {
     }
   }
 
-  /**
-   * Implements hook_entity_operation().
-   */
-  #[Hook('entity_operation')]
-  public function entityOperation(EntityInterface $term): array {
-    $operations = [];
-    if ($term instanceof Term && $term->access('create')) {
-      $operations['add-child'] = [
-        'title' => t('Add child'),
-        'weight' => 10,
-        'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
-          'taxonomy_vocabulary' => $term->bundle(),
-        ], [
-          'query' => [
-            'parent' => $term->id(),
-          ],
-        ]),
-      ];
-    }
-    return $operations;
-  }
-
-  /**
-   * @defgroup taxonomy_index Taxonomy indexing
-   * @{
-   * Functions to maintain taxonomy indexing.
-   *
-   * Taxonomy uses default field storage to store canonical relationships
-   * between terms and fieldable entities. However its most common use case
-   * requires listing all content associated with a term or group of terms
-   * sorted by creation date. To avoid slow queries due to joining across
-   * multiple node and field tables with various conditions and order by
-   * criteria, we maintain a denormalized table with all relationships between
-   * terms, published nodes and common sort criteria such as status, sticky and
-   * created. When using other field storage engines or alternative methods of
-   * denormalizing this data you should set the
-   * taxonomy.settings:maintain_index_table to '0' to avoid unnecessary writes
-   * in SQL.
-   */
-
-  /**
-   * Implements hook_ENTITY_TYPE_insert() for node entities.
-   */
-  #[Hook('node_insert')]
-  public function nodeInsert(EntityInterface $node) {
-    // Add taxonomy index entries for the node.
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_update() for node entities.
-   */
-  #[Hook('node_update')]
-  public function nodeUpdate(EntityInterface $node) {
-    // If we're not dealing with the default revision of the node, do not make any
-    // change to the taxonomy index.
-    if (!$node->isDefaultRevision()) {
-      return;
-    }
-    taxonomy_delete_node_index($node);
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_predelete() for node entities.
-   */
-  #[Hook('node_predelete')]
-  public function nodePredelete(EntityInterface $node) {
-    // Clean up the {taxonomy_index} table when nodes are deleted.
-    taxonomy_delete_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
-   */
-  #[Hook('taxonomy_term_delete')]
-  public function taxonomyTermDelete(Term $term) {
-    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
-      // Clean up the {taxonomy_index} table when terms are deleted.
-      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
-    }
-  }
-
 }
-- 
GitLab


From 86a2d95248f7ce909b3a3c84dda4943f97b66f17 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 10:26:07 -0500
Subject: [PATCH 06/53] Fixing PHPSTAN errors

---
 core/modules/taxonomy/src/Hook/TaxonomyHooks.php | 2 --
 1 file changed, 2 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index e9e037c426e6..38637cd81b42 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -2,8 +2,6 @@
 
 namespace Drupal\taxonomy\Hook;
 
-use Drupal\taxonomy\Entity\Term;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Hook\Attribute\Hook;
-- 
GitLab


From 1c4473b75c31d6e75d5c80ddfd95db92bfb7805b Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 12:01:48 -0500
Subject: [PATCH 07/53] Updating baseline.

---
 core/.phpstan-baseline.php | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index 8e9b084c392e..26f15bb279b6 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -40071,30 +40071,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodeInsert\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodePredelete\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodeUpdate\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:taxonomyTermDelete\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\taxonomy\\\\Plugin\\\\Validation\\\\Constraint\\\\TaxonomyTermHierarchyConstraintValidator\\:\\:create\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
-- 
GitLab


From 86f61a02323b43940d814348eedcc2ada4acf8c5 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 12:10:55 -0500
Subject: [PATCH 08/53] Adding return types for delete_node_index and
 build_node_index.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index ab2a5b6ef806..dd02924e3366 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -51,7 +51,7 @@ public function __construct(ConfigFactoryInterface $configFactory, EntityTypeMan
    * @param \Drupal\node\Entity\Node $node
    *   The node entity.
    */
-  protected function build_node_index($node) {
+  protected function build_node_index($node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
     if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
@@ -98,7 +98,7 @@ protected function build_node_index($node) {
    * @param \Drupal\Core\Entity\EntityInterface $node
    *   The node entity.
    */
-  protected function delete_node_index(EntityInterface $node) {
+  protected function delete_node_index(EntityInterface $node): void {
     if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
       \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
-- 
GitLab


From 06ef25afb0372bb6d55fc7d41875a058a3c5b1ee Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 10:17:56 -0500
Subject: [PATCH 09/53] Splitting entity related hooks into separate class,
 adding build_node_index and delete_node_index as private methods.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 190 ++++++++++++++++++
 .../taxonomy/src/Hook/TaxonomyHooks.php       |  83 --------
 2 files changed, 190 insertions(+), 83 deletions(-)
 create mode 100644 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
new file mode 100644
index 000000000000..ab2a5b6ef806
--- /dev/null
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -0,0 +1,190 @@
+<?php
+
+namespace Drupal\taxonomy\Hook;
+
+use Drupal\taxonomy\Entity\Term;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\Core\Url;
+
+/**
+ * Hook implementations for taxonomy.
+ */
+class TaxonomyEntityHooks {
+
+  /**
+   * A config factory for retrieving required config settings.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * A config factory for retrieving required config settings.
+   *
+   * @property \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs TaxonomyEntityHooks.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
+   *   The configuration factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   *   The entity type manager.
+   */
+  public function __construct(ConfigFactoryInterface $configFactory, EntityTypeManagerInterface $entityTypeManager) {
+    $this->configFactory = $configFactory;
+    $this->entityTypeManager = $entityTypeManager;
+  }
+
+  /**
+   * Builds and inserts taxonomy index entries for a given node.
+   *
+   * The index lists all terms that are related to a given node entity, and is
+   * therefore maintained at the entity level.
+   *
+   * @param \Drupal\node\Entity\Node $node
+   *   The node entity.
+   */
+  protected function build_node_index($node) {
+    // We maintain a denormalized table of term/node relationships, containing
+    // only data for current, published nodes.
+    if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+      return;
+    }
+
+    $status = $node->isPublished();
+    $sticky = (int) $node->isSticky();
+    // We only maintain the taxonomy index for published nodes.
+    if ($status && $node->isDefaultRevision()) {
+      // Collect a unique list of all the term IDs from all node fields.
+      $tid_all = [];
+      $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+      foreach ($node->getFieldDefinitions() as $field) {
+        $field_name = $field->getName();
+        $class = $field->getItemDefinition()->getClass();
+        $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
+        if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
+          foreach ($node->getTranslationLanguages() as $language) {
+            foreach ($node->getTranslation($language->getId())->$field_name as $item) {
+              if (!$item->isEmpty()) {
+                $tid_all[$item->target_id] = $item->target_id;
+              }
+            }
+          }
+        }
+      }
+      // Insert index entries for all the node's terms.
+      if (!empty($tid_all)) {
+        $connection = \Drupal::database();
+        foreach ($tid_all as $tid) {
+          $connection->merge('taxonomy_index')
+            ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
+            ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
+            ->execute();
+        }
+      }
+    }
+  }
+
+  /**
+   * Deletes taxonomy index entries for a given node.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $node
+   *   The node entity.
+   */
+  protected function delete_node_index(EntityInterface $node) {
+    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+      \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+    }
+  }
+
+  /**
+   * Implements hook_entity_operation().
+   */
+  #[Hook('entity_operation')]
+  public function entityOperation(EntityInterface $term): array {
+    $operations = [];
+    if ($term instanceof Term && $term->access('create')) {
+      $operations['add-child'] = [
+        'title' => t('Add child'),
+        'weight' => 10,
+        'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
+          'taxonomy_vocabulary' => $term->bundle(),
+        ], [
+          'query' => [
+            'parent' => $term->id(),
+          ],
+        ]),
+      ];
+    }
+    return $operations;
+  }
+
+  /**
+   * @defgroup taxonomy_index Taxonomy indexing
+   * @{
+   * Functions to maintain taxonomy indexing.
+   *
+   * Taxonomy uses default field storage to store canonical relationships
+   * between terms and fieldable entities. However its most common use case
+   * requires listing all content associated with a term or group of terms
+   * sorted by creation date. To avoid slow queries due to joining across
+   * multiple node and field tables with various conditions and order by
+   * criteria, we maintain a denormalized table with all relationships between
+   * terms, published nodes and common sort criteria such as status, sticky and
+   * created. When using other field storage engines or alternative methods of
+   * denormalizing this data you should set the
+   * taxonomy.settings:maintain_index_table to '0' to avoid unnecessary writes
+   * in SQL.
+   */
+
+  /**
+   * Implements hook_ENTITY_TYPE_insert() for node entities.
+   */
+  #[Hook('node_insert')]
+  public function nodeInsert(EntityInterface $node): void {
+    // Add taxonomy index entries for the node.
+    $this->build_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_update() for node entities.
+   */
+  #[Hook('node_update')]
+  public function nodeUpdate(EntityInterface $node): void {
+    // If we're not dealing with the default revision of the node, do not make any
+    // change to the taxonomy index.
+    if (!$node->isDefaultRevision()) {
+      return;
+    }
+    $this->delete_node_index($node);
+    $this->build_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_predelete() for node entities.
+   */
+  #[Hook('node_predelete')]
+  public function nodePredelete(EntityInterface $node): void {
+    // Clean up the {taxonomy_index} table when nodes are deleted.
+    $this->delete_node_index($node);
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
+   */
+  #[Hook('taxonomy_term_delete')]
+  public function taxonomyTermDelete(Term $term): void {
+    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+      // Clean up the {taxonomy_index} table when terms are deleted.
+      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
+    }
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index fcbc82172927..e9e037c426e6 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -93,87 +93,4 @@ public function localTasksAlter(&$local_tasks): void {
     }
   }
 
-  /**
-   * Implements hook_entity_operation().
-   */
-  #[Hook('entity_operation')]
-  public function entityOperation(EntityInterface $term): array {
-    $operations = [];
-    if ($term instanceof Term && $term->access('create')) {
-      $operations['add-child'] = [
-        'title' => t('Add child'),
-        'weight' => 10,
-        'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
-          'taxonomy_vocabulary' => $term->bundle(),
-        ], [
-          'query' => [
-            'parent' => $term->id(),
-          ],
-        ]),
-      ];
-    }
-    return $operations;
-  }
-
-  /**
-   * @defgroup taxonomy_index Taxonomy indexing
-   * @{
-   * Functions to maintain taxonomy indexing.
-   *
-   * Taxonomy uses default field storage to store canonical relationships
-   * between terms and fieldable entities. However its most common use case
-   * requires listing all content associated with a term or group of terms
-   * sorted by creation date. To avoid slow queries due to joining across
-   * multiple node and field tables with various conditions and order by
-   * criteria, we maintain a denormalized table with all relationships between
-   * terms, published nodes and common sort criteria such as status, sticky and
-   * created. When using other field storage engines or alternative methods of
-   * denormalizing this data you should set the
-   * taxonomy.settings:maintain_index_table to '0' to avoid unnecessary writes
-   * in SQL.
-   */
-
-  /**
-   * Implements hook_ENTITY_TYPE_insert() for node entities.
-   */
-  #[Hook('node_insert')]
-  public function nodeInsert(EntityInterface $node) {
-    // Add taxonomy index entries for the node.
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_update() for node entities.
-   */
-  #[Hook('node_update')]
-  public function nodeUpdate(EntityInterface $node) {
-    // If we're not dealing with the default revision of the node, do not make any
-    // change to the taxonomy index.
-    if (!$node->isDefaultRevision()) {
-      return;
-    }
-    taxonomy_delete_node_index($node);
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_predelete() for node entities.
-   */
-  #[Hook('node_predelete')]
-  public function nodePredelete(EntityInterface $node) {
-    // Clean up the {taxonomy_index} table when nodes are deleted.
-    taxonomy_delete_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
-   */
-  #[Hook('taxonomy_term_delete')]
-  public function taxonomyTermDelete(Term $term) {
-    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
-      // Clean up the {taxonomy_index} table when terms are deleted.
-      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
-    }
-  }
-
 }
-- 
GitLab


From 92ed19965a4a8e2a7496c4ff00026658e966ce0a Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 10:26:07 -0500
Subject: [PATCH 10/53] Fixing PHPSTAN errors

---
 core/modules/taxonomy/src/Hook/TaxonomyHooks.php | 2 --
 1 file changed, 2 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index e9e037c426e6..38637cd81b42 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -2,8 +2,6 @@
 
 namespace Drupal\taxonomy\Hook;
 
-use Drupal\taxonomy\Entity\Term;
-use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Hook\Attribute\Hook;
-- 
GitLab


From 538b1a7e5c440c5d9d9adea81672e43a599b68c2 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 12:01:48 -0500
Subject: [PATCH 11/53] Updating baseline.

---
 core/.phpstan-baseline.php | 24 ------------------------
 1 file changed, 24 deletions(-)

diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index 8e9b084c392e..26f15bb279b6 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -40071,30 +40071,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodeInsert\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodePredelete\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:nodeUpdate\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:taxonomyTermDelete\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\taxonomy\\\\Plugin\\\\Validation\\\\Constraint\\\\TaxonomyTermHierarchyConstraintValidator\\:\\:create\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
-- 
GitLab


From c4c15539736e9e0cd3a5e0d5ca131c00b55ad47c Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 6 Feb 2025 12:10:55 -0500
Subject: [PATCH 12/53] Adding return types for delete_node_index and
 build_node_index.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index ab2a5b6ef806..dd02924e3366 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -51,7 +51,7 @@ public function __construct(ConfigFactoryInterface $configFactory, EntityTypeMan
    * @param \Drupal\node\Entity\Node $node
    *   The node entity.
    */
-  protected function build_node_index($node) {
+  protected function build_node_index($node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
     if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
@@ -98,7 +98,7 @@ protected function build_node_index($node) {
    * @param \Drupal\Core\Entity\EntityInterface $node
    *   The node entity.
    */
-  protected function delete_node_index(EntityInterface $node) {
+  protected function delete_node_index(EntityInterface $node): void {
     if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
       \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
-- 
GitLab


From 433f920483587ffa2345012237c1a6a1149c2f45 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Mon, 10 Feb 2025 13:15:21 -0500
Subject: [PATCH 13/53] Setting up TaxonomyHelp class.

---
 .../taxonomy/src/Hook/TaxonomyHelp.php        | 88 +++++++++++++++++++
 .../taxonomy/src/Hook/TaxonomyHooks.php       | 58 ------------
 2 files changed, 88 insertions(+), 58 deletions(-)
 create mode 100644 core/modules/taxonomy/src/Hook/TaxonomyHelp.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHelp.php b/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
new file mode 100644
index 000000000000..2425a6499cae
--- /dev/null
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Drupal\taxonomy\Hook;
+
+use Drupal\Core\Url;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslationInterface;
+
+/**
+ * Implements hook_help().
+ */
+#[Hook('help')]
+class TaxonomyHelp {
+
+  use StringTranslationTrait;
+
+  /**
+   * Constructs TaxonomyHelp.
+   *
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
+   *   The translation service.
+   */
+  public function __construct(TranslationInterface $string_translation) {
+    $this->stringTranslation = $string_translation;
+  }
+
+  /**
+   * Implements hook_help().
+   */
+  public function __invoke($route_name, RouteMatchInterface $route_match): string {
+    switch ($route_name) {
+      case 'help.page.taxonomy':
+        $field_ui_url = \Drupal::moduleHandler()->moduleExists('field_ui') ? Url::fromRoute('help.page', ['name' => 'field_ui'])->toString() : '#';
+        $output = '';
+        $output .= '<h2>' . $this->t('About') . '</h2>';
+        $output .= '<p>' . $this->t('The Taxonomy module allows users who have permission to create and edit content to categorize (tag) content of that type. Users who have the <em>Administer vocabularies and terms</em> <a href=":permissions" title="Taxonomy module permissions">permission</a> can add <em>vocabularies</em> that contain a set of related <em>terms</em>. The terms in a vocabulary can either be pre-set by an administrator or built gradually as content is added and edited. Terms may be organized hierarchically if desired.', [
+          ':permissions' => Url::fromRoute('user.admin_permissions.module', [
+            'modules' => 'taxonomy',
+          ])->toString(),
+        ]) . '</p>';
+        $output .= '<p>' . $this->t('For more information, see the <a href=":taxonomy">online documentation for the Taxonomy module</a>.', [':taxonomy' => 'https://www.drupal.org/docs/8/core/modules/taxonomy']) . '</p>';
+        $output .= '<h2>' . $this->t('Uses') . '</h2>';
+        $output .= '<dl>';
+        $output .= '<dt>' . $this->t('Managing vocabularies') . '</dt>';
+        $output .= '<dd>' . $this->t('Users who have the <em>Administer vocabularies and terms</em> permission can add and edit vocabularies from the <a href=":taxonomy_admin">Taxonomy administration page</a>. Vocabularies can be deleted from their <em>Edit vocabulary</em> page. Users with the <em>Taxonomy term: Administer fields</em> permission may add additional fields for terms in that vocabulary using the <a href=":field_ui">Field UI module</a>.', [
+          ':taxonomy_admin' => Url::fromRoute('entity.taxonomy_vocabulary.collection')->toString(),
+          ':field_ui' => $field_ui_url,
+        ]) . '</dd>';
+        $output .= '<dt>' . $this->t('Managing terms') . '</dt>';
+        $output .= '<dd>' . $this->t('Users who have the <em>Administer vocabularies and terms</em> permission or the <em>Edit terms</em> permission for a particular vocabulary can add, edit, and organize the terms in a vocabulary from a vocabulary\'s term listing page, which can be accessed by going to the <a href=":taxonomy_admin">Taxonomy administration page</a> and clicking <em>List terms</em> in the <em>Operations</em> column. Users must have the <em>Administer vocabularies and terms</em> permission or the <em>Delete terms</em> permission for a particular vocabulary to delete terms.', [
+          ':taxonomy_admin' => Url::fromRoute('entity.taxonomy_vocabulary.collection')->toString(),
+        ]) . ' </dd>';
+        $output .= '<dt>' . $this->t('Classifying entity content') . '</dt>';
+        $output .= '<dd>' . $this->t('A user with the <em>Administer fields</em> permission for a certain entity type may add <em>Taxonomy term</em> reference fields to the entity type, which will allow entities to be classified using taxonomy terms. See the <a href=":entity_reference">Entity Reference help</a> for more information about reference fields. See the <a href=":field">Field module help</a> and the <a href=":field_ui">Field UI help</a> pages for general information on fields and how to create and manage them.', [
+          ':field_ui' => $field_ui_url,
+          ':field' => Url::fromRoute('help.page', [
+            'name' => 'field',
+          ])->toString(),
+          ':entity_reference' => Url::fromRoute('help.page', [
+            'name' => 'entity_reference',
+          ])->toString(),
+        ]) . '</dd>';
+        $output .= '<dt>' . $this->t('Adding new terms during content creation') . '</dt>';
+        $output .= '<dd>' . $this->t("Allowing users to add new terms gradually builds a vocabulary as content is added and edited. Users can add new terms if either of the two <em>Autocomplete</em> widgets is chosen for the Taxonomy term reference field in the <em>Manage form display</em> page for the field. You will also need to enable the <em>Create referenced entities if they don't already exist</em> option, and restrict the field to one vocabulary.") . '</dd>';
+        $output .= '<dt>' . $this->t('Configuring displays and form displays') . '</dt>';
+        $output .= '<dd>' . $this->t('See the <a href=":entity_reference">Entity Reference help</a> page for the field widgets and formatters that can be configured for any reference field on the <em>Manage display</em> and <em>Manage form display</em> pages. Taxonomy additionally provides an <em>RSS category</em> formatter that displays nothing when the entity item is displayed as HTML, but displays an RSS category instead of a list when the entity item is displayed in an RSS feed.', [
+          ':entity_reference' => Url::fromRoute('help.page', [
+            'name' => 'entity_reference',
+          ])->toString(),
+        ]) . '</li>';
+        $output .= '</ul>';
+        $output .= '</dd>';
+        $output .= '</dl>';
+        return $output;
+
+      case 'entity.taxonomy_vocabulary.collection':
+        $output = '<p>' . $this->t('Taxonomy is for categorizing content. Terms are grouped into vocabularies. For example, a vocabulary called "Fruit" would contain the terms "Apple" and "Banana".') . '</p>';
+        return $output;
+
+      default:
+        $output = '';
+        return $output;
+    }
+  }
+
+}
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index 38637cd81b42..88399198fae2 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -2,8 +2,6 @@
 
 namespace Drupal\taxonomy\Hook;
 
-use Drupal\Core\Url;
-use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Hook\Attribute\Hook;
 
 /**
@@ -11,62 +9,6 @@
  */
 class TaxonomyHooks {
 
-  /**
-   * Implements hook_help().
-   */
-  #[Hook('help')]
-  public function help($route_name, RouteMatchInterface $route_match) {
-    switch ($route_name) {
-      case 'help.page.taxonomy':
-        $field_ui_url = \Drupal::moduleHandler()->moduleExists('field_ui') ? Url::fromRoute('help.page', ['name' => 'field_ui'])->toString() : '#';
-        $output = '';
-        $output .= '<h2>' . t('About') . '</h2>';
-        $output .= '<p>' . t('The Taxonomy module allows users who have permission to create and edit content to categorize (tag) content of that type. Users who have the <em>Administer vocabularies and terms</em> <a href=":permissions" title="Taxonomy module permissions">permission</a> can add <em>vocabularies</em> that contain a set of related <em>terms</em>. The terms in a vocabulary can either be pre-set by an administrator or built gradually as content is added and edited. Terms may be organized hierarchically if desired.', [
-          ':permissions' => Url::fromRoute('user.admin_permissions.module', [
-            'modules' => 'taxonomy',
-          ])->toString(),
-        ]) . '</p>';
-        $output .= '<p>' . t('For more information, see the <a href=":taxonomy">online documentation for the Taxonomy module</a>.', [':taxonomy' => 'https://www.drupal.org/docs/8/core/modules/taxonomy']) . '</p>';
-        $output .= '<h2>' . t('Uses') . '</h2>';
-        $output .= '<dl>';
-        $output .= '<dt>' . t('Managing vocabularies') . '</dt>';
-        $output .= '<dd>' . t('Users who have the <em>Administer vocabularies and terms</em> permission can add and edit vocabularies from the <a href=":taxonomy_admin">Taxonomy administration page</a>. Vocabularies can be deleted from their <em>Edit vocabulary</em> page. Users with the <em>Taxonomy term: Administer fields</em> permission may add additional fields for terms in that vocabulary using the <a href=":field_ui">Field UI module</a>.', [
-          ':taxonomy_admin' => Url::fromRoute('entity.taxonomy_vocabulary.collection')->toString(),
-          ':field_ui' => $field_ui_url,
-        ]) . '</dd>';
-        $output .= '<dt>' . t('Managing terms') . '</dt>';
-        $output .= '<dd>' . t('Users who have the <em>Administer vocabularies and terms</em> permission or the <em>Edit terms</em> permission for a particular vocabulary can add, edit, and organize the terms in a vocabulary from a vocabulary\'s term listing page, which can be accessed by going to the <a href=":taxonomy_admin">Taxonomy administration page</a> and clicking <em>List terms</em> in the <em>Operations</em> column. Users must have the <em>Administer vocabularies and terms</em> permission or the <em>Delete terms</em> permission for a particular vocabulary to delete terms.', [
-          ':taxonomy_admin' => Url::fromRoute('entity.taxonomy_vocabulary.collection')->toString(),
-        ]) . ' </dd>';
-        $output .= '<dt>' . t('Classifying entity content') . '</dt>';
-        $output .= '<dd>' . t('A user with the <em>Administer fields</em> permission for a certain entity type may add <em>Taxonomy term</em> reference fields to the entity type, which will allow entities to be classified using taxonomy terms. See the <a href=":entity_reference">Entity Reference help</a> for more information about reference fields. See the <a href=":field">Field module help</a> and the <a href=":field_ui">Field UI help</a> pages for general information on fields and how to create and manage them.', [
-          ':field_ui' => $field_ui_url,
-          ':field' => Url::fromRoute('help.page', [
-            'name' => 'field',
-          ])->toString(),
-          ':entity_reference' => Url::fromRoute('help.page', [
-            'name' => 'entity_reference',
-          ])->toString(),
-        ]) . '</dd>';
-        $output .= '<dt>' . t('Adding new terms during content creation') . '</dt>';
-        $output .= '<dd>' . t("Allowing users to add new terms gradually builds a vocabulary as content is added and edited. Users can add new terms if either of the two <em>Autocomplete</em> widgets is chosen for the Taxonomy term reference field in the <em>Manage form display</em> page for the field. You will also need to enable the <em>Create referenced entities if they don't already exist</em> option, and restrict the field to one vocabulary.") . '</dd>';
-        $output .= '<dt>' . t('Configuring displays and form displays') . '</dt>';
-        $output .= '<dd>' . t('See the <a href=":entity_reference">Entity Reference help</a> page for the field widgets and formatters that can be configured for any reference field on the <em>Manage display</em> and <em>Manage form display</em> pages. Taxonomy additionally provides an <em>RSS category</em> formatter that displays nothing when the entity item is displayed as HTML, but displays an RSS category instead of a list when the entity item is displayed in an RSS feed.', [
-          ':entity_reference' => Url::fromRoute('help.page', [
-            'name' => 'entity_reference',
-          ])->toString(),
-        ]) . '</li>';
-        $output .= '</ul>';
-        $output .= '</dd>';
-        $output .= '</dl>';
-        return $output;
-
-      case 'entity.taxonomy_vocabulary.collection':
-        $output = '<p>' . t('Taxonomy is for categorizing content. Terms are grouped into vocabularies. For example, a vocabulary called "Fruit" would contain the terms "Apple" and "Banana".') . '</p>';
-        return $output;
-    }
-  }
-
   /**
    * Implements hook_theme().
    */
-- 
GitLab


From cf857a6507c0b5f6e699e622f6b39ea204a58d07 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Mon, 10 Feb 2025 13:21:06 -0500
Subject: [PATCH 14/53] Updating baseline.

---
 core/.phpstan-baseline.php | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/core/.phpstan-baseline.php b/core/.phpstan-baseline.php
index 34b8d822b660..e5127801c51a 100644
--- a/core/.phpstan-baseline.php
+++ b/core/.phpstan-baseline.php
@@ -40035,12 +40035,6 @@
 	'count' => 1,
 	'path' => __DIR__ . '/modules/taxonomy/src/Form/VocabularyResetForm.php',
 ];
-$ignoreErrors[] = [
-	'message' => '#^Method Drupal\\\\taxonomy\\\\Hook\\\\TaxonomyHooks\\:\\:help\\(\\) has no return type specified\\.$#',
-	'identifier' => 'missingType.return',
-	'count' => 1,
-	'path' => __DIR__ . '/modules/taxonomy/src/Hook/TaxonomyHooks.php',
-];
 $ignoreErrors[] = [
 	'message' => '#^Method Drupal\\\\taxonomy\\\\Plugin\\\\Validation\\\\Constraint\\\\TaxonomyTermHierarchyConstraintValidator\\:\\:create\\(\\) has no return type specified\\.$#',
 	'identifier' => 'missingType.return',
-- 
GitLab


From f976191b3c8ecc8ebc6abb03262a52ac4f3e6d44 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Mon, 10 Feb 2025 14:09:45 -0500
Subject: [PATCH 15/53] Taxonomy Theme Hook class.

---
 .../modules/taxonomy/src/Hook/TaxonomyHooks.php |  8 --------
 .../modules/taxonomy/src/Hook/TaxonomyTheme.php | 17 +++++++++++++++++
 2 files changed, 17 insertions(+), 8 deletions(-)
 create mode 100644 core/modules/taxonomy/src/Hook/TaxonomyTheme.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index 88399198fae2..be0484965937 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -9,14 +9,6 @@
  */
 class TaxonomyHooks {
 
-  /**
-   * Implements hook_theme().
-   */
-  #[Hook('theme')]
-  public function theme() : array {
-    return ['taxonomy_term' => ['render element' => 'elements']];
-  }
-
   /**
    * Implements hook_local_tasks_alter().
    *
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyTheme.php b/core/modules/taxonomy/src/Hook/TaxonomyTheme.php
new file mode 100644
index 000000000000..2f7dba8a2ee2
--- /dev/null
+++ b/core/modules/taxonomy/src/Hook/TaxonomyTheme.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace Drupal\taxonomy\Hook;
+
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Implements hook_theme().
+ */
+#[Hook('theme')]
+class TaxonomyTheme {
+
+  public function __invoke() : array {
+    return ['taxonomy_term' => ['render element' => 'elements']];
+  }
+
+}
-- 
GitLab


From 85f2a01653781a07689b984324e46e4e5352a1ed Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Wed, 26 Feb 2025 13:33:07 -0500
Subject: [PATCH 16/53] Fixing merge conflict.

---
 .../taxonomy/src/Hook/TaxonomyHooks.php       | 162 ------------------
 1 file changed, 162 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index 778b2019e7fd..4cd838b6a535 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -2,14 +2,6 @@
 
 namespace Drupal\taxonomy\Hook;
 
-<<<<<<< HEAD
-=======
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\taxonomy\Entity\Term;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Url;
-use Drupal\Core\Routing\RouteMatchInterface;
->>>>>>> 11.x
 use Drupal\Core\Hook\Attribute\Hook;
 
 /**
@@ -20,74 +12,6 @@ class TaxonomyHooks {
   use StringTranslationTrait;
 
   /**
-<<<<<<< HEAD
-=======
-   * Implements hook_help().
-   */
-  #[Hook('help')]
-  public function help($route_name, RouteMatchInterface $route_match): ?string {
-    switch ($route_name) {
-      case 'help.page.taxonomy':
-        $field_ui_url = \Drupal::moduleHandler()->moduleExists('field_ui') ? Url::fromRoute('help.page', ['name' => 'field_ui'])->toString() : '#';
-        $output = '';
-        $output .= '<h2>' . $this->t('About') . '</h2>';
-        $output .= '<p>' . $this->t('The Taxonomy module allows users who have permission to create and edit content to categorize (tag) content of that type. Users who have the <em>Administer vocabularies and terms</em> <a href=":permissions" title="Taxonomy module permissions">permission</a> can add <em>vocabularies</em> that contain a set of related <em>terms</em>. The terms in a vocabulary can either be pre-set by an administrator or built gradually as content is added and edited. Terms may be organized hierarchically if desired.', [
-          ':permissions' => Url::fromRoute('user.admin_permissions.module', [
-            'modules' => 'taxonomy',
-          ])->toString(),
-        ]) . '</p>';
-        $output .= '<p>' . $this->t('For more information, see the <a href=":taxonomy">online documentation for the Taxonomy module</a>.', [':taxonomy' => 'https://www.drupal.org/docs/8/core/modules/taxonomy']) . '</p>';
-        $output .= '<h2>' . $this->t('Uses') . '</h2>';
-        $output .= '<dl>';
-        $output .= '<dt>' . $this->t('Managing vocabularies') . '</dt>';
-        $output .= '<dd>' . $this->t('Users who have the <em>Administer vocabularies and terms</em> permission can add and edit vocabularies from the <a href=":taxonomy_admin">Taxonomy administration page</a>. Vocabularies can be deleted from their <em>Edit vocabulary</em> page. Users with the <em>Taxonomy term: Administer fields</em> permission may add additional fields for terms in that vocabulary using the <a href=":field_ui">Field UI module</a>.', [
-          ':taxonomy_admin' => Url::fromRoute('entity.taxonomy_vocabulary.collection')->toString(),
-          ':field_ui' => $field_ui_url,
-        ]) . '</dd>';
-        $output .= '<dt>' . $this->t('Managing terms') . '</dt>';
-        $output .= '<dd>' . $this->t('Users who have the <em>Administer vocabularies and terms</em> permission or the <em>Edit terms</em> permission for a particular vocabulary can add, edit, and organize the terms in a vocabulary from a vocabulary\'s term listing page, which can be accessed by going to the <a href=":taxonomy_admin">Taxonomy administration page</a> and clicking <em>List terms</em> in the <em>Operations</em> column. Users must have the <em>Administer vocabularies and terms</em> permission or the <em>Delete terms</em> permission for a particular vocabulary to delete terms.', [
-          ':taxonomy_admin' => Url::fromRoute('entity.taxonomy_vocabulary.collection')->toString(),
-        ]) . ' </dd>';
-        $output .= '<dt>' . $this->t('Classifying entity content') . '</dt>';
-        $output .= '<dd>' . $this->t('A user with the <em>Administer fields</em> permission for a certain entity type may add <em>Taxonomy term</em> reference fields to the entity type, which will allow entities to be classified using taxonomy terms. See the <a href=":entity_reference">Entity Reference help</a> for more information about reference fields. See the <a href=":field">Field module help</a> and the <a href=":field_ui">Field UI help</a> pages for general information on fields and how to create and manage them.', [
-          ':field_ui' => $field_ui_url,
-          ':field' => Url::fromRoute('help.page', [
-            'name' => 'field',
-          ])->toString(),
-          ':entity_reference' => Url::fromRoute('help.page', [
-            'name' => 'entity_reference',
-          ])->toString(),
-        ]) . '</dd>';
-        $output .= '<dt>' . $this->t('Adding new terms during content creation') . '</dt>';
-        $output .= '<dd>' . $this->t("Allowing users to add new terms gradually builds a vocabulary as content is added and edited. Users can add new terms if either of the two <em>Autocomplete</em> widgets is chosen for the Taxonomy term reference field in the <em>Manage form display</em> page for the field. You will also need to enable the <em>Create referenced entities if they don't already exist</em> option, and restrict the field to one vocabulary.") . '</dd>';
-        $output .= '<dt>' . $this->t('Configuring displays and form displays') . '</dt>';
-        $output .= '<dd>' . $this->t('See the <a href=":entity_reference">Entity Reference help</a> page for the field widgets and formatters that can be configured for any reference field on the <em>Manage display</em> and <em>Manage form display</em> pages. Taxonomy additionally provides an <em>RSS category</em> formatter that displays nothing when the entity item is displayed as HTML, but displays an RSS category instead of a list when the entity item is displayed in an RSS feed.', [
-          ':entity_reference' => Url::fromRoute('help.page', [
-            'name' => 'entity_reference',
-          ])->toString(),
-        ]) . '</li>';
-        $output .= '</ul>';
-        $output .= '</dd>';
-        $output .= '</dl>';
-        return $output;
-
-      case 'entity.taxonomy_vocabulary.collection':
-        $output = '<p>' . $this->t('Taxonomy is for categorizing content. Terms are grouped into vocabularies. For example, a vocabulary called "Fruit" would contain the terms "Apple" and "Banana".') . '</p>';
-        return $output;
-    }
-    return NULL;
-  }
-
-  /**
-   * Implements hook_theme().
-   */
-  #[Hook('theme')]
-  public function theme() : array {
-    return ['taxonomy_term' => ['render element' => 'elements']];
-  }
-
-  /**
->>>>>>> 11.x
    * Implements hook_local_tasks_alter().
    *
    * @todo Evaluate removing as part of https://www.drupal.org/node/2358923.
@@ -103,90 +27,4 @@ public function localTasksAlter(&$local_tasks): void {
     }
   }
 
-<<<<<<< HEAD
-=======
-  /**
-   * Implements hook_entity_operation().
-   */
-  #[Hook('entity_operation')]
-  public function entityOperation(EntityInterface $term): array {
-    $operations = [];
-    if ($term instanceof Term && $term->access('create')) {
-      $operations['add-child'] = [
-        'title' => $this->t('Add child'),
-        'weight' => 10,
-        'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
-          'taxonomy_vocabulary' => $term->bundle(),
-        ], [
-          'query' => [
-            'parent' => $term->id(),
-          ],
-        ]),
-      ];
-    }
-    return $operations;
-  }
-
-  /**
-   * @defgroup taxonomy_index Taxonomy indexing
-   * @{
-   * Functions to maintain taxonomy indexing.
-   *
-   * Taxonomy uses default field storage to store canonical relationships
-   * between terms and fieldable entities. However its most common use case
-   * requires listing all content associated with a term or group of terms
-   * sorted by creation date. To avoid slow queries due to joining across
-   * multiple node and field tables with various conditions and order by
-   * criteria, we maintain a denormalized table with all relationships between
-   * terms, published nodes and common sort criteria such as status, sticky and
-   * created. When using other field storage engines or alternative methods of
-   * denormalizing this data you should set the
-   * taxonomy.settings:maintain_index_table to '0' to avoid unnecessary writes
-   * in SQL.
-   */
-
-  /**
-   * Implements hook_ENTITY_TYPE_insert() for node entities.
-   */
-  #[Hook('node_insert')]
-  public function nodeInsert(EntityInterface $node): void {
-    // Add taxonomy index entries for the node.
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_update() for node entities.
-   */
-  #[Hook('node_update')]
-  public function nodeUpdate(EntityInterface $node): void {
-    // If we're not dealing with the default revision of the node, do not make
-    // any change to the taxonomy index.
-    if (!$node->isDefaultRevision()) {
-      return;
-    }
-    taxonomy_delete_node_index($node);
-    taxonomy_build_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_predelete() for node entities.
-   */
-  #[Hook('node_predelete')]
-  public function nodePredelete(EntityInterface $node): void {
-    // Clean up the {taxonomy_index} table when nodes are deleted.
-    taxonomy_delete_node_index($node);
-  }
-
-  /**
-   * Implements hook_ENTITY_TYPE_delete() for taxonomy_term entities.
-   */
-  #[Hook('taxonomy_term_delete')]
-  public function taxonomyTermDelete(Term $term): void {
-    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
-      // Clean up the {taxonomy_index} table when terms are deleted.
-      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
-    }
-  }
-
->>>>>>> 11.x
 }
-- 
GitLab


From 805b5adc11c3baba62cf36caef7701b8c0f04921 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Wed, 26 Feb 2025 15:06:07 -0500
Subject: [PATCH 17/53] Adding dependency injection for translation.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php       | 13 ++++++++++---
 core/modules/taxonomy/src/Hook/TaxonomyHooks.php    |  2 --
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index dd02924e3366..002a02977b05 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -8,6 +8,8 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Url;
 
 /**
@@ -15,6 +17,8 @@
  */
 class TaxonomyEntityHooks {
 
+  use stringTranslationTrait;
+
   /**
    * A config factory for retrieving required config settings.
    *
@@ -25,7 +29,7 @@ class TaxonomyEntityHooks {
   /**
    * A config factory for retrieving required config settings.
    *
-   * @property \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
    */
   protected $entityTypeManager;
 
@@ -36,10 +40,13 @@ class TaxonomyEntityHooks {
    *   The configuration factory.
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
    *   The entity type manager.
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
+   *   The translation service.
    */
-  public function __construct(ConfigFactoryInterface $configFactory, EntityTypeManagerInterface $entityTypeManager) {
+  public function __construct(ConfigFactoryInterface $configFactory, EntityTypeManagerInterface $entityTypeManager, TranslationInterface $string_translation) {
     $this->configFactory = $configFactory;
     $this->entityTypeManager = $entityTypeManager;
+    $this->stringTranslation = $string_translation;
   }
 
   /**
@@ -112,7 +119,7 @@ public function entityOperation(EntityInterface $term): array {
     $operations = [];
     if ($term instanceof Term && $term->access('create')) {
       $operations['add-child'] = [
-        'title' => t('Add child'),
+        'title' => $this->t('Add child'),
         'weight' => 10,
         'url' => Url::fromRoute('entity.taxonomy_term.add_form', [
           'taxonomy_vocabulary' => $term->bundle(),
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
index 4cd838b6a535..be0484965937 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
@@ -9,8 +9,6 @@
  */
 class TaxonomyHooks {
 
-  use StringTranslationTrait;
-
   /**
    * Implements hook_local_tasks_alter().
    *
-- 
GitLab


From a17b8869328faeb1bf77ceef58411c072698463c Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Wed, 26 Feb 2025 15:32:26 -0500
Subject: [PATCH 18/53] Converting helper functions to camelCase, cleaning up
 constructor.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 45 +++++--------------
 1 file changed, 11 insertions(+), 34 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 002a02977b05..b26e7cd6e3f3 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -19,34 +19,11 @@ class TaxonomyEntityHooks {
 
   use stringTranslationTrait;
 
-  /**
-   * A config factory for retrieving required config settings.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
-  /**
-   * A config factory for retrieving required config settings.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * Constructs TaxonomyEntityHooks.
-   *
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
-   *   The configuration factory.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
-   *   The entity type manager.
-   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
-   *   The translation service.
-   */
-  public function __construct(ConfigFactoryInterface $configFactory, EntityTypeManagerInterface $entityTypeManager, TranslationInterface $string_translation) {
-    $this->configFactory = $configFactory;
-    $this->entityTypeManager = $entityTypeManager;
-    $this->stringTranslation = $string_translation;
+  public function __construct(
+    protected ConfigFactoryInterface $configFactory, 
+    protected EntityTypeManagerInterface $entityTypeManager, 
+    protected TranslationInterface $string_translation
+  ) {
   }
 
   /**
@@ -58,7 +35,7 @@ public function __construct(ConfigFactoryInterface $configFactory, EntityTypeMan
    * @param \Drupal\node\Entity\Node $node
    *   The node entity.
    */
-  protected function build_node_index($node): void {
+  protected function buildNodeIndex($node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
     if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
@@ -105,7 +82,7 @@ protected function build_node_index($node): void {
    * @param \Drupal\Core\Entity\EntityInterface $node
    *   The node entity.
    */
-  protected function delete_node_index(EntityInterface $node): void {
+  protected function deleteNodeIndex(EntityInterface $node): void {
     if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
       \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
@@ -157,7 +134,7 @@ public function entityOperation(EntityInterface $term): array {
   #[Hook('node_insert')]
   public function nodeInsert(EntityInterface $node): void {
     // Add taxonomy index entries for the node.
-    $this->build_node_index($node);
+    $this->buildNodeIndex($node);
   }
 
   /**
@@ -170,8 +147,8 @@ public function nodeUpdate(EntityInterface $node): void {
     if (!$node->isDefaultRevision()) {
       return;
     }
-    $this->delete_node_index($node);
-    $this->build_node_index($node);
+    $this->deleteNodeIndex($node);
+    $this->buildNodeIndex($node);
   }
 
   /**
@@ -180,7 +157,7 @@ public function nodeUpdate(EntityInterface $node): void {
   #[Hook('node_predelete')]
   public function nodePredelete(EntityInterface $node): void {
     // Clean up the {taxonomy_index} table when nodes are deleted.
-    $this->delete_node_index($node);
+    $this->deleteNodeIndex($node);
   }
 
   /**
-- 
GitLab


From 5589891c67c90126d1ed75fff6e8ca266200410c Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Wed, 26 Feb 2025 15:35:48 -0500
Subject: [PATCH 19/53] Fixing PHPCS errors.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index b26e7cd6e3f3..072beeb3738e 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -20,9 +20,9 @@ class TaxonomyEntityHooks {
   use stringTranslationTrait;
 
   public function __construct(
-    protected ConfigFactoryInterface $configFactory, 
-    protected EntityTypeManagerInterface $entityTypeManager, 
-    protected TranslationInterface $string_translation
+    protected ConfigFactoryInterface $configFactory,
+    protected EntityTypeManagerInterface $entityTypeManager,
+    protected TranslationInterface $string_translation,
   ) {
   }
 
-- 
GitLab


From 1f1d479c6ff7403b805c5ea8f42410c8d31ebc5c Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Wed, 26 Feb 2025 16:41:09 -0500
Subject: [PATCH 20/53] Adding NodeInterface type for helper functions.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 072beeb3738e..aeb2f811b566 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -8,6 +8,7 @@
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\node\NodeInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Url;
@@ -32,10 +33,10 @@ public function __construct(
    * The index lists all terms that are related to a given node entity, and is
    * therefore maintained at the entity level.
    *
-   * @param \Drupal\node\Entity\Node $node
+   * @param \Drupal\node\NodeInterface $node
    *   The node entity.
    */
-  protected function buildNodeIndex($node): void {
+  protected function buildNodeIndex(NodeInterface $node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
     if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
@@ -79,10 +80,10 @@ protected function buildNodeIndex($node): void {
   /**
    * Deletes taxonomy index entries for a given node.
    *
-   * @param \Drupal\Core\Entity\EntityInterface $node
+   * @param \Drupal\node\NodeInterface $node
    *   The node entity.
    */
-  protected function deleteNodeIndex(EntityInterface $node): void {
+  protected function deleteNodeIndex(NodeInterface $node): void {
     if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
       \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
-- 
GitLab


From f7ebf00480bdf79ebf0bd3d35dd72834e5b51175 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 27 Feb 2025 06:44:44 -0500
Subject: [PATCH 21/53] Adding dependency injection for database connection.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index aeb2f811b566..ff0ddc30d898 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -4,6 +4,7 @@
 
 use Drupal\taxonomy\Entity\Term;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Database\Connection;
 use Drupal\Core\Hook\Attribute\Hook;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -22,6 +23,7 @@ class TaxonomyEntityHooks {
 
   public function __construct(
     protected ConfigFactoryInterface $configFactory,
+    protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
     protected TranslationInterface $string_translation,
   ) {
@@ -66,9 +68,8 @@ protected function buildNodeIndex(NodeInterface $node): void {
       }
       // Insert index entries for all the node's terms.
       if (!empty($tid_all)) {
-        $connection = \Drupal::database();
         foreach ($tid_all as $tid) {
-          $connection->merge('taxonomy_index')
+          $this->database->merge('taxonomy_index')
             ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
             ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
             ->execute();
@@ -85,7 +86,7 @@ protected function buildNodeIndex(NodeInterface $node): void {
    */
   protected function deleteNodeIndex(NodeInterface $node): void {
     if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
-      \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+      $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
   }
 
@@ -168,7 +169,7 @@ public function nodePredelete(EntityInterface $node): void {
   public function taxonomyTermDelete(Term $term): void {
     if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
       // Clean up the {taxonomy_index} table when terms are deleted.
-      \Drupal::database()->delete('taxonomy_index')->condition('tid', $term->id())->execute();
+      $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
   }
 
-- 
GitLab


From 4cb4f0c89e3749a0d718535e18b5d94af910c46c Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 27 Feb 2025 07:27:27 -0500
Subject: [PATCH 22/53] Adding dependency injection for config.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index ff0ddc30d898..ad3362d9b5ce 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -41,7 +41,8 @@ public function __construct(
   protected function buildNodeIndex(NodeInterface $node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
-    if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+    $config = $this->configFactory->get('taxonomy.settings');
+    if (!$config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
       return;
     }
 
@@ -85,7 +86,8 @@ protected function buildNodeIndex(NodeInterface $node): void {
    *   The node entity.
    */
   protected function deleteNodeIndex(NodeInterface $node): void {
-    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+    $config = $this->configFactory->get('taxonomy.settings');
+    if ($config->get('maintain_index_table')) {
       $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
   }
@@ -167,7 +169,8 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+    $config = $this->configFactory->get('taxonomy.settings');
+    if ($config->get('maintain_index_table')) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
-- 
GitLab


From 639d7d9bc168fc1af49a29858cff5035f134e654 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 27 Feb 2025 09:37:42 -0500
Subject: [PATCH 23/53] Converting taxonomy_theme_suggestions_taxonomy_term,
 adding to theme hooks, updating theme hooks.

---
 .../taxonomy/src/Hook/TaxonomyTheme.php       | 17 ---------
 .../taxonomy/src/Hook/TaxonomyThemeHooks.php  | 36 +++++++++++++++++++
 core/modules/taxonomy/taxonomy.module         | 15 --------
 3 files changed, 36 insertions(+), 32 deletions(-)
 delete mode 100644 core/modules/taxonomy/src/Hook/TaxonomyTheme.php
 create mode 100644 core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyTheme.php b/core/modules/taxonomy/src/Hook/TaxonomyTheme.php
deleted file mode 100644
index 2f7dba8a2ee2..000000000000
--- a/core/modules/taxonomy/src/Hook/TaxonomyTheme.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-namespace Drupal\taxonomy\Hook;
-
-use Drupal\Core\Hook\Attribute\Hook;
-
-/**
- * Implements hook_theme().
- */
-#[Hook('theme')]
-class TaxonomyTheme {
-
-  public function __invoke() : array {
-    return ['taxonomy_term' => ['render element' => 'elements']];
-  }
-
-}
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
new file mode 100644
index 000000000000..ead2f34f2b4a
--- /dev/null
+++ b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\taxonomy\Hook;
+
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Implements hook_theme().
+ */
+class TaxonomyThemeHooks {
+
+  /**
+   * Implements hook_theme().
+   */
+  #[Hook('theme')]
+  public function taxonomyTheme($existing, $type, $theme, $path): array {
+    return ['taxonomy_term' => ['render element' => 'elements']];
+  }
+
+  /**
+   * Implements hook_theme_suggestions_HOOK().
+   */
+  #[Hook('theme_suggestions_taxonomy_term')]
+  public function themeSuggestionsTaxonomyTerm(array $variables): array {
+    $suggestions = [];
+
+    /** @var \Drupal\taxonomy\TermInterface $term */
+    $term = $variables['elements']['#taxonomy_term'];
+
+    $suggestions[] = 'taxonomy_term__' . $term->bundle();
+    $suggestions[] = 'taxonomy_term__' . $term->id();
+
+    return $suggestions;
+  }
+
+}
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index bbced8262a60..c6512d623112 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -9,21 +9,6 @@
 use Drupal\Core\Render\Element;
 use Drupal\taxonomy\Entity\Term;
 
-/**
- * Implements hook_theme_suggestions_HOOK().
- */
-function taxonomy_theme_suggestions_taxonomy_term(array $variables): array {
-  $suggestions = [];
-
-  /** @var \Drupal\taxonomy\TermInterface $term */
-  $term = $variables['elements']['#taxonomy_term'];
-
-  $suggestions[] = 'taxonomy_term__' . $term->bundle();
-  $suggestions[] = 'taxonomy_term__' . $term->id();
-
-  return $suggestions;
-}
-
 /**
  * Prepares variables for taxonomy term templates.
  *
-- 
GitLab


From 49dfd1d8215cd1793f682060075f52e395ff9b6b Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 27 Feb 2025 11:00:30 -0500
Subject: [PATCH 24/53] Cleaning up translation implementation.

---
 .../modules/taxonomy/src/Hook/TaxonomyEntityHooks.php |  2 --
 core/modules/taxonomy/src/Hook/TaxonomyHelp.php       | 11 -----------
 2 files changed, 13 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index ad3362d9b5ce..bc1ab56d995f 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -11,7 +11,6 @@
 use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\node\NodeInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Url;
 
 /**
@@ -25,7 +24,6 @@ public function __construct(
     protected ConfigFactoryInterface $configFactory,
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
-    protected TranslationInterface $string_translation,
   ) {
   }
 
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHelp.php b/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
index 2425a6499cae..4fc29b3174dc 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
@@ -6,7 +6,6 @@
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Hook\Attribute\Hook;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\Core\StringTranslation\TranslationInterface;
 
 /**
  * Implements hook_help().
@@ -16,16 +15,6 @@ class TaxonomyHelp {
 
   use StringTranslationTrait;
 
-  /**
-   * Constructs TaxonomyHelp.
-   *
-   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
-   *   The translation service.
-   */
-  public function __construct(TranslationInterface $string_translation) {
-    $this->stringTranslation = $string_translation;
-  }
-
   /**
    * Implements hook_help().
    */
-- 
GitLab


From 291c58f27d332fa92e79730c866b6ef0b7a010df Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 27 Feb 2025 11:06:10 -0500
Subject: [PATCH 25/53] Setting config in constructor.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index bc1ab56d995f..c158b390c234 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -25,6 +25,7 @@ public function __construct(
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
   ) {
+    $this->config = configFactory->get('taxonomy.settings');
   }
 
   /**
@@ -39,8 +40,7 @@ public function __construct(
   protected function buildNodeIndex(NodeInterface $node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
-    $config = $this->configFactory->get('taxonomy.settings');
-    if (!$config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+    if (!$this->config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
       return;
     }
 
@@ -84,8 +84,7 @@ protected function buildNodeIndex(NodeInterface $node): void {
    *   The node entity.
    */
   protected function deleteNodeIndex(NodeInterface $node): void {
-    $config = $this->configFactory->get('taxonomy.settings');
-    if ($config->get('maintain_index_table')) {
+    if ($this->config->get('maintain_index_table')) {
       $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
   }
@@ -167,8 +166,7 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    $config = $this->configFactory->get('taxonomy.settings');
-    if ($config->get('maintain_index_table')) {
+    if ($this->config->get('maintain_index_table')) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
-- 
GitLab


From 1af1bdf5058fcfc421bd3582be72d1a94f48a77c Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 28 Feb 2025 09:43:53 -0500
Subject: [PATCH 26/53] Reverting setting of config in constructor.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index c158b390c234..bc1ab56d995f 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -25,7 +25,6 @@ public function __construct(
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
   ) {
-    $this->config = configFactory->get('taxonomy.settings');
   }
 
   /**
@@ -40,7 +39,8 @@ public function __construct(
   protected function buildNodeIndex(NodeInterface $node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
-    if (!$this->config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+    $config = $this->configFactory->get('taxonomy.settings');
+    if (!$config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
       return;
     }
 
@@ -84,7 +84,8 @@ protected function buildNodeIndex(NodeInterface $node): void {
    *   The node entity.
    */
   protected function deleteNodeIndex(NodeInterface $node): void {
-    if ($this->config->get('maintain_index_table')) {
+    $config = $this->configFactory->get('taxonomy.settings');
+    if ($config->get('maintain_index_table')) {
       $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
   }
@@ -166,7 +167,8 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    if ($this->config->get('maintain_index_table')) {
+    $config = $this->configFactory->get('taxonomy.settings');
+    if ($config->get('maintain_index_table')) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
-- 
GitLab


From 8a679153485c090b5f8a8254337da8fa76206c49 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 28 Feb 2025 10:45:40 -0500
Subject: [PATCH 27/53] Adding depency injection for ModuleHandler.

---
 core/modules/taxonomy/src/Hook/TaxonomyHelp.php | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHelp.php b/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
index 4fc29b3174dc..c63b6d99b4ba 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
@@ -2,26 +2,30 @@
 
 namespace Drupal\taxonomy\Hook;
 
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Url;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Hook\Attribute\Hook;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
- * Implements hook_help().
+ * Help hook implementation for taxonomy().
  */
-#[Hook('help')]
 class TaxonomyHelp {
 
   use StringTranslationTrait;
 
+  public function __construct(protected ModuleHandlerInterface $moduleHandler) {
+  }
+
   /**
    * Implements hook_help().
    */
-  public function __invoke($route_name, RouteMatchInterface $route_match): string {
+  #[Hook('help')]
+  public function help($route_name, RouteMatchInterface $route_match): string {
     switch ($route_name) {
       case 'help.page.taxonomy':
-        $field_ui_url = \Drupal::moduleHandler()->moduleExists('field_ui') ? Url::fromRoute('help.page', ['name' => 'field_ui'])->toString() : '#';
+        $field_ui_url = $this->moduleHandler->moduleExists('field_ui') ? Url::fromRoute('help.page', ['name' => 'field_ui'])->toString() : '#';
         $output = '';
         $output .= '<h2>' . $this->t('About') . '</h2>';
         $output .= '<p>' . $this->t('The Taxonomy module allows users who have permission to create and edit content to categorize (tag) content of that type. Users who have the <em>Administer vocabularies and terms</em> <a href=":permissions" title="Taxonomy module permissions">permission</a> can add <em>vocabularies</em> that contain a set of related <em>terms</em>. The terms in a vocabulary can either be pre-set by an administrator or built gradually as content is added and edited. Terms may be organized hierarchically if desired.', [
-- 
GitLab


From 04b2cd48474a2054f958103fa1fe03ad68046d60 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 28 Feb 2025 11:18:33 -0500
Subject: [PATCH 28/53] Setting config in the constructor.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 20 ++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index bc1ab56d995f..81dfa3d3e892 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -4,6 +4,7 @@
 
 use Drupal\taxonomy\Entity\Term;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ImmutableConfig;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Hook\Attribute\Hook;
 use Drupal\Core\Entity\EntityInterface;
@@ -20,11 +21,19 @@ class TaxonomyEntityHooks {
 
   use stringTranslationTrait;
 
+  /**
+   * The configuration settings of this module.
+   *
+   * @var \Drupal\Core\Config\ImmutableConfig
+   */
+  protected ImmutableConfig $config;
+
   public function __construct(
-    protected ConfigFactoryInterface $configFactory,
+    configFactoryInterface $config,
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
   ) {
+    $this->config = $config->get('taxonomy.settings');
   }
 
   /**
@@ -39,8 +48,7 @@ public function __construct(
   protected function buildNodeIndex(NodeInterface $node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
-    $config = $this->configFactory->get('taxonomy.settings');
-    if (!$config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+    if (!$this->config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
       return;
     }
 
@@ -84,8 +92,7 @@ protected function buildNodeIndex(NodeInterface $node): void {
    *   The node entity.
    */
   protected function deleteNodeIndex(NodeInterface $node): void {
-    $config = $this->configFactory->get('taxonomy.settings');
-    if ($config->get('maintain_index_table')) {
+    if ($this->config->get('maintain_index_table')) {
       $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
   }
@@ -167,8 +174,7 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    $config = $this->configFactory->get('taxonomy.settings');
-    if ($config->get('maintain_index_table')) {
+    if ($this->config->get('maintain_index_table')) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
-- 
GitLab


From bbacb9ccfe24daa3da823ed7c7f94a24758d3cfa Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 28 Feb 2025 16:08:42 -0500
Subject: [PATCH 29/53] Removing config from constructor, adding helper
 function.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 31 +++++++++++--------
 1 file changed, 18 insertions(+), 13 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 81dfa3d3e892..0a22219067c8 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -4,7 +4,6 @@
 
 use Drupal\taxonomy\Entity\Term;
 use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Config\ImmutableConfig;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Hook\Attribute\Hook;
 use Drupal\Core\Entity\EntityInterface;
@@ -21,19 +20,25 @@ class TaxonomyEntityHooks {
 
   use stringTranslationTrait;
 
-  /**
-   * The configuration settings of this module.
-   *
-   * @var \Drupal\Core\Config\ImmutableConfig
-   */
-  protected ImmutableConfig $config;
-
   public function __construct(
-    configFactoryInterface $config,
+    protected configFactoryInterface $config,
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
   ) {
-    $this->config = $config->get('taxonomy.settings');
+  }
+
+  /**
+   * Returns the module configuration object.
+   *
+   * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
+   *   The module configuration object.
+   */
+  protected function getConfig() {
+    if ($this->config === NULL) {
+      // Get module config.
+      $this->config = $this->config->get('taxonomy.settings');
+    }
+    return $this->config;
   }
 
   /**
@@ -48,7 +53,7 @@ public function __construct(
   protected function buildNodeIndex(NodeInterface $node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
-    if (!$this->config->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+    if (!$this->getConfig()->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
       return;
     }
 
@@ -92,7 +97,7 @@ protected function buildNodeIndex(NodeInterface $node): void {
    *   The node entity.
    */
   protected function deleteNodeIndex(NodeInterface $node): void {
-    if ($this->config->get('maintain_index_table')) {
+    if ($this->getConfig()->get('maintain_index_table')) {
       $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
   }
@@ -174,7 +179,7 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    if ($this->config->get('maintain_index_table')) {
+    if ($this->getConfig()->get('maintain_index_table')) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
-- 
GitLab


From 609958f1eb0d876a420391bc8821362450f577a7 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 20 Mar 2025 13:23:18 -0400
Subject: [PATCH 30/53] Fixing config-related pieces and use statement.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php       | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 0a22219067c8..86b52e563d5d 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -18,10 +18,10 @@
  */
 class TaxonomyEntityHooks {
 
-  use stringTranslationTrait;
+  use StringTranslationTrait;
 
   public function __construct(
-    protected configFactoryInterface $config,
+    protected ConfigFactoryInterface $configFactory,
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
   ) {
@@ -29,16 +29,13 @@ public function __construct(
 
   /**
    * Returns the module configuration object.
-   *
-   * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
-   *   The module configuration object.
    */
   protected function getConfig() {
-    if ($this->config === NULL) {
+    if ($this->configFactory === NULL) {
       // Get module config.
-      $this->config = $this->config->get('taxonomy.settings');
+      $this->configFactory = $this->configFactory->get('taxonomy.settings');
     }
-    return $this->config;
+    return $this->configFactory;
   }
 
   /**
-- 
GitLab


From 126ee214eec0b3eceb650dd02e58ef6ab51a692d Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 20 Mar 2025 13:44:54 -0400
Subject: [PATCH 31/53] Adding back docblock comment.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 86b52e563d5d..2cfc9d1170be 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -29,6 +29,9 @@ public function __construct(
 
   /**
    * Returns the module configuration object.
+   *
+   * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
+   *   The module configuration object.
    */
   protected function getConfig() {
     if ($this->configFactory === NULL) {
-- 
GitLab


From 7c594280a744dc50c838f8537de6bce8d6c486c2 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 20 Mar 2025 14:17:40 -0400
Subject: [PATCH 32/53] Updating TaxonomyHelpHooks and TaxonomyMenuHooks
 organiztion outlined in Meta issue.

---
 .../src/Hook/{TaxonomyHelp.php => TaxonomyHelpHooks.php}      | 2 +-
 .../src/Hook/{TaxonomyHooks.php => TaxonomyMenuHooks.php}     | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)
 rename core/modules/taxonomy/src/Hook/{TaxonomyHelp.php => TaxonomyHelpHooks.php} (99%)
 rename core/modules/taxonomy/src/Hook/{TaxonomyHooks.php => TaxonomyMenuHooks.php} (92%)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHelp.php b/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
similarity index 99%
rename from core/modules/taxonomy/src/Hook/TaxonomyHelp.php
rename to core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
index c63b6d99b4ba..a674256e5e4f 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHelp.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
@@ -11,7 +11,7 @@
 /**
  * Help hook implementation for taxonomy().
  */
-class TaxonomyHelp {
+class TaxonomyHelpHooks {
 
   use StringTranslationTrait;
 
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php
similarity index 92%
rename from core/modules/taxonomy/src/Hook/TaxonomyHooks.php
rename to core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php
index be0484965937..a5f457e76dbc 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php
@@ -5,9 +5,9 @@
 use Drupal\Core\Hook\Attribute\Hook;
 
 /**
- * Hook implementations for taxonomy.
+ * Menu hook implementations for taxonomy.
  */
-class TaxonomyHooks {
+class TaxonomyMenuHooks {
 
   /**
    * Implements hook_local_tasks_alter().
-- 
GitLab


From e784e2606fbdbf0f74655bcedcf266ef288dbb5b Mon Sep 17 00:00:00 2001
From: Mike McGovern <26519-mcgovernm@users.noreply.drupalcode.org>
Date: Thu, 20 Mar 2025 19:16:26 +0000
Subject: [PATCH 33/53] Apply 2 suggestion(s) to 2 file(s)

Co-authored-by: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
---
 core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php  | 3 +--
 core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php | 6 +++++-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
index a674256e5e4f..9daa7908d379 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
@@ -15,8 +15,7 @@ class TaxonomyHelpHooks {
 
   use StringTranslationTrait;
 
-  public function __construct(protected ModuleHandlerInterface $moduleHandler) {
-  }
+  public function __construct(protected ModuleHandlerInterface $moduleHandler) {}
 
   /**
    * Implements hook_help().
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
index ead2f34f2b4a..a9b024b5f48e 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
@@ -14,7 +14,11 @@ class TaxonomyThemeHooks {
    */
   #[Hook('theme')]
   public function taxonomyTheme($existing, $type, $theme, $path): array {
-    return ['taxonomy_term' => ['render element' => 'elements']];
+    return [
+      'taxonomy_term' => [
+        'render element' => 'elements',
+      ],
+    ];
   }
 
   /**
-- 
GitLab


From ce9132e79bfceaf008508a9700be636573f8544e Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 09:00:21 -0400
Subject: [PATCH 34/53] Replacing getconfig() with shouldMaintainIndexTable()
 and cleaning up implementation.

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 20 +++++++------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 2cfc9d1170be..cadb741008f9 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -28,17 +28,11 @@ public function __construct(
   }
 
   /**
-   * Returns the module configuration object.
-   *
-   * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
-   *   The module configuration object.
+   * Returns the maintain_index_table configuration value.
    */
-  protected function getConfig() {
-    if ($this->configFactory === NULL) {
-      // Get module config.
-      $this->configFactory = $this->configFactory->get('taxonomy.settings');
-    }
-    return $this->configFactory;
+  protected function shouldMaintainIndexTable(): boolean {
+    $taxonomy_config = $this->configFactory->get('taxonomy.settings');
+    return $taxonomy_config->get('maintain_index_table');
   }
 
   /**
@@ -53,7 +47,7 @@ protected function getConfig() {
   protected function buildNodeIndex(NodeInterface $node): void {
     // We maintain a denormalized table of term/node relationships, containing
     // only data for current, published nodes.
-    if (!$this->getConfig()->get('maintain_index_table') || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+    if (!$this->shouldMaintainIndexTable() || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
       return;
     }
 
@@ -97,7 +91,7 @@ protected function buildNodeIndex(NodeInterface $node): void {
    *   The node entity.
    */
   protected function deleteNodeIndex(NodeInterface $node): void {
-    if ($this->getConfig()->get('maintain_index_table')) {
+    if ($this->shouldMaintainIndexTable()) {
       $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
     }
   }
@@ -179,7 +173,7 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    if ($this->getConfig()->get('maintain_index_table')) {
+    if ($this->shouldMaintainIndexTable()) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
-- 
GitLab


From 0132c4e1c9816d5adc87413e2109192855ccccb0 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 09:04:53 -0400
Subject: [PATCH 35/53] Fixing return type.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index cadb741008f9..da47af9cae2d 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -30,7 +30,7 @@ public function __construct(
   /**
    * Returns the maintain_index_table configuration value.
    */
-  protected function shouldMaintainIndexTable(): boolean {
+  protected function shouldMaintainIndexTable(): bool {
     $taxonomy_config = $this->configFactory->get('taxonomy.settings');
     return $taxonomy_config->get('maintain_index_table');
   }
-- 
GitLab


From 03b60ecac8b520cc01eda64eb001d6f486574b37 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 11:19:20 -0400
Subject: [PATCH 36/53] Fixing return on shouldMaintainIndexTable().

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index da47af9cae2d..ea29e967357c 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -32,6 +32,9 @@ public function __construct(
    */
   protected function shouldMaintainIndexTable(): bool {
     $taxonomy_config = $this->configFactory->get('taxonomy.settings');
+    if($taxonomy_config->get('maintain_index_table') == NULL){
+      return FALSE;
+    }
     return $taxonomy_config->get('maintain_index_table');
   }
 
-- 
GitLab


From b06ec6199c98a15614427756e6f8dbcf70544542 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 11:23:08 -0400
Subject: [PATCH 37/53] Fixing phpcs errors.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index ea29e967357c..41d15f257b20 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -32,7 +32,7 @@ public function __construct(
    */
   protected function shouldMaintainIndexTable(): bool {
     $taxonomy_config = $this->configFactory->get('taxonomy.settings');
-    if($taxonomy_config->get('maintain_index_table') == NULL){
+    if ($taxonomy_config->get('maintain_index_table') == NULL) {
       return FALSE;
     }
     return $taxonomy_config->get('maintain_index_table');
-- 
GitLab


From 7f20ef56acb0bd656960f52736851c156a4f6d87 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 11:39:35 -0400
Subject: [PATCH 38/53] Removing taxonomy_build_node_index and
 taxonomy_delete_node_index from taxonomy.module.

---
 core/modules/taxonomy/taxonomy.module | 68 ---------------------------
 1 file changed, 68 deletions(-)

diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index c6512d623112..2496048588af 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -4,8 +4,6 @@
  * @file
  */
 
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Render\Element;
 use Drupal\taxonomy\Entity\Term;
 
@@ -73,69 +71,3 @@ function taxonomy_term_is_page(Term $term) {
   }
   return FALSE;
 }
-
-/**
- * Builds and inserts taxonomy index entries for a given node.
- *
- * The index lists all terms that are related to a given node entity, and is
- * therefore maintained at the entity level.
- *
- * @param \Drupal\node\NodeInterface $node
- *   The node entity.
- */
-function taxonomy_build_node_index($node) {
-  // We maintain a denormalized table of term/node relationships, containing
-  // only data for current, published nodes.
-  if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityTypeManager()->getStorage('node') instanceof SqlContentEntityStorage)) {
-    return;
-  }
-
-  $status = $node->isPublished();
-  $sticky = (int) $node->isSticky();
-  // We only maintain the taxonomy index for published nodes.
-  if ($status && $node->isDefaultRevision()) {
-    // Collect a unique list of all the term IDs from all node fields.
-    $tid_all = [];
-    $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
-    foreach ($node->getFieldDefinitions() as $field) {
-      $field_name = $field->getName();
-      $class = $field->getItemDefinition()->getClass();
-      $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
-      if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
-        foreach ($node->getTranslationLanguages() as $language) {
-          foreach ($node->getTranslation($language->getId())->$field_name as $item) {
-            if (!$item->isEmpty()) {
-              $tid_all[$item->target_id] = $item->target_id;
-            }
-          }
-        }
-      }
-    }
-    // Insert index entries for all the node's terms.
-    if (!empty($tid_all)) {
-      $connection = \Drupal::database();
-      foreach ($tid_all as $tid) {
-        $connection->merge('taxonomy_index')
-          ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
-          ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
-          ->execute();
-      }
-    }
-  }
-}
-
-/**
- * Deletes taxonomy index entries for a given node.
- *
- * @param \Drupal\Core\Entity\EntityInterface $node
- *   The node entity.
- */
-function taxonomy_delete_node_index(EntityInterface $node) {
-  if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
-    \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
-  }
-}
-
-/**
- * @} End of "defgroup taxonomy_index".
- */
-- 
GitLab


From 7b351458299448ba69f8c6c15303ec4393e8db0e Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 11:59:58 -0400
Subject: [PATCH 39/53] Revert "Removing taxonomy_build_node_index and
 taxonomy_delete_node_index from taxonomy.module."

This reverts commit 7f20ef56acb0bd656960f52736851c156a4f6d87.
---
 core/modules/taxonomy/taxonomy.module | 68 +++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 2496048588af..c6512d623112 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -4,6 +4,8 @@
  * @file
  */
 
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Render\Element;
 use Drupal\taxonomy\Entity\Term;
 
@@ -71,3 +73,69 @@ function taxonomy_term_is_page(Term $term) {
   }
   return FALSE;
 }
+
+/**
+ * Builds and inserts taxonomy index entries for a given node.
+ *
+ * The index lists all terms that are related to a given node entity, and is
+ * therefore maintained at the entity level.
+ *
+ * @param \Drupal\node\NodeInterface $node
+ *   The node entity.
+ */
+function taxonomy_build_node_index($node) {
+  // We maintain a denormalized table of term/node relationships, containing
+  // only data for current, published nodes.
+  if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityTypeManager()->getStorage('node') instanceof SqlContentEntityStorage)) {
+    return;
+  }
+
+  $status = $node->isPublished();
+  $sticky = (int) $node->isSticky();
+  // We only maintain the taxonomy index for published nodes.
+  if ($status && $node->isDefaultRevision()) {
+    // Collect a unique list of all the term IDs from all node fields.
+    $tid_all = [];
+    $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+    foreach ($node->getFieldDefinitions() as $field) {
+      $field_name = $field->getName();
+      $class = $field->getItemDefinition()->getClass();
+      $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
+      if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
+        foreach ($node->getTranslationLanguages() as $language) {
+          foreach ($node->getTranslation($language->getId())->$field_name as $item) {
+            if (!$item->isEmpty()) {
+              $tid_all[$item->target_id] = $item->target_id;
+            }
+          }
+        }
+      }
+    }
+    // Insert index entries for all the node's terms.
+    if (!empty($tid_all)) {
+      $connection = \Drupal::database();
+      foreach ($tid_all as $tid) {
+        $connection->merge('taxonomy_index')
+          ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
+          ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
+          ->execute();
+      }
+    }
+  }
+}
+
+/**
+ * Deletes taxonomy index entries for a given node.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $node
+ *   The node entity.
+ */
+function taxonomy_delete_node_index(EntityInterface $node) {
+  if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+    \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+  }
+}
+
+/**
+ * @} End of "defgroup taxonomy_index".
+ */
-- 
GitLab


From 7512ff7bef7aa791b015183267d19f0d2a010d44 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 15:06:01 -0400
Subject: [PATCH 40/53] Fixing logic in shouldMaintainIndexTable.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 41d15f257b20..b8b103f4200c 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -32,10 +32,8 @@ public function __construct(
    */
   protected function shouldMaintainIndexTable(): bool {
     $taxonomy_config = $this->configFactory->get('taxonomy.settings');
-    if ($taxonomy_config->get('maintain_index_table') == NULL) {
-      return FALSE;
-    }
-    return $taxonomy_config->get('maintain_index_table');
+    $maintain_index_table = $taxonomy_config->get('maintain_index_table');
+    return $maintain_index_table;
   }
 
   /**
-- 
GitLab


From 363bd8099cc740692824ec5a947ee2eee3e47d78 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 16:03:07 -0400
Subject: [PATCH 41/53] Adding return type to comment.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index b8b103f4200c..283223e970cc 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -29,6 +29,9 @@ public function __construct(
 
   /**
    * Returns the maintain_index_table configuration value.
+   * 
+   * @return bool
+   *   Whether or not the index table should be maintained.
    */
   protected function shouldMaintainIndexTable(): bool {
     $taxonomy_config = $this->configFactory->get('taxonomy.settings');
-- 
GitLab


From 0e83e6cdbf1772922f1f0637a6b689320f03024b Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 16:06:43 -0400
Subject: [PATCH 42/53] Fixing phpcs error.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 283223e970cc..5ed995bb0174 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -29,7 +29,7 @@ public function __construct(
 
   /**
    * Returns the maintain_index_table configuration value.
-   * 
+   *
    * @return bool
    *   Whether or not the index table should be maintained.
    */
-- 
GitLab


From f90f2474b40463c4fc345605a4aa8a8faf90a746 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 16:53:06 -0400
Subject: [PATCH 43/53] Casting return value as bool.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 5ed995bb0174..834fa6cdfa49 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -30,13 +30,11 @@ public function __construct(
   /**
    * Returns the maintain_index_table configuration value.
    *
-   * @return bool
-   *   Whether or not the index table should be maintained.
    */
   protected function shouldMaintainIndexTable(): bool {
     $taxonomy_config = $this->configFactory->get('taxonomy.settings');
     $maintain_index_table = $taxonomy_config->get('maintain_index_table');
-    return $maintain_index_table;
+    return (bool) $maintain_index_table;
   }
 
   /**
-- 
GitLab


From f25a3f10cc1ee58a55ce1bca48681242c78bf8ba Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 21 Mar 2025 16:57:02 -0400
Subject: [PATCH 44/53] Fixing phpcs error.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 1 -
 1 file changed, 1 deletion(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 834fa6cdfa49..8a45a6ea411e 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -29,7 +29,6 @@ public function __construct(
 
   /**
    * Returns the maintain_index_table configuration value.
-   *
    */
   protected function shouldMaintainIndexTable(): bool {
     $taxonomy_config = $this->configFactory->get('taxonomy.settings');
-- 
GitLab


From 77ada68d7bae59017ac5033d038a9f24f4c40545 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Wed, 26 Mar 2025 11:23:54 -0400
Subject: [PATCH 45/53] Moving node index functionality to a service and
 deprecating taxonomy_build_node_index() and taxonomy_delete_node_index().

---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php |  82 +-----------
 core/modules/taxonomy/src/NodeIndex.php       | 123 ++++++++++++++++++
 core/modules/taxonomy/taxonomy.module         |  54 ++------
 core/modules/taxonomy/taxonomy.services.yml   |   5 +
 4 files changed, 145 insertions(+), 119 deletions(-)
 create mode 100644 core/modules/taxonomy/src/NodeIndex.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 8a45a6ea411e..27e5371b7a29 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -8,8 +8,6 @@
 use Drupal\Core\Hook\Attribute\Hook;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
-use Drupal\node\NodeInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
 
@@ -27,76 +25,6 @@ public function __construct(
   ) {
   }
 
-  /**
-   * Returns the maintain_index_table configuration value.
-   */
-  protected function shouldMaintainIndexTable(): bool {
-    $taxonomy_config = $this->configFactory->get('taxonomy.settings');
-    $maintain_index_table = $taxonomy_config->get('maintain_index_table');
-    return (bool) $maintain_index_table;
-  }
-
-  /**
-   * Builds and inserts taxonomy index entries for a given node.
-   *
-   * The index lists all terms that are related to a given node entity, and is
-   * therefore maintained at the entity level.
-   *
-   * @param \Drupal\node\NodeInterface $node
-   *   The node entity.
-   */
-  protected function buildNodeIndex(NodeInterface $node): void {
-    // We maintain a denormalized table of term/node relationships, containing
-    // only data for current, published nodes.
-    if (!$this->shouldMaintainIndexTable() || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
-      return;
-    }
-
-    $status = $node->isPublished();
-    $sticky = (int) $node->isSticky();
-    // We only maintain the taxonomy index for published nodes.
-    if ($status && $node->isDefaultRevision()) {
-      // Collect a unique list of all the term IDs from all node fields.
-      $tid_all = [];
-      $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
-      foreach ($node->getFieldDefinitions() as $field) {
-        $field_name = $field->getName();
-        $class = $field->getItemDefinition()->getClass();
-        $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
-        if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
-          foreach ($node->getTranslationLanguages() as $language) {
-            foreach ($node->getTranslation($language->getId())->$field_name as $item) {
-              if (!$item->isEmpty()) {
-                $tid_all[$item->target_id] = $item->target_id;
-              }
-            }
-          }
-        }
-      }
-      // Insert index entries for all the node's terms.
-      if (!empty($tid_all)) {
-        foreach ($tid_all as $tid) {
-          $this->database->merge('taxonomy_index')
-            ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
-            ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
-            ->execute();
-        }
-      }
-    }
-  }
-
-  /**
-   * Deletes taxonomy index entries for a given node.
-   *
-   * @param \Drupal\node\NodeInterface $node
-   *   The node entity.
-   */
-  protected function deleteNodeIndex(NodeInterface $node): void {
-    if ($this->shouldMaintainIndexTable()) {
-      $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
-    }
-  }
-
   /**
    * Implements hook_entity_operation().
    */
@@ -143,7 +71,7 @@ public function entityOperation(EntityInterface $term): array {
   #[Hook('node_insert')]
   public function nodeInsert(EntityInterface $node): void {
     // Add taxonomy index entries for the node.
-    $this->buildNodeIndex($node);
+    \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
   }
 
   /**
@@ -156,8 +84,8 @@ public function nodeUpdate(EntityInterface $node): void {
     if (!$node->isDefaultRevision()) {
       return;
     }
-    $this->deleteNodeIndex($node);
-    $this->buildNodeIndex($node);
+    \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node);
+    \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
   }
 
   /**
@@ -166,7 +94,7 @@ public function nodeUpdate(EntityInterface $node): void {
   #[Hook('node_predelete')]
   public function nodePredelete(EntityInterface $node): void {
     // Clean up the {taxonomy_index} table when nodes are deleted.
-    $this->deleteNodeIndex($node);
+    \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node);
   }
 
   /**
@@ -174,7 +102,7 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    if ($this->shouldMaintainIndexTable()) {
+    if (\Drupal::service('taxonomy.node_index')->shouldMaintainIndexTable()) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
diff --git a/core/modules/taxonomy/src/NodeIndex.php b/core/modules/taxonomy/src/NodeIndex.php
new file mode 100644
index 000000000000..340cef51c9b2
--- /dev/null
+++ b/core/modules/taxonomy/src/NodeIndex.php
@@ -0,0 +1,123 @@
+<?php
+
+namespace Drupal\taxonomy;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\node\NodeInterface;
+
+/**
+ * Defines a Controller class for maintaining the taxonomy node index.
+ */
+class NodeIndex {
+
+  /**
+   * The database connection.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * The config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs the NodeIndex.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   * @param \Drupal\Core\Database\Connection $database
+   *   The database connection.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(ConfigFactoryInterface $config_factory, Connection $database, EntityTypeManagerInterface $entity_type_manager) {
+    $this->configFactory = $config_factory;
+    $this->database = $database;
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * Returns the maintain_index_table configuration value.
+   */
+  public function shouldMaintainIndexTable(): bool {
+    $taxonomy_config = $this->configFactory->get('taxonomy.settings');
+    $maintain_index_table = $taxonomy_config->get('maintain_index_table');
+    return (bool) $maintain_index_table;
+  }
+
+  /**
+   * Builds and inserts taxonomy index entries for a given node.
+   *
+   * The index lists all terms that are related to a given node entity, and is
+   * therefore maintained at the entity level.
+   *
+   * @param \Drupal\node\NodeInterface $node
+   *   The node entity.
+   */
+  public function buildNodeIndex(NodeInterface $node): void {
+    // We maintain a denormalized table of term/node relationships, containing
+    // only data for current, published nodes.
+    if (!$this->shouldMaintainIndexTable() || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+      return;
+    }
+
+    $status = $node->isPublished();
+    $sticky = (int) $node->isSticky();
+    // We only maintain the taxonomy index for published nodes.
+    if ($status && $node->isDefaultRevision()) {
+      // Collect a unique list of all the term IDs from all node fields.
+      $tid_all = [];
+      $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+      foreach ($node->getFieldDefinitions() as $field) {
+        $field_name = $field->getName();
+        $class = $field->getItemDefinition()->getClass();
+        $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
+        if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
+          foreach ($node->getTranslationLanguages() as $language) {
+            foreach ($node->getTranslation($language->getId())->$field_name as $item) {
+              if (!$item->isEmpty()) {
+                $tid_all[$item->target_id] = $item->target_id;
+              }
+            }
+          }
+        }
+      }
+      // Insert index entries for all the node's terms.
+      if (!empty($tid_all)) {
+        foreach ($tid_all as $tid) {
+          $this->database->merge('taxonomy_index')
+            ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
+            ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
+            ->execute();
+        }
+      }
+    }
+  }
+
+  /**
+   * Deletes taxonomy index entries for a given node.
+   *
+   * @param \Drupal\node\NodeInterface $node
+   *   The node entity.
+   */
+  public function deleteNodeIndex(NodeInterface $node): void {
+    if ($this->shouldMaintainIndexTable()) {
+      $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+    }
+  }
+
+}
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index c6512d623112..adb088a99c5f 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -5,7 +5,6 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Render\Element;
 use Drupal\taxonomy\Entity\Term;
 
@@ -82,46 +81,14 @@ function taxonomy_term_is_page(Term $term) {
  *
  * @param \Drupal\node\NodeInterface $node
  *   The node entity.
+ *
+ * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
+ * \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
+ * @see https://www.drupal.org/node/3515362
  */
 function taxonomy_build_node_index($node) {
-  // We maintain a denormalized table of term/node relationships, containing
-  // only data for current, published nodes.
-  if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityTypeManager()->getStorage('node') instanceof SqlContentEntityStorage)) {
-    return;
-  }
-
-  $status = $node->isPublished();
-  $sticky = (int) $node->isSticky();
-  // We only maintain the taxonomy index for published nodes.
-  if ($status && $node->isDefaultRevision()) {
-    // Collect a unique list of all the term IDs from all node fields.
-    $tid_all = [];
-    $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
-    foreach ($node->getFieldDefinitions() as $field) {
-      $field_name = $field->getName();
-      $class = $field->getItemDefinition()->getClass();
-      $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
-      if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
-        foreach ($node->getTranslationLanguages() as $language) {
-          foreach ($node->getTranslation($language->getId())->$field_name as $item) {
-            if (!$item->isEmpty()) {
-              $tid_all[$item->target_id] = $item->target_id;
-            }
-          }
-        }
-      }
-    }
-    // Insert index entries for all the node's terms.
-    if (!empty($tid_all)) {
-      $connection = \Drupal::database();
-      foreach ($tid_all as $tid) {
-        $connection->merge('taxonomy_index')
-          ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
-          ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
-          ->execute();
-      }
-    }
-  }
+  @trigger_error('taxonomy_build_node_index() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::service(\'taxonomy.node_index\')->buildNodeIndex($node). See https://www.drupal.org/node/3515362', E_USER_DEPRECATED);
+  \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
 }
 
 /**
@@ -129,11 +96,14 @@ function taxonomy_build_node_index($node) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity.
+ *
+ * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
+ * \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node) instead.
+ * @see https://www.drupal.org/node/3515362
  */
 function taxonomy_delete_node_index(EntityInterface $node) {
-  if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
-    \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
-  }
+  @trigger_error('taxonomy_delete_node_index() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::service(\'taxonomy.node_index\')->deleteNodeIndex($node). See https://www.drupal.org/node/3515362', E_USER_DEPRECATED);
+  \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node);
 }
 
 /**
diff --git a/core/modules/taxonomy/taxonomy.services.yml b/core/modules/taxonomy/taxonomy.services.yml
index 91a333ec9773..97f513fa2f5b 100644
--- a/core/modules/taxonomy/taxonomy.services.yml
+++ b/core/modules/taxonomy/taxonomy.services.yml
@@ -11,3 +11,8 @@ services:
     arguments: ['@current_route_match']
     tags:
       - { name: 'context_provider' }
+  taxonomy.node_index:
+    class: Drupal\taxonomy\NodeIndex
+    arguments: ['@config.factory', '@database', '@entity_type.manager']
+    tags:
+      - { name: 'node_index'}
-- 
GitLab


From 1f9742072eafa1d470db8cb8de29899f8e67acdf Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Wed, 26 Mar 2025 11:55:38 -0400
Subject: [PATCH 46/53] Adding alias for taxonomy.node_index service.

---
 core/modules/taxonomy/taxonomy.services.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/core/modules/taxonomy/taxonomy.services.yml b/core/modules/taxonomy/taxonomy.services.yml
index 97f513fa2f5b..2a5fa8fba95d 100644
--- a/core/modules/taxonomy/taxonomy.services.yml
+++ b/core/modules/taxonomy/taxonomy.services.yml
@@ -16,3 +16,4 @@ services:
     arguments: ['@config.factory', '@database', '@entity_type.manager']
     tags:
       - { name: 'node_index'}
+  Drupal\taxonomy\NodeIndex: '@taxonomy.node_index'
-- 
GitLab


From 38b1ddfb5ee1f011b00abc334d813ab6eddb006b Mon Sep 17 00:00:00 2001
From: Mike McGovern <26519-mcgovernm@users.noreply.drupalcode.org>
Date: Thu, 27 Mar 2025 12:09:34 +0000
Subject: [PATCH 47/53] Apply 6 suggestion(s) to 2 file(s)

Co-authored-by: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 15 +++----
 core/modules/taxonomy/src/NodeIndex.php       | 40 ++-----------------
 2 files changed, 12 insertions(+), 43 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 27e5371b7a29..4f7b4b416476 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -3,6 +3,7 @@
 namespace Drupal\taxonomy\Hook;
 
 use Drupal\taxonomy\Entity\Term;
+use Drupal\taxonomy\NodeIndex;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Hook\Attribute\Hook;
@@ -22,8 +23,8 @@ public function __construct(
     protected ConfigFactoryInterface $configFactory,
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
-  ) {
-  }
+    protected NodeIndex $nodeIndex,
+  ) {}
 
   /**
    * Implements hook_entity_operation().
@@ -71,7 +72,7 @@ public function entityOperation(EntityInterface $term): array {
   #[Hook('node_insert')]
   public function nodeInsert(EntityInterface $node): void {
     // Add taxonomy index entries for the node.
-    \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
+    $this->nodeIndex->buildNodeIndex($node);
   }
 
   /**
@@ -84,8 +85,8 @@ public function nodeUpdate(EntityInterface $node): void {
     if (!$node->isDefaultRevision()) {
       return;
     }
-    \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node);
-    \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
+    $this->nodeIndex->deleteNodeIndex($node);
+    $this->nodeIndex->buildNodeIndex($node);
   }
 
   /**
@@ -94,7 +95,7 @@ public function nodeUpdate(EntityInterface $node): void {
   #[Hook('node_predelete')]
   public function nodePredelete(EntityInterface $node): void {
     // Clean up the {taxonomy_index} table when nodes are deleted.
-    \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node);
+    $this->nodeIndex->deleteNodeIndex($node);
   }
 
   /**
@@ -102,7 +103,7 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    if (\Drupal::service('taxonomy.node_index')->shouldMaintainIndexTable()) {
+    if ($this->nodeIndex->shouldMaintainIndexTable()) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
diff --git a/core/modules/taxonomy/src/NodeIndex.php b/core/modules/taxonomy/src/NodeIndex.php
index 340cef51c9b2..21e57d08c1be 100644
--- a/core/modules/taxonomy/src/NodeIndex.php
+++ b/core/modules/taxonomy/src/NodeIndex.php
@@ -13,42 +13,10 @@
  */
 class NodeIndex {
 
-  /**
-   * The database connection.
-   *
-   * @var \Drupal\Core\Database\Connection
-   */
-  protected $database;
-
-  /**
-   * The config factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * Constructs the NodeIndex.
-   *
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   The config factory.
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity type manager.
-   */
-  public function __construct(ConfigFactoryInterface $config_factory, Connection $database, EntityTypeManagerInterface $entity_type_manager) {
-    $this->configFactory = $config_factory;
-    $this->database = $database;
-    $this->entityTypeManager = $entity_type_manager;
-  }
+  public function __construct(
+    protected readonly ConfigFactoryInterface $configFactory,
+    protected readonly Connection $database,
+    protected readonly EntityTypeManagerInterface $entityTypeManager) {}
 
   /**
    * Returns the maintain_index_table configuration value.
-- 
GitLab


From eef4ba29e40a26d0db09110233366acfacbc5203 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 27 Mar 2025 08:18:47 -0400
Subject: [PATCH 48/53] Fixing PHPCS error.

---
 core/modules/taxonomy/src/NodeIndex.php | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/core/modules/taxonomy/src/NodeIndex.php b/core/modules/taxonomy/src/NodeIndex.php
index 21e57d08c1be..6627c677a173 100644
--- a/core/modules/taxonomy/src/NodeIndex.php
+++ b/core/modules/taxonomy/src/NodeIndex.php
@@ -16,7 +16,8 @@ class NodeIndex {
   public function __construct(
     protected readonly ConfigFactoryInterface $configFactory,
     protected readonly Connection $database,
-    protected readonly EntityTypeManagerInterface $entityTypeManager) {}
+    protected readonly EntityTypeManagerInterface $entityTypeManager,
+  ) {}
 
   /**
    * Returns the maintain_index_table configuration value.
-- 
GitLab


From 13b5437bdac9333f2a9fd7675f23c4c28ef05902 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Thu, 27 Mar 2025 10:17:56 -0400
Subject: [PATCH 49/53] Revert "Moving node index functionality to a service
 and deprecating taxonomy_build_node_index() and
 taxonomy_delete_node_index()."

This reverts commit 77ada68d7bae59017ac5033d038a9f24f4c40545.
---
 .../taxonomy/src/Hook/TaxonomyEntityHooks.php | 84 +++++++++++++++--
 core/modules/taxonomy/src/NodeIndex.php       | 92 -------------------
 core/modules/taxonomy/taxonomy.module         | 56 ++++++++---
 core/modules/taxonomy/taxonomy.services.yml   |  6 --
 4 files changed, 121 insertions(+), 117 deletions(-)
 delete mode 100644 core/modules/taxonomy/src/NodeIndex.php

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 4f7b4b416476..b41b01315dc8 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -3,12 +3,13 @@
 namespace Drupal\taxonomy\Hook;
 
 use Drupal\taxonomy\Entity\Term;
-use Drupal\taxonomy\NodeIndex;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Hook\Attribute\Hook;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\node\NodeInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
 
@@ -23,9 +24,78 @@ public function __construct(
     protected ConfigFactoryInterface $configFactory,
     protected Connection $database,
     protected EntityTypeManagerInterface $entityTypeManager,
-    protected NodeIndex $nodeIndex,
   ) {}
 
+  /**
+   * Returns the maintain_index_table configuration value.
+   */
+  protected function shouldMaintainIndexTable(): bool {
+    $taxonomy_config = $this->configFactory->get('taxonomy.settings');
+    $maintain_index_table = $taxonomy_config->get('maintain_index_table');
+    return (bool) $maintain_index_table;
+  }
+
+  /**
+   * Builds and inserts taxonomy index entries for a given node.
+   *
+   * The index lists all terms that are related to a given node entity, and is
+   * therefore maintained at the entity level.
+   *
+   * @param \Drupal\node\NodeInterface $node
+   *   The node entity.
+   */
+  protected function buildNodeIndex(NodeInterface $node): void {
+    // We maintain a denormalized table of term/node relationships, containing
+    // only data for current, published nodes.
+    if (!$this->shouldMaintainIndexTable() || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
+      return;
+    }
+
+    $status = $node->isPublished();
+    $sticky = (int) $node->isSticky();
+    // We only maintain the taxonomy index for published nodes.
+    if ($status && $node->isDefaultRevision()) {
+      // Collect a unique list of all the term IDs from all node fields.
+      $tid_all = [];
+      $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+      foreach ($node->getFieldDefinitions() as $field) {
+        $field_name = $field->getName();
+        $class = $field->getItemDefinition()->getClass();
+        $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
+        if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
+          foreach ($node->getTranslationLanguages() as $language) {
+            foreach ($node->getTranslation($language->getId())->$field_name as $item) {
+              if (!$item->isEmpty()) {
+                $tid_all[$item->target_id] = $item->target_id;
+              }
+            }
+          }
+        }
+      }
+      // Insert index entries for all the node's terms.
+      if (!empty($tid_all)) {
+        foreach ($tid_all as $tid) {
+          $this->database->merge('taxonomy_index')
+            ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
+            ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
+            ->execute();
+        }
+      }
+    }
+  }
+
+  /**
+   * Deletes taxonomy index entries for a given node.
+   *
+   * @param \Drupal\node\NodeInterface $node
+   *   The node entity.
+   */
+  protected function deleteNodeIndex(NodeInterface $node): void {
+    if ($this->shouldMaintainIndexTable()) {
+      $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+    }
+  }
+
   /**
    * Implements hook_entity_operation().
    */
@@ -72,7 +142,7 @@ public function entityOperation(EntityInterface $term): array {
   #[Hook('node_insert')]
   public function nodeInsert(EntityInterface $node): void {
     // Add taxonomy index entries for the node.
-    $this->nodeIndex->buildNodeIndex($node);
+    $this->buildNodeIndex($node);
   }
 
   /**
@@ -85,8 +155,8 @@ public function nodeUpdate(EntityInterface $node): void {
     if (!$node->isDefaultRevision()) {
       return;
     }
-    $this->nodeIndex->deleteNodeIndex($node);
-    $this->nodeIndex->buildNodeIndex($node);
+    $this->deleteNodeIndex($node);
+    $this->buildNodeIndex($node);
   }
 
   /**
@@ -95,7 +165,7 @@ public function nodeUpdate(EntityInterface $node): void {
   #[Hook('node_predelete')]
   public function nodePredelete(EntityInterface $node): void {
     // Clean up the {taxonomy_index} table when nodes are deleted.
-    $this->nodeIndex->deleteNodeIndex($node);
+    $this->deleteNodeIndex($node);
   }
 
   /**
@@ -103,7 +173,7 @@ public function nodePredelete(EntityInterface $node): void {
    */
   #[Hook('taxonomy_term_delete')]
   public function taxonomyTermDelete(Term $term): void {
-    if ($this->nodeIndex->shouldMaintainIndexTable()) {
+    if ($this->shouldMaintainIndexTable()) {
       // Clean up the {taxonomy_index} table when terms are deleted.
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
diff --git a/core/modules/taxonomy/src/NodeIndex.php b/core/modules/taxonomy/src/NodeIndex.php
deleted file mode 100644
index 6627c677a173..000000000000
--- a/core/modules/taxonomy/src/NodeIndex.php
+++ /dev/null
@@ -1,92 +0,0 @@
-<?php
-
-namespace Drupal\taxonomy;
-
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
-use Drupal\node\NodeInterface;
-
-/**
- * Defines a Controller class for maintaining the taxonomy node index.
- */
-class NodeIndex {
-
-  public function __construct(
-    protected readonly ConfigFactoryInterface $configFactory,
-    protected readonly Connection $database,
-    protected readonly EntityTypeManagerInterface $entityTypeManager,
-  ) {}
-
-  /**
-   * Returns the maintain_index_table configuration value.
-   */
-  public function shouldMaintainIndexTable(): bool {
-    $taxonomy_config = $this->configFactory->get('taxonomy.settings');
-    $maintain_index_table = $taxonomy_config->get('maintain_index_table');
-    return (bool) $maintain_index_table;
-  }
-
-  /**
-   * Builds and inserts taxonomy index entries for a given node.
-   *
-   * The index lists all terms that are related to a given node entity, and is
-   * therefore maintained at the entity level.
-   *
-   * @param \Drupal\node\NodeInterface $node
-   *   The node entity.
-   */
-  public function buildNodeIndex(NodeInterface $node): void {
-    // We maintain a denormalized table of term/node relationships, containing
-    // only data for current, published nodes.
-    if (!$this->shouldMaintainIndexTable() || !($this->entityTypeManager->getStorage('node') instanceof SqlContentEntityStorage)) {
-      return;
-    }
-
-    $status = $node->isPublished();
-    $sticky = (int) $node->isSticky();
-    // We only maintain the taxonomy index for published nodes.
-    if ($status && $node->isDefaultRevision()) {
-      // Collect a unique list of all the term IDs from all node fields.
-      $tid_all = [];
-      $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
-      foreach ($node->getFieldDefinitions() as $field) {
-        $field_name = $field->getName();
-        $class = $field->getItemDefinition()->getClass();
-        $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
-        if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
-          foreach ($node->getTranslationLanguages() as $language) {
-            foreach ($node->getTranslation($language->getId())->$field_name as $item) {
-              if (!$item->isEmpty()) {
-                $tid_all[$item->target_id] = $item->target_id;
-              }
-            }
-          }
-        }
-      }
-      // Insert index entries for all the node's terms.
-      if (!empty($tid_all)) {
-        foreach ($tid_all as $tid) {
-          $this->database->merge('taxonomy_index')
-            ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
-            ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
-            ->execute();
-        }
-      }
-    }
-  }
-
-  /**
-   * Deletes taxonomy index entries for a given node.
-   *
-   * @param \Drupal\node\NodeInterface $node
-   *   The node entity.
-   */
-  public function deleteNodeIndex(NodeInterface $node): void {
-    if ($this->shouldMaintainIndexTable()) {
-      $this->database->delete('taxonomy_index')->condition('nid', $node->id())->execute();
-    }
-  }
-
-}
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 1bd7194c97b2..c01e428cc1e9 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -5,6 +5,7 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Render\Element;
 use Drupal\taxonomy\Entity\Term;
 
@@ -81,14 +82,47 @@ function taxonomy_term_is_page(Term $term) {
  *
  * @param \Drupal\node\NodeInterface $node
  *   The node entity.
- *
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
- * \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
- * @see https://www.drupal.org/node/3515362
  */
 function taxonomy_build_node_index($node): void {
-  @trigger_error('taxonomy_build_node_index() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::service(\'taxonomy.node_index\')->buildNodeIndex($node). See https://www.drupal.org/node/3515362', E_USER_DEPRECATED);
-  \Drupal::service('taxonomy.node_index')->buildNodeIndex($node);
+  @trigger_error('taxonomy_build_node_index() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. See https://www.drupal.org/node/3515362', E_USER_DEPRECATED);
+  // We maintain a denormalized table of term/node relationships, containing
+  // only data for current, published nodes.
+  if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityTypeManager()->getStorage('node') instanceof SqlContentEntityStorage)) {
+    return;
+  }
+
+  $status = $node->isPublished();
+  $sticky = (int) $node->isSticky();
+  // We only maintain the taxonomy index for published nodes.
+  if ($status && $node->isDefaultRevision()) {
+    // Collect a unique list of all the term IDs from all node fields.
+    $tid_all = [];
+    $entity_reference_class = 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem';
+    foreach ($node->getFieldDefinitions() as $field) {
+      $field_name = $field->getName();
+      $class = $field->getItemDefinition()->getClass();
+      $is_entity_reference_class = ($class === $entity_reference_class) || is_subclass_of($class, $entity_reference_class);
+      if ($is_entity_reference_class && $field->getSetting('target_type') == 'taxonomy_term') {
+        foreach ($node->getTranslationLanguages() as $language) {
+          foreach ($node->getTranslation($language->getId())->$field_name as $item) {
+            if (!$item->isEmpty()) {
+              $tid_all[$item->target_id] = $item->target_id;
+            }
+          }
+        }
+      }
+    }
+    // Insert index entries for all the node's terms.
+    if (!empty($tid_all)) {
+      $connection = \Drupal::database();
+      foreach ($tid_all as $tid) {
+        $connection->merge('taxonomy_index')
+          ->keys(['nid' => $node->id(), 'tid' => $tid, 'status' => $node->isPublished()])
+          ->fields(['sticky' => $sticky, 'created' => $node->getCreatedTime()])
+          ->execute();
+      }
+    }
+  }
 }
 
 /**
@@ -96,14 +130,12 @@ function taxonomy_build_node_index($node): void {
  *
  * @param \Drupal\Core\Entity\EntityInterface $node
  *   The node entity.
- *
- * @deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use
- * \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node) instead.
- * @see https://www.drupal.org/node/3515362
  */
 function taxonomy_delete_node_index(EntityInterface $node): void {
-  @trigger_error('taxonomy_delete_node_index() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. Use \Drupal::service(\'taxonomy.node_index\')->deleteNodeIndex($node). See https://www.drupal.org/node/3515362', E_USER_DEPRECATED);
-  \Drupal::service('taxonomy.node_index')->deleteNodeIndex($node);
+  @trigger_error('taxonomy_delete_node_index() is deprecated in drupal:11.2.0 and is removed from drupal:12.0.0. See https://www.drupal.org/node/3515362', E_USER_DEPRECATED);
+  if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
+    \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
+  }
 }
 
 /**
diff --git a/core/modules/taxonomy/taxonomy.services.yml b/core/modules/taxonomy/taxonomy.services.yml
index 2a5fa8fba95d..91a333ec9773 100644
--- a/core/modules/taxonomy/taxonomy.services.yml
+++ b/core/modules/taxonomy/taxonomy.services.yml
@@ -11,9 +11,3 @@ services:
     arguments: ['@current_route_match']
     tags:
       - { name: 'context_provider' }
-  taxonomy.node_index:
-    class: Drupal\taxonomy\NodeIndex
-    arguments: ['@config.factory', '@database', '@entity_type.manager']
-    tags:
-      - { name: 'node_index'}
-  Drupal\taxonomy\NodeIndex: '@taxonomy.node_index'
-- 
GitLab


From fb7562dd86ee6fd3af2fabf370505ed9193efdfe Mon Sep 17 00:00:00 2001
From: Mike McGovern <26519-mcgovernm@users.noreply.drupalcode.org>
Date: Fri, 9 May 2025 13:21:27 +0000
Subject: [PATCH 50/53] Apply 6 suggestion(s) to 4 file(s)

Co-authored-by: Derek Wright <12223-dww@users.noreply.drupalcode.org>
---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 6 ++----
 core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php   | 4 ++--
 core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php   | 2 +-
 core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php  | 2 +-
 4 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index b41b01315dc8..ae35a8bb4ad7 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -14,7 +14,7 @@
 use Drupal\Core\Url;
 
 /**
- * Hook implementations for taxonomy.
+ * Entity hook implementations for taxonomy.
  */
 class TaxonomyEntityHooks {
 
@@ -30,9 +30,7 @@ public function __construct(
    * Returns the maintain_index_table configuration value.
    */
   protected function shouldMaintainIndexTable(): bool {
-    $taxonomy_config = $this->configFactory->get('taxonomy.settings');
-    $maintain_index_table = $taxonomy_config->get('maintain_index_table');
-    return (bool) $maintain_index_table;
+    return (bool) $this->configFactory->get('taxonomy.settings')->get('maintain_index_table');
   }
 
   /**
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
index 9daa7908d379..2692e0d4e22d 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyHelpHooks.php
@@ -9,7 +9,7 @@
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 
 /**
- * Help hook implementation for taxonomy().
+ * Help hook implementation for the Taxonomy module.
  */
 class TaxonomyHelpHooks {
 
@@ -21,7 +21,7 @@ public function __construct(protected ModuleHandlerInterface $moduleHandler) {}
    * Implements hook_help().
    */
   #[Hook('help')]
-  public function help($route_name, RouteMatchInterface $route_match): string {
+  public function help(string $route_name, RouteMatchInterface $route_match): string {
     switch ($route_name) {
       case 'help.page.taxonomy':
         $field_ui_url = $this->moduleHandler->moduleExists('field_ui') ? Url::fromRoute('help.page', ['name' => 'field_ui'])->toString() : '#';
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php
index a5f457e76dbc..65e949cde151 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyMenuHooks.php
@@ -15,7 +15,7 @@ class TaxonomyMenuHooks {
    * @todo Evaluate removing as part of https://www.drupal.org/node/2358923.
    */
   #[Hook('local_tasks_alter')]
-  public function localTasksAlter(&$local_tasks): void {
+  public function localTasksAlter(array &$local_tasks): void {
     $local_task_key = 'config_translation.local_tasks:entity.taxonomy_vocabulary.config_translation_overview';
     if (isset($local_tasks[$local_task_key])) {
       // The config_translation module expects the base route to be
diff --git a/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
index a9b024b5f48e..9a74574c4fa9 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
@@ -5,7 +5,7 @@
 use Drupal\Core\Hook\Attribute\Hook;
 
 /**
- * Implements hook_theme().
+ * Implements theme hook implementations for the Taxonomy module.
  */
 class TaxonomyThemeHooks {
 
-- 
GitLab


From 2781d81afb4d1c8bc4bec00ca3bcb431e75b877d Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 9 May 2025 10:14:16 -0400
Subject: [PATCH 51/53] Fix defgroup open and close that were separated during
 hook conversion.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 6 +++++-
 core/modules/taxonomy/taxonomy.module                  | 4 ----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index ae35a8bb4ad7..260fc1320685 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -176,5 +176,9 @@ public function taxonomyTermDelete(Term $term): void {
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
   }
-
+  
+  // phpcs:ignore Drupal.Commenting.InlineComment.DocBlock
+  /**
+   * @} End of "defgroup taxonomy_index".
+   */
 }
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index c01e428cc1e9..ecc5fa0c4dbe 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -137,7 +137,3 @@ function taxonomy_delete_node_index(EntityInterface $node): void {
     \Drupal::database()->delete('taxonomy_index')->condition('nid', $node->id())->execute();
   }
 }
-
-/**
- * @} End of "defgroup taxonomy_index".
- */
-- 
GitLab


From 6ac20ba274b66dd70dd780e484eb03017b70e000 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 9 May 2025 10:22:44 -0400
Subject: [PATCH 52/53] Fixing PHPCS error.

---
 core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
index 260fc1320685..f1b031d4a265 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyEntityHooks.php
@@ -176,7 +176,7 @@ public function taxonomyTermDelete(Term $term): void {
       $this->database->delete('taxonomy_index')->condition('tid', $term->id())->execute();
     }
   }
-  
+
   // phpcs:ignore Drupal.Commenting.InlineComment.DocBlock
   /**
    * @} End of "defgroup taxonomy_index".
-- 
GitLab


From 111b9feb7d96676fdde31cdfed85f78f02659c02 Mon Sep 17 00:00:00 2001
From: Mike McGovern <mcgovernm@566364.no-reply.drupal.org>
Date: Fri, 9 May 2025 10:51:32 -0400
Subject: [PATCH 53/53] Removing arguments from theme hook.

---
 core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
index 9a74574c4fa9..e62ba91ee791 100644
--- a/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
+++ b/core/modules/taxonomy/src/Hook/TaxonomyThemeHooks.php
@@ -13,7 +13,7 @@ class TaxonomyThemeHooks {
    * Implements hook_theme().
    */
   #[Hook('theme')]
-  public function taxonomyTheme($existing, $type, $theme, $path): array {
+  public function taxonomyTheme(): array {
     return [
       'taxonomy_term' => [
         'render element' => 'elements',
-- 
GitLab