Repository: wagtail/wagtail

Issue:
Tags field needs universal help text to explain need to quote multi-word tags
Wagtail's tagging system requires multi-word tags to be quoted, to prevent a two-word tag becoming two separate tags. This appears to catch users out repeatedly and has generated several Issues in recent months.

The tag field widget, wherever used (page models, images, documents etc) should have standard help text (appearing beneath it like all help text) explaining the need for quoting. Explaining the need for comma-delimiting might also be worth adding while we're at it.



Discussion:
I'd like to work on this today. I'm at the Django under the Hood sprint. We have about 3 hours of sprinting left.

I think this can be closed, as https://github.com/wagtail/wagtail/issues/3488 makes the default behaviour different.
I think it's still a good idea to have help text explaining the behaviour, whatever that behaviour is... I guess that with #3488 in place, we'd need two different help messages depending on the value of `TAG_SPACES_ALLOWED`.
Hello @lb- . I would like to have a shot with this issue.
@amajai  no need to ask permission, review the comments and the PRs that are linked and give it a go :) 

Resolving patch:
diff --git a/wagtail/admin/widgets/tags.py b/wagtail/admin/widgets/tags.py
--- a/wagtail/admin/widgets/tags.py
+++ b/wagtail/admin/widgets/tags.py
@@ -2,6 +2,7 @@
 
 from django.conf import settings
 from django.urls import reverse
+from django.utils.translation import gettext_lazy as _
 from taggit.forms import TagWidget
 from taggit.models import Tag
 
@@ -31,6 +32,15 @@ def get_context(self, name, value, attrs):
         else:
             free_tagging = self.free_tagging
 
+        tag_spaces_allowed = getattr(settings, "TAG_SPACES_ALLOWED", True)
+        if tag_spaces_allowed:
+            help_text = _(
+                'Multi-word tags with spaces will automatically be enclosed in double quotes (").'
+            )
+        else:
+            help_text = _("Tags can only consist of a single word, no spaces allowed.")
+
+        context["widget"]["help_text"] = help_text
         context["widget"]["autocomplete_url"] = autocomplete_url
         context["widget"]["options_json"] = json.dumps(
             {


Test patch:
diff --git a/wagtail/admin/tests/test_widgets.py b/wagtail/admin/tests/test_widgets.py
--- a/wagtail/admin/tests/test_widgets.py
+++ b/wagtail/admin/tests/test_widgets.py
@@ -361,6 +361,16 @@ def get_js_init_params(self, html):
                 return json.loads("[%s]" % params_raw)
         return []
 
+    def get_help_text_html_element(self, html):
+        """Return a help text html element with content as string"""
+        start = """<input type="text" name="tags">"""
+        end = "<script>"
+        items_after_input_tag = html.split(start)[1]
+        if items_after_input_tag:
+            help_text_element = items_after_input_tag.split(end)[0].strip()
+            return help_text_element
+        return []
+
     def test_render_js_init_basic(self):
         """Checks that the 'initTagField' is correctly added to the inline script for tag widgets"""
         widget = widgets.AdminTagWidget()
@@ -462,6 +472,43 @@ def test_render_with_free_tagging_true(self):
             ],
         )
 
+    @override_settings(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"""
+        widget = widgets.AdminTagWidget()
+        help_text = widget.get_context(None, None, {})["widget"]["help_text"]
+
+        html = widget.render("tags", None, {})
+        help_text_html_element = self.get_help_text_html_element(html)
+
+        self.assertEqual(
+            help_text,
+            'Multi-word tags with spaces will automatically be enclosed in double quotes (").',
+        )
+
+        self.assertHTMLEqual(
+            help_text_html_element,
+            """<p class="help">%s</p>""" % help_text,
+        )
+
+    @override_settings(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"""
+        widget = widgets.AdminTagWidget()
+        help_text = widget.get_context(None, None, {})["widget"]["help_text"]
+
+        html = widget.render("tags", None, {})
+        help_text_html_element = self.get_help_text_html_element(html)
+
+        self.assertEqual(
+            help_text, "Tags can only consist of a single word, no spaces allowed."
+        )
+
+        self.assertHTMLEqual(
+            help_text_html_element,
+            """<p class="help">%s</p>""" % help_text,
+        )
+
 
 class TestTagField(TestCase):
     def setUp(self):