From ec601d6ba419db06e85271e6d281768d16f79c89 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 1 Apr 2025 15:07:49 +0100
Subject: [PATCH 01/10] Use filtered text to look for entity_usage as these are
 the links that a user actually sees

---
 src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
index 31618b6..4247f3d 100644
--- a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
+++ b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
@@ -19,9 +19,9 @@ abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedT
     if (empty($item_value['value'])) {
       return [];
     }
-    $text = $item_value['value'];
+    $text = check_markup($item->value, $item->format, $item->getLangcode());
     if ($item->getFieldDefinition()->getType() === 'text_with_summary') {
-      $text .= $item_value['summary'];
+      $text .= check_markup($item->summary, $item->format, $item->getLangcode());
     }
     $entities_in_text = $this->parseEntitiesFromText($text);
     $valid_entities = [];
-- 
GitLab


From c652c22fb4d3196d105924cd5395dd0b49c25ac6 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 1 Apr 2025 15:24:51 +0100
Subject: [PATCH 02/10] Nicer code

---
 src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php | 4 ++--
 tests/src/Kernel/EntityUsageTrackExceptionTest.php  | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
index 4247f3d..2cea73e 100644
--- a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
+++ b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
@@ -19,9 +19,9 @@ abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedT
     if (empty($item_value['value'])) {
       return [];
     }
-    $text = check_markup($item->value, $item->format, $item->getLangcode());
+    $text = $item->processed;
     if ($item->getFieldDefinition()->getType() === 'text_with_summary') {
-      $text .= check_markup($item->summary, $item->format, $item->getLangcode());
+      $text .= $item->summary_processed;
     }
     $entities_in_text = $this->parseEntitiesFromText($text);
     $valid_entities = [];
diff --git a/tests/src/Kernel/EntityUsageTrackExceptionTest.php b/tests/src/Kernel/EntityUsageTrackExceptionTest.php
index 2577b58..339f3b6 100644
--- a/tests/src/Kernel/EntityUsageTrackExceptionTest.php
+++ b/tests/src/Kernel/EntityUsageTrackExceptionTest.php
@@ -58,6 +58,7 @@ class EntityUsageTrackExceptionTest extends KernelTestBase {
 
     $this->installEntitySchema('entity_test');
     $this->installSchema('entity_usage', ['entity_usage']);
+    $this->installConfig(['filter']);
 
     $this->config('entity_usage.settings')
       ->set('track_enabled_source_entity_types', ['entity_test'])
-- 
GitLab


From 0e39520f0750361d9c2e66ffb41727be869de1e8 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 1 Apr 2025 15:29:19 +0100
Subject: [PATCH 03/10] Fix PHPStan

---
 phpstan-baseline.neon | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 9009583..3cfbfff 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -65,6 +65,16 @@ parameters:
 			count: 1
 			path: src/Plugin/EntityUsage/Track/EntityReference.php
 
+		-
+			message: "#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\FieldItemInterface\\:\\:\\$processed\\.$#"
+			count: 1
+			path: src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
+
+		-
+			message: "#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\FieldItemInterface\\:\\:\\$summary_processed\\.$#"
+			count: 1
+			path: src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
+
 		-
 			message: "#^Function entity_usage_test_entity_usage_block_tracking\\(\\) has no return type specified\\.$#"
 			count: 1
-- 
GitLab


From 58ed22b797348ec7ec10bb1ae49655dad55c6db6 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Tue, 1 Apr 2025 15:53:39 +0100
Subject: [PATCH 04/10] Only convert urls to links if configured to and only
 use that filter

---
 src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
index 2cea73e..cf8b720 100644
--- a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
+++ b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
@@ -5,6 +5,7 @@ namespace Drupal\entity_usage\Plugin\EntityUsage\Track;
 use Drupal\Core\Field\FieldItemInterface;
 use Drupal\entity_usage\EmbedTrackInterface;
 use Drupal\entity_usage\EntityUsageTrackBase;
+use Drupal\filter\Entity\FilterFormat;
 
 /**
  * Base class for plugins tracking usage in entities embedded in WYSIWYG fields.
@@ -19,10 +20,17 @@ abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedT
     if (empty($item_value['value'])) {
       return [];
     }
-    $text = $item->processed;
+    $text = $item->value;
     if ($item->getFieldDefinition()->getType() === 'text_with_summary') {
-      $text .= $item->summary_processed;
+      $text .= $item->summary;
     }
+    $format = FilterFormat::load($item->format);
+    // If the text format convert URLs in text to real URLs we should too.
+    if ($format->filters()->has('filter_url')) {
+      $filter = $format->filters()->get('filter_url');
+      $text = $filter->process($text, $item->getLangcode())->getProcessedText();
+    }
+
     $entities_in_text = $this->parseEntitiesFromText($text);
     $valid_entities = [];
 
-- 
GitLab


From b498bc531d882f5a95a798f181313e3615bee381 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 2 Apr 2025 11:29:54 +0100
Subject: [PATCH 05/10] Use fallback filter format when appropriate

---
 .../EntityUsage/Track/TextFieldEmbedBase.php  | 26 ++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
index cf8b720..f8a9e1f 100644
--- a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
+++ b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
@@ -2,16 +2,37 @@
 
 namespace Drupal\entity_usage\Plugin\EntityUsage\Track;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ImmutableConfig;
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\FieldItemInterface;
 use Drupal\entity_usage\EmbedTrackInterface;
+use Drupal\entity_usage\EntityUsageInterface;
 use Drupal\entity_usage\EntityUsageTrackBase;
+use Drupal\entity_usage\UrlToEntityInterface;
 use Drupal\filter\Entity\FilterFormat;
+use Psr\Log\LoggerInterface;
 
 /**
  * Base class for plugins tracking usage in entities embedded in WYSIWYG fields.
  */
 abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedTrackInterface {
 
+  /**
+   * The filter settings.
+   */
+  protected ImmutableConfig $filterConfig;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsageInterface $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, ?LoggerInterface $entityUsageLogger = NULL, ?UrlToEntityInterface $urlToEntity = NULL, ?array $always_track_base_fields = NULL) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository, $entityUsageLogger, $urlToEntity, $always_track_base_fields);
+    $this->filterConfig = $config_factory->get('filter.settings');
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -24,7 +45,10 @@ abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedT
     if ($item->getFieldDefinition()->getType() === 'text_with_summary') {
       $text .= $item->summary;
     }
-    $format = FilterFormat::load($item->format);
+
+    // Use the fallback format if necessary.
+    // @see \Drupal\filter\Element\ProcessedText::preRenderText()
+    $format = FilterFormat::load($item->format ?? $this->filterConfig->get('fallback_format'));
     // If the text format convert URLs in text to real URLs we should too.
     if ($format->filters()->has('filter_url')) {
       $filter = $format->filters()->get('filter_url');
-- 
GitLab


From eab75814023ecdb09f9f777690d76eb6f1ae910c Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 2 Apr 2025 11:36:32 +0100
Subject: [PATCH 06/10] Update baseline

---
 phpstan-baseline.neon | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 3cfbfff..32e7516 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -66,12 +66,12 @@ parameters:
 			path: src/Plugin/EntityUsage/Track/EntityReference.php
 
 		-
-			message: "#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\FieldItemInterface\\:\\:\\$processed\\.$#"
+			message: "#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\FieldItemInterface\\:\\:\\$summary\\.$#"
 			count: 1
 			path: src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
 
 		-
-			message: "#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\FieldItemInterface\\:\\:\\$summary_processed\\.$#"
+			message: "#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\FieldItemInterface\\:\\:\\$value\\.$#"
 			count: 1
 			path: src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
 
-- 
GitLab


From 61ca4994d559e398740eae913aaf7b3d66395da5 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 2 Apr 2025 14:09:50 +0100
Subject: [PATCH 07/10] Move code to convert text to links to the correct
 plugin

---
 src/Plugin/EntityUsage/Track/HtmlLink.php     | 40 ++++++++++++++
 .../EntityUsage/Track/TextFieldEmbedBase.php  | 53 +++++++------------
 2 files changed, 58 insertions(+), 35 deletions(-)

diff --git a/src/Plugin/EntityUsage/Track/HtmlLink.php b/src/Plugin/EntityUsage/Track/HtmlLink.php
index 0d016fd..bd2da28 100644
--- a/src/Plugin/EntityUsage/Track/HtmlLink.php
+++ b/src/Plugin/EntityUsage/Track/HtmlLink.php
@@ -3,7 +3,17 @@
 namespace Drupal\entity_usage\Plugin\EntityUsage\Track;
 
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Config\ImmutableConfig;
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Field\FieldItemInterface;
+use Drupal\entity_usage\EntityUsageInterface;
 use Drupal\entity_usage\EntityUsageTrackUrlUpdateInterface;
+use Drupal\entity_usage\UrlToEntityInterface;
+use Drupal\filter\Entity\FilterFormat;
+use Psr\Log\LoggerInterface;
 
 /**
  * Tracks usage of entities referenced from regular HTML Links.
@@ -18,6 +28,19 @@ use Drupal\entity_usage\EntityUsageTrackUrlUpdateInterface;
  */
 class HtmlLink extends TextFieldEmbedBase implements EntityUsageTrackUrlUpdateInterface {
 
+  /**
+   * The filter settings.
+   */
+  protected ImmutableConfig $filterConfig;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsageInterface $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, ?LoggerInterface $entityUsageLogger = NULL, ?UrlToEntityInterface $urlToEntity = NULL, ?array $always_track_base_fields = NULL) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository, $entityUsageLogger, $urlToEntity, $always_track_base_fields);
+    $this->filterConfig = $config_factory->get('filter.settings');
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -74,4 +97,21 @@ class HtmlLink extends TextFieldEmbedBase implements EntityUsageTrackUrlUpdateIn
     return $entities;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getTextFromField(FieldItemInterface $item): string {
+    $text = parent::getTextFromField($item);
+
+    // Use the fallback format if necessary.
+    // @see \Drupal\filter\Element\ProcessedText::preRenderText()
+    $format = FilterFormat::load($item->format ?? $this->filterConfig->get('fallback_format'));
+    // If the text format convert URLs in text to real URLs we should too.
+    if ($format->filters()->has('filter_url')) {
+      $filter = $format->filters()->get('filter_url');
+      $text = $filter->process($text, $item->getLangcode())->getProcessedText();
+    }
+    return $text;
+  }
+
 }
diff --git a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
index f8a9e1f..62349ca 100644
--- a/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
+++ b/src/Plugin/EntityUsage/Track/TextFieldEmbedBase.php
@@ -2,37 +2,15 @@
 
 namespace Drupal\entity_usage\Plugin\EntityUsage\Track;
 
-use Drupal\Core\Config\ConfigFactoryInterface;
-use Drupal\Core\Config\ImmutableConfig;
-use Drupal\Core\Entity\EntityFieldManagerInterface;
-use Drupal\Core\Entity\EntityRepositoryInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\FieldItemInterface;
 use Drupal\entity_usage\EmbedTrackInterface;
-use Drupal\entity_usage\EntityUsageInterface;
 use Drupal\entity_usage\EntityUsageTrackBase;
-use Drupal\entity_usage\UrlToEntityInterface;
-use Drupal\filter\Entity\FilterFormat;
-use Psr\Log\LoggerInterface;
 
 /**
  * Base class for plugins tracking usage in entities embedded in WYSIWYG fields.
  */
 abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedTrackInterface {
 
-  /**
-   * The filter settings.
-   */
-  protected ImmutableConfig $filterConfig;
-
-  /**
-   * {@inheritdoc}
-   */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityUsageInterface $usage_service, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, EntityRepositoryInterface $entity_repository, ?LoggerInterface $entityUsageLogger = NULL, ?UrlToEntityInterface $urlToEntity = NULL, ?array $always_track_base_fields = NULL) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition, $usage_service, $entity_type_manager, $entity_field_manager, $config_factory, $entity_repository, $entityUsageLogger, $urlToEntity, $always_track_base_fields);
-    $this->filterConfig = $config_factory->get('filter.settings');
-  }
-
   /**
    * {@inheritdoc}
    */
@@ -41,19 +19,7 @@ abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedT
     if (empty($item_value['value'])) {
       return [];
     }
-    $text = $item->value;
-    if ($item->getFieldDefinition()->getType() === 'text_with_summary') {
-      $text .= $item->summary;
-    }
-
-    // Use the fallback format if necessary.
-    // @see \Drupal\filter\Element\ProcessedText::preRenderText()
-    $format = FilterFormat::load($item->format ?? $this->filterConfig->get('fallback_format'));
-    // If the text format convert URLs in text to real URLs we should too.
-    if ($format->filters()->has('filter_url')) {
-      $filter = $format->filters()->get('filter_url');
-      $text = $filter->process($text, $item->getLangcode())->getProcessedText();
-    }
+    $text = $this->getTextFromField($item);
 
     $entities_in_text = $this->parseEntitiesFromText($text);
     $valid_entities = [];
@@ -84,4 +50,21 @@ abstract class TextFieldEmbedBase extends EntityUsageTrackBase implements EmbedT
     return $valid_entities;
   }
 
+  /**
+   * Gets the text from the field.
+   *
+   * @param \Drupal\Core\Field\FieldItemInterface $item
+   *   The field item.
+   *
+   * @return string
+   *   The field text.
+   */
+  protected function getTextFromField(FieldItemInterface $item): string {
+    $text = $item->value;
+    if ($item->getFieldDefinition()->getType() === 'text_with_summary') {
+      $text .= $item->summary;
+    }
+    return $text;
+  }
+
 }
-- 
GitLab


From f5ea3fffbf5c6a46c477a9ded5c873b7d7036005 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 2 Apr 2025 14:43:42 +0100
Subject: [PATCH 08/10] Add test coverage

---
 src/Plugin/EntityUsage/Track/HtmlLink.php     |   2 +-
 tests/src/Kernel/EntityUsageFilterUrlTest.php | 132 ++++++++++++++++++
 2 files changed, 133 insertions(+), 1 deletion(-)
 create mode 100644 tests/src/Kernel/EntityUsageFilterUrlTest.php

diff --git a/src/Plugin/EntityUsage/Track/HtmlLink.php b/src/Plugin/EntityUsage/Track/HtmlLink.php
index bd2da28..ca2506c 100644
--- a/src/Plugin/EntityUsage/Track/HtmlLink.php
+++ b/src/Plugin/EntityUsage/Track/HtmlLink.php
@@ -107,7 +107,7 @@ class HtmlLink extends TextFieldEmbedBase implements EntityUsageTrackUrlUpdateIn
     // @see \Drupal\filter\Element\ProcessedText::preRenderText()
     $format = FilterFormat::load($item->format ?? $this->filterConfig->get('fallback_format'));
     // If the text format convert URLs in text to real URLs we should too.
-    if ($format->filters()->has('filter_url')) {
+    if ($format instanceof FilterFormat && $format->filters()->has('filter_url') && $format->filters('filter_url')->status) {
       $filter = $format->filters()->get('filter_url');
       $text = $filter->process($text, $item->getLangcode())->getProcessedText();
     }
diff --git a/tests/src/Kernel/EntityUsageFilterUrlTest.php b/tests/src/Kernel/EntityUsageFilterUrlTest.php
new file mode 100644
index 0000000..e5d4a0c
--- /dev/null
+++ b/tests/src/Kernel/EntityUsageFilterUrlTest.php
@@ -0,0 +1,132 @@
+<?php
+
+namespace Drupal\Tests\entity_usage\Kernel;
+
+use Drupal\filter\Entity\FilterFormat;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\entity_test\Entity\EntityTest;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+
+/**
+ * Tests URLs in text tracking.
+ *
+ * @group entity_usage
+ */
+class EntityUsageFilterUrlTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'entity_test',
+    'entity_usage',
+    'field',
+    'filter',
+    'system',
+    'text',
+    'user',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    FieldStorageConfig::create([
+      'type' => 'text_long',
+      'entity_type' => 'entity_test',
+      'field_name' => 'text_no_url_filter',
+    ])->save();
+    FieldConfig::create([
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
+      'field_name' => 'text_no_url_filter',
+      'label' => 'Text No URL Filter',
+    ])->save();
+
+    FieldStorageConfig::create([
+      'type' => 'text_long',
+      'entity_type' => 'entity_test',
+      'field_name' => 'text_url_filter',
+    ])->save();
+    FieldConfig::create([
+      'entity_type' => 'entity_test',
+      'bundle' => 'entity_test',
+      'field_name' => 'text_url_filter',
+      'label' => 'Text URL Filter',
+    ])->save();
+
+    $format = FilterFormat::create([
+      'format' => 'no_url_format',
+      'name' => 'No URL format',
+    ]);
+    $format->setFilterConfig('filter_url', [
+      'status' => 0,
+    ]);
+    $format->save();
+
+    // Add another text format specifying the URL filter.
+    $format = FilterFormat::create([
+      'format' => 'url_format',
+      'name' => 'URL format',
+    ]);
+    $format->setFilterConfig('filter_url', [
+      'status' => 1,
+      'settings' => [
+        'filter_url_length' => 30,
+      ],
+    ]);
+    $format->save();
+
+    $this->installEntitySchema('entity_test');
+    $this->installSchema('entity_usage', ['entity_usage']);
+    $this->installConfig(['filter']);
+
+    $this->config('entity_usage.settings')
+      ->set('track_enabled_source_entity_types', ['entity_test'])
+      ->set('track_enabled_target_entity_types', ['entity_test'])
+      ->set('track_enabled_plugins', ['html_link'])
+      ->set('site_domains', ['http://localhost'])
+      ->save();
+    $this->container->get('kernel')->resetContainer();
+  }
+
+  /**
+   * Tests text URLs are tracked if the filter is set up.
+   */
+  public function testUrlTracking(): void {
+    $entity1 = EntityTest::create([
+      'type' => 'entity_test',
+      'name' => $this->randomString(),
+    ]);
+    $entity1->save();
+
+    $entity2 = EntityTest::create([
+      'type' => 'entity_test',
+      'name' => $this->randomString(),
+    ]);
+    $entity2->save();
+
+    $entity3 = EntityTest::create([
+      'type' => 'entity_test',
+      'name' => $this->randomString(),
+      'text_no_url_filter' => ['value' => $entity1->toUrl()->setAbsolute()->toString(), 'format' => 'no_url_format'],
+      'text_url_filter' => ['value' => $entity2->toUrl()->setAbsolute()->toString(), 'format' => 'url_format'],
+    ]);
+    $entity3->save();
+
+    // We should have a single usage in the text_url_filter field.
+    /** @var \Drupal\entity_usage\EntityUsage $entity_usage */
+    $entity_usage = $this->container->get('entity_usage.usage');
+    $targets = $entity_usage->listTargets($entity3);
+    $this->assertCount(1, $targets['entity_test']);
+    $this->assertSame([[
+      'method' => 'html_link',
+      'field_name' => 'text_url_filter',
+      'count' => '1',
+    ]], $targets['entity_test'][2]);
+  }
+
+}
-- 
GitLab


From 90ab1956ead074a809aba2daf5c8878cbaac79ba Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 2 Apr 2025 14:50:16 +0100
Subject: [PATCH 09/10] PHPStan and PHPCS silliness

---
 phpstan-baseline.neon                         |  5 +++++
 tests/src/Kernel/EntityUsageFilterUrlTest.php | 13 ++++++++-----
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 32e7516..f073158 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -65,6 +65,11 @@ parameters:
 			count: 1
 			path: src/Plugin/EntityUsage/Track/EntityReference.php
 
+		-
+			message: "#^Access to an undefined property Drupal\\\\filter\\\\FilterPluginCollection\\|Drupal\\\\filter\\\\Plugin\\\\FilterInterface\\:\\:\\$status\\.$#"
+			count: 1
+			path: src/Plugin/EntityUsage/Track/HtmlLink.php
+
 		-
 			message: "#^Access to an undefined property Drupal\\\\Core\\\\Field\\\\FieldItemInterface\\:\\:\\$summary\\.$#"
 			count: 1
diff --git a/tests/src/Kernel/EntityUsageFilterUrlTest.php b/tests/src/Kernel/EntityUsageFilterUrlTest.php
index e5d4a0c..bb42241 100644
--- a/tests/src/Kernel/EntityUsageFilterUrlTest.php
+++ b/tests/src/Kernel/EntityUsageFilterUrlTest.php
@@ -122,11 +122,14 @@ class EntityUsageFilterUrlTest extends KernelTestBase {
     $entity_usage = $this->container->get('entity_usage.usage');
     $targets = $entity_usage->listTargets($entity3);
     $this->assertCount(1, $targets['entity_test']);
-    $this->assertSame([[
-      'method' => 'html_link',
-      'field_name' => 'text_url_filter',
-      'count' => '1',
-    ]], $targets['entity_test'][2]);
+    $this->assertSame(
+      [[
+        'method' => 'html_link',
+        'field_name' => 'text_url_filter',
+        'count' => '1',
+      ]],
+      $targets['entity_test'][2]
+    );
   }
 
 }
-- 
GitLab


From d3fe90b104878b283be9cb1736f2d503d58f4bf8 Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Wed, 2 Apr 2025 14:53:43 +0100
Subject: [PATCH 10/10] Bahhh

---
 tests/src/Kernel/EntityUsageFilterUrlTest.php | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/tests/src/Kernel/EntityUsageFilterUrlTest.php b/tests/src/Kernel/EntityUsageFilterUrlTest.php
index bb42241..5e59541 100644
--- a/tests/src/Kernel/EntityUsageFilterUrlTest.php
+++ b/tests/src/Kernel/EntityUsageFilterUrlTest.php
@@ -123,11 +123,13 @@ class EntityUsageFilterUrlTest extends KernelTestBase {
     $targets = $entity_usage->listTargets($entity3);
     $this->assertCount(1, $targets['entity_test']);
     $this->assertSame(
-      [[
-        'method' => 'html_link',
-        'field_name' => 'text_url_filter',
-        'count' => '1',
-      ]],
+      [
+        [
+          'method' => 'html_link',
+          'field_name' => 'text_url_filter',
+          'count' => '1',
+        ],
+      ],
       $targets['entity_test'][2]
     );
   }
-- 
GitLab