Repository: wagtail/wagtail

Issue:
Add Wagtail prefix to non-taggit settings
### Is your proposal related to a problem?

All of our settings are prefixed with `WAGTAIL_` except for two Wagtail specific tagging settings.

* [`TAG_SPACES_ALLOWED`](https://docs.wagtail.org/en/stable/reference/settings.html#tag-spaces-allowed)
* [`TAG_LIMIT`](https://docs.wagtail.org/en/stable/reference/settings.html#tag-limit)

### Describe the solution you'd like

Adding an alias for the other non-Taggit settings, to have a name spaced `WAGTAIL_` prefix, while still supporting the current naming but triggering a warning.

* `TAG_SPACES_ALLOWED` -> `WAGTAIL_TAGS_SPACES_ALLOWED`
* `TAG_LIMIT` -> `WAGTAIL_TAGS_LIMIT`

See how a similar rename was done a while ago https://github.com/wagtail/wagtail/pull/11525 (including warnings `RemovedInWagtail70Warning`).

This way we have Wagtail prefixed (namespaced) settings once the next major release bump happens.

### Additional context

The PR #12564 introduced a hard limit on number of tags returned to 10 to avoid fetching all items possible which was causing performance issues for large databases - see https://github.com/wagtail/wagtail/issues/12415 .

There may be a future desire to make this hard limit configurable, for now though we will not cover that on this issue.


### Working on this

* PR WIP already https://github.com/wagtail/wagtail/pull/12639
* Anyone can contribute to this. View our [contributing guidelines](https://docs.wagtail.org/en/latest/contributing/index.html), add a comment to the issue once you’re ready to start.



Discussion:
aayushman-singh: @laymonage @lb- 
aayushman-singh: Thank you for your insight. @laymonage Ran into some issues with ruff here as `html=` was removed. I've added it back to clear tests. Please check lines 565 and 584., is there anything else I missed?
aayushman-singh: I think this PR is ready to merge @lb- @laymonage 

Patch:
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index b012ab174e..609e30285c 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -4,6 +4,7 @@ Changelog
 6.5 (xx.xx.xxxx) - IN DEVELOPMENT
 ~~~~~~~~~~~~~~~~
 
+ * Add `WAGTAIL_` prefix to Wagtail-specific tag settings (Aayushman Singh)
  * Docs: Add missing `django.contrib.admin` to list of apps in "add to Django project" guide (Mohamed Rabiaa)
 
 
diff --git a/docs/reference/settings.md b/docs/reference/settings.md
index c6d91d24cd..e1391d3d61 100644
--- a/docs/reference/settings.md
+++ b/docs/reference/settings.md
@@ -808,18 +808,26 @@ TAGGIT_CASE_INSENSITIVE = True
 
 Tags are case-sensitive by default ('music' and 'Music' are treated as distinct tags). In many cases the reverse behavior is preferable.
 
-### `TAG_SPACES_ALLOWED`
+### `WAGTAIL_TAG_SPACES_ALLOWED`
+
+```{versionchanged} 6.5
+The setting was renamed from `TAG_SPACES_ALLOWED` to `WAGTAIL_TAG_SPACES_ALLOWED`.
+```
 
 ```python
-TAG_SPACES_ALLOWED = False
+WAGTAIL_TAG_SPACES_ALLOWED = False
 ```
 
 Tags can only consist of a single word, no spaces allowed. The default setting is `True` (spaces in tags are allowed).
 
-### `TAG_LIMIT`
+### `WAGTAIL_TAG_LIMIT`
+
+```{versionchanged} 6.5
+The setting was renamed from `TAG_LIMIT` to `WAGTAIL_TAG_LIMIT`.
+```
 
 ```python
-TAG_LIMIT = 5
+WAGTAIL_TAG_LIMIT = 5
 ```
 
 Limit the number of tags that can be added to (django-taggit) Tag model. Default setting is `None`, meaning no limit on tags.
diff --git a/docs/releases/6.5.md b/docs/releases/6.5.md
index 11373c32b8..46ad46e51c 100644
--- a/docs/releases/6.5.md
+++ b/docs/releases/6.5.md
@@ -31,6 +31,10 @@ depth: 1
 
 ## Upgrade considerations - deprecation of old functionality
 
+### `TAG_LIMIT` and `TAG_SPACES_ALLOWED` settings renamed to `WAGTAIL_TAG_LIMIT` and `WAGTAIL_TAG_SPACES_ALLOWED`
+
+The `TAG_LIMIT` and `TAG_SPACES_ALLOWED` settings have been renamed to `WAGTAIL_TAG_LIMIT` and `WAGTAIL_TAG_SPACES_ALLOWED` respectively. The old settings will continue to work for now, but will be removed in a future release.
+
 ## Upgrade considerations - changes affecting Wagtail customisations
 
 ## Upgrade considerations - changes to undocumented internals
diff --git a/wagtail/admin/views/tags.py b/wagtail/admin/views/tags.py
index f4963718f0..1decdf1f7f 100644
--- a/wagtail/admin/views/tags.py
+++ b/wagtail/admin/views/tags.py
@@ -2,6 +2,8 @@ from django.contrib.contenttypes.models import ContentType
 from django.http import Http404, JsonResponse
 from taggit.models import Tag, TagBase
 
+TAGS_AUTOCOMPLETE_LIMIT = 10
+
 
 def autocomplete(request, app_name=None, model_name=None):
     if app_name and model_name:
@@ -22,7 +24,7 @@ def autocomplete(request, app_name=None, model_name=None):
         tags = (
             tag_model.objects.filter(name__istartswith=term)
             .order_by("name")
-            .values_list("name", flat=True)[:10]
+            .values_list("name", flat=True)[:TAGS_AUTOCOMPLETE_LIMIT]
         )
     else:
         tags = tag_model.objects.none()
diff --git a/wagtail/admin/widgets/tags.py b/wagtail/admin/widgets/tags.py
index 87c32caddd..340c0a77bd 100644
--- a/wagtail/admin/widgets/tags.py
+++ b/wagtail/admin/widgets/tags.py
@@ -1,4 +1,5 @@
 import json
+from warnings import warn
 
 from django.conf import settings
 from django.urls import reverse
@@ -6,6 +7,8 @@ from django.utils.translation import gettext_lazy as _
 from taggit.forms import TagWidget
 from taggit.models import Tag
 
+from wagtail.utils.deprecation import RemovedInWagtail70Warning
+
 
 class AdminTagWidget(TagWidget):
     template_name = "wagtailadmin/widgets/tag_widget.html"
@@ -39,7 +42,19 @@ class AdminTagWidget(TagWidget):
         else:
             free_tagging = self.free_tagging
 
-        tag_spaces_allowed = getattr(settings, "TAG_SPACES_ALLOWED", True)
+        if hasattr(settings, "TAG_SPACES_ALLOWED"):
+            warn(
+                "The setting 'TAG_SPACES_ALLOWED' is deprecated. "
+                "Please use 'WAGTAIL_TAG_SPACES_ALLOWED' instead.",
+                RemovedInWagtail70Warning,
+            )
+        tag_spaces_allowed = getattr(
+            settings,
+            "WAGTAIL_TAG_SPACES_ALLOWED",
+            # RemovedInWagtail70Warning: Remove fallback to deprecated setting
+            getattr(settings, "TAG_SPACES_ALLOWED", True),
+        )
+
         if tag_spaces_allowed:
             help_text = _(
                 'Multi-word tags with spaces will automatically be enclosed in double quotes (").'
@@ -47,13 +62,26 @@ class AdminTagWidget(TagWidget):
         else:
             help_text = _("Tags can only consist of a single word, no spaces allowed.")
 
+        if hasattr(settings, "TAG_LIMIT"):
+            warn(
+                "The setting 'TAG_LIMIT' is deprecated. "
+                "Please use 'WAGTAIL_TAG_LIMIT' instead.",
+                RemovedInWagtail70Warning,
+            )
+        tag_limit = getattr(
+            settings,
+            "WAGTAIL_TAG_LIMIT",
+            # RemovedInWagtail70Warning: Remove fallback to deprecated setting
+            getattr(settings, "TAG_LIMIT", None),
+        )
+
         context["widget"]["help_text"] = help_text
         context["widget"]["attrs"]["data-w-tag-delay-value"] = 200
         context["widget"]["attrs"]["data-w-tag-url-value"] = autocomplete_url
         context["widget"]["attrs"]["data-w-tag-options-value"] = json.dumps(
             {
-                "allowSpaces": getattr(settings, "TAG_SPACES_ALLOWED", True),
-                "tagLimit": getattr(settings, "TAG_LIMIT", None),
+                "allowSpaces": tag_spaces_allowed,
+                "tagLimit": tag_limit,
                 "autocompleteOnly": not free_tagging,
             }
         )


Test patch:
diff --git a/wagtail/admin/tests/test_widgets.py b/wagtail/admin/tests/test_widgets.py
index 0d8ed35e4e..d4fb05c266 100644
--- a/wagtail/admin/tests/test_widgets.py
+++ b/wagtail/admin/tests/test_widgets.py
@@ -12,6 +12,7 @@ from wagtail.admin.forms.tags import TagField
 from wagtail.models import Page
 from wagtail.test.testapp.forms import AdminStarDateInput
 from wagtail.test.testapp.models import EventPage, RestaurantTag, SimplePage
+from wagtail.utils.deprecation import RemovedInWagtail70Warning
 
 
 class TestAdminPageChooserWidget(TestCase):
@@ -430,9 +431,9 @@ class TestAdminTagWidget(TestCase):
             ],
         )
 
-    @override_settings(TAG_SPACES_ALLOWED=False)
+    @override_settings(WAGTAIL_TAG_SPACES_ALLOWED=False)
     def test_render_js_init_no_spaces_allowed(self):
-        """Checks that the 'w-tag' controller attributes are correctly added to the tag widgets based  on TAG_SPACES_ALLOWED in settings"""
+        """Checks that the 'w-tag' controller attributes are correctly added to the tag widgets based  on WAGTAIL_TAG_SPACES_ALLOWED in settings"""
         widget = widgets.AdminTagWidget()
 
         html = widget.render("tags", None, attrs={"id": "alpha"})
@@ -447,9 +448,9 @@ class TestAdminTagWidget(TestCase):
             ],
         )
 
-    @override_settings(TAG_LIMIT=5)
+    @override_settings(WAGTAIL_TAG_LIMIT=5)
     def test_render_js_init_with_tag_limit(self):
-        """Checks that the 'w-tag' controller attributes are correctly added to the tag widget using options based on TAG_LIMIT in settings"""
+        """Checks that the 'w-tag' controller attributes are correctly added to the tag widget using options based on WAGTAIL_TAG_LIMIT in settings"""
 
         widget = widgets.AdminTagWidget()
 
@@ -517,9 +518,9 @@ class TestAdminTagWidget(TestCase):
             ],
         )
 
-    @override_settings(TAG_SPACES_ALLOWED=True)
+    @override_settings(WAGTAIL_TAG_SPACES_ALLOWED=True)
     def test_tags_help_text_spaces_allowed(self):
-        """Checks that the tags help text html element content is correct when TAG_SPACES_ALLOWED is True"""
+        """Checks that the tags help text html element content is correct when WAGTAIL_TAG_SPACES_ALLOWED is True"""
         widget = widgets.AdminTagWidget()
         help_text = widget.get_context(None, None, {})["widget"]["help_text"]
 
@@ -535,9 +536,9 @@ class TestAdminTagWidget(TestCase):
             html,
         )
 
-    @override_settings(TAG_SPACES_ALLOWED=False)
+    @override_settings(WAGTAIL_TAG_SPACES_ALLOWED=False)
     def test_tags_help_text_no_spaces_allowed(self):
-        """Checks that the tags help text html element content is correct when TAG_SPACES_ALLOWED is False"""
+        """Checks that the tags help text html element content is correct when WAGTAIL_TAG_SPACES_ALLOWED is False"""
         widget = widgets.AdminTagWidget()
         help_text = widget.get_context(None, None, {})["widget"]["help_text"]
 
@@ -552,6 +553,44 @@ class TestAdminTagWidget(TestCase):
             html,
         )
 
+    @override_settings(TAG_LIMIT=3)
+    def test_legacy_tag_limit_setting(self):
+        widget = widgets.AdminTagWidget()
+        with self.assertWarnsMessage(
+            RemovedInWagtail70Warning,
+            "The setting 'TAG_LIMIT' is deprecated. "
+            "Please use 'WAGTAIL_TAG_LIMIT' instead.",
+        ):
+            html = widget.render("tags", None, attrs={"id": "alpha"})
+        params = self.get_js_init_params(html)
+        self.assertEqual(
+            params,
+            [
+                "alpha",
+                "/admin/tag-autocomplete/",
+                {"allowSpaces": True, "tagLimit": 3, "autocompleteOnly": False},
+            ],
+        )
+
+    @override_settings(TAG_SPACES_ALLOWED=False)
+    def test_legacy_tag_spaces_allowed_setting(self):
+        widget = widgets.AdminTagWidget()
+        with self.assertWarnsMessage(
+            RemovedInWagtail70Warning,
+            "The setting 'TAG_SPACES_ALLOWED' is deprecated. "
+            "Please use 'WAGTAIL_TAG_SPACES_ALLOWED' instead.",
+        ):
+            html = widget.render("tags", None, attrs={"id": "alpha"})
+        params = self.get_js_init_params(html)
+        self.assertEqual(
+            params,
+            [
+                "alpha",
+                "/admin/tag-autocomplete/",
+                {"allowSpaces": False, "tagLimit": None, "autocompleteOnly": False},
+            ],
+        )
+
 
 class TestTagField(TestCase):
     def setUp(self):