Enable tagging only in some categories

This is looking good @neil. One thing that would be good relating to this would be the simple option to ‘enable tags in category’ option in the category modal.

In my use case I only want tags (and specific tags at that) to be able to be used in specific categories. E.g. in those categories where I don’t want tags enabled I wouldn’t want the tag input field to be shown to users. Is this doable?

4 Likes

It’s probably doable, but I have to focus on completing some other tag features first. Will have to come back around to this one later.

9 Likes

I would love to only enable tags in certain categories as well - bookmarking this thread to keep an eye on the discussion moving forward

I think this is currently possible in the way that you can define tag-groups and you can configure category setting in order to use that tag-group.

do you mean something else?

3 Likes

Another feature that would make sense related to this:

If tag filter is enabled, yet only certain categories have tags availble using the ‘Tags that can only be used in this category’ in category settings, I believe the homepage (both the main category, latest and top) pages should have the tag filter disabled by default.

I.e. only when digging down into the categories/sub-categories with tags allowed should the tag filter be shown (showing the respective tags available).

Otherwise from the homepage (whether that be categories or latest), you’ll get a whole bunch of tags in the filter, often without context as they only have context when filtered inside their respective categories.

Does this make sense?

1 Like

Keen to test this out. Am I able to grab some code somewhere for this? Cheers.

100% agree. In our example, we have a documentary section with a dedicated tag group. I want to show the tag drop down here, with only the dedicated tags. That’s working.

But I don’t want to have the same tags available in the drop down on top-level latest, top for all categories. It’s taking away the advantage of dedicating tag groups to certain categories IMHO and is confusing at the top level.

Only global tags not assigned to a tag group assigned to a category should show up in the top-level tag drop down.

In the tag group settings there should be something like:

[ ] Limit this tag group only to assigned categories, don’t show in top level drop downs

This is something I’d also like to see.

On my first (imported) forum, I needed a classified ads category.

Since on Discourse, there is no such thing as a “folder” containing categories like there is on other engines like vbulletin or phpbb, I had basically three choices:

  1. A single ads category for both “buy” and “sell” ads, where users would add by themselves [BUY] or [SELL] as their topic’s title prefix (so 2000s…)
  2. A single ads category where users could use tags “buy” or “sell”. The most convenient by far, but we didn’t have any use of tags on any other categories, and users would see the tag field in the composer for any category, which would be confusing.
  3. Having 2 ads category at the top level: “buy”, and “sell”. This is the choice we made;

I’m importing another, larger forum, and I have the exact same “issue”, except that I’d need tags for 2 categories instead of 1: a classified ads category, and an “other languages” category containing only posts in foreign languages that would use a specific tag for the language in which they are written, such as “hebrew”, “danish”, etc.

And again, we don’t have the need for tags for any other category.

I’d need the tag selector in the topic list navigation bar for both these categories, but not for other categories.
I could easily hide it when necessary with a bit of CSS, but the major problem is the tag input in the composer, which can’t be displayed or hidden at will…

I guess at this stage the best way would be to override the composer tagValidation method.
Each time a category is selected in the composer, it would hide or show the tag input, based on the selected category.

When the tag fields is hidden, it would look like this then, with an empty space:

Also it could potentially break the layout if we use plugins or theme components that have custom composer fields, like the location plugin.

I’m trying the method I thought about as a workaround.

Hiding the tag selector in the topic list with CSS:


(you must target each taggable category with your CSS selector)

body:not(.category-other-languages):not(.category-trading-post) {
    .category-breadcrumb .tag-drop {
        display: none;
    }
}

Showing and hiding the tag selector in the composer with JS:

<script type="text/discourse-plugin" version="0.8.23">
    // show tag chooser in the composer only when necessary
    const discourseComputed = require("discourse-common/utils/decorators").default;
    const EmberObject = require("@ember/object").default;
    function toggleTagChooser(display = "hide") {
        if (display == "show") {
            document.getElementsByClassName("mini-tag-chooser")[0].style.display = "block";
            document.getElementsByClassName("reply-area")[0].classList.add("with-tags");
            return;
        }
        // Verify the existence of the tag choser
        let tagChoser = document.getElementsByClassName("mini-tag-chooser");
        if(tagChoser.length > 0) {
            tagChoser[0].style.display = "none";
            document.getElementsByClassName("reply-area")[0].classList.remove("with-tags");
        }
        return;
    }
    api.modifyClass('controller:composer', {
        @discourseComputed("model.category", "model.tags", "lastValidatedAt")
        tagValidation(category, tags, lastValidatedAt) {
            // custom code to toggle the tag choser
            toggleTagChooser("hide");
            if(category != null) {
                if (
                    category.allow_global_tags == true ||
                    category.allowed_tag_groups.length > 0 ||
                    category.allowed_tags.length > 0
                ) {
                    toggleTagChooser("show");
                }
            }
            // end of the custom code
            const tagsArray = tags || [];
            if (this.site.can_tag_topics && !this.currentUser.staff && category) {
                // category.minimumRequiredTags incorporates both minimum_required_tags, and required_tag_groups
                if (category.minimumRequiredTags > tagsArray.length) {
                    return EmberObject.create({
                        failed: true,
                        reason: I18n.t("composer.error.tags_missing", {
                            count: category.minimumRequiredTags,
                        }),
                        lastShownAt: lastValidatedAt,
                    });
                }
            }
        }
    });
</script>
1 Like

Exactly what I was looking for. Great.

It is especially wrong in the current core code to show the tag selection box when there are no tags for a user to select from for a category. The last code solves this UX problem. It should be in core this way @team

In addition, there should be two standard texts for the tag selection drop-down:

“optional tags”

and one if tags are mandatory (and available for a user) for a category

“select at least X tags”

By creating a tag group, you can make it mandatory to use one of a set of tags (“buy” or “sell”) on all posts in a category.

1 Like

Still the tag selection box shows up with “optional tags” in the composer for a category with a mandatory tag group and shows up on categories where no tags are available for the user in another category. This is quite confusing from an UX perspective. The user has to hit the error pop-up before he understands what is required.

I know, I just want to somehow hide the tag feature for the categories tags are not available in, as @Terrapop explains.

When tags are disabled in the site settings, the category selector is on the same line as the topic title:

With my workaround, there a bit of a waste of space since the category selector always lies under the topic title:

In one hand, changing the category selector position when we select a category depending on whether it requires tags could be a wrong UX thing. On the other hand, we rarely use the category selector more than once.

1 Like

I’m not so much concerned about the waste of space but found another “issue” with your otherwise very nice JS code. Maybe you can look into this?

We have tag groups that are “staff only” (e.g. hidden tags and system tags) and mandatory tag groups for users per category. Both are linked via “Restrict these tag groups to this category”.

image

Now, this code only checks if a category allows tags or tag_groups.length>0 or allowed_tags >0 but unfortunately this is always the case as we have those tag groups that are only for staff in the restricted tag groups, too.

Could the code be changed to appreciate the user context and if there are really tags for this specific user available?

 if(category != null) {
                if (
                    category.allow_global_tags == true ||
                    category.allowed_tag_groups.length > 0 ||
                    category.allowed_tags.length > 0
                ) {
                    toggleTagChooser("visible");
                }
            }

Should be possible to count only public in the array category.allowed_tag_groups.length for non-staff users (or are just the names and not the states available in the array?):

public_category.allowed_tag_groups = [public_tag_group.name, staff_only_tag_group.name]
private_category.allowed_tag_groups = [private_tag_group.name, staff_only_tag_group.name]

Ok, update:

In our case, we will inspect the names in allowed_tag_groups and exclude them from the array if currentUser is not staff. But that is a dirty workaround, as I don’t know how to add the user context here (or if this even possible given the current core code, don’t think so).

             var non_staff_tag_groups = category.allowed_tag_groups.filter(filterHidden);
                function filterHidden(value) {
                  if(value.toLowerCase().indexOf("hidden") === -1 && value.toLowerCase().indexOf("system") === -1) return value;
                }
                if (
                    category.allow_global_tags == true ||
                    (category.allowed_tag_groups.length > 0 && this.currentUser.staff) ||
                    (non_staff_tag_groups.length > 0 && !this.currentUser.staff) ||
                    category.allowed_tags.length > 0
                ) {
                    toggleTagChooser("visible");
                }
            }

But this is a dirty hack, the whole tag dropdown in composer should be more contextual via core and should consider all the cases above.

2 Likes

Sorry, it seems that I didn’t see your message in 2020!

Anyway, my code broke after a recent Discourse update. Here’s a working update (the CSS doesn’t change though):

Target the category classes on which you want to hide the tag selector:

body:not(.category-other-languages):not(.category-trading-post) {
    .category-breadcrumb .tag-drop {
        display: none;
    }
}

The script that will dynamically toggle the tag selector:

<script type="text/discourse-plugin" version="0.8.23">
    // show tag chooser in the composer only when necessary
    const discourseComputed = require("discourse-common/utils/decorators").default;
    const EmberObject = require("@ember/object").default;
    function toggleTagChooser(display = "hide") {
        if (display == "show") {
            document.getElementsByClassName("mini-tag-chooser")[0].style.display = "block";
            document.getElementsByClassName("reply-area")[0].classList.add("with-tags");
            return;
        }
        // Verify the existence of the tag choser
        let tagChoser = document.getElementsByClassName("mini-tag-chooser");
        if(tagChoser.length > 0) {
            tagChoser[0].style.display = "none";
            document.getElementsByClassName("reply-area")[0].classList.remove("with-tags");
        }
        return;
    }
    api.modifyClass('controller:composer', {
        @discourseComputed("model.category", "model.tags", "lastValidatedAt")
        tagValidation(category, tags, lastValidatedAt) {
            // custom code to toggle the tag choser
            toggleTagChooser("hide");
            if(category != null) {
                if (
                    category.allow_global_tags == true ||
                    category.allowed_tag_groups.length > 0 ||
                    category.allowed_tags.length > 0
                ) {
                    toggleTagChooser("show");
                }
            }
            // end of the custom code
            const tagsArray = tags || [];
            if (this.site.can_tag_topics && !this.currentUser.staff && category) {
                // category.minimumRequiredTags incorporates both minimum_required_tags, and required_tag_groups
                if (category.minimumRequiredTags > tagsArray.length) {
                    return EmberObject.create({
                        failed: true,
                        reason: I18n.t("composer.error.tags_missing", {
                            count: category.minimumRequiredTags,
                        }),
                        lastShownAt: lastValidatedAt,
                    });
                }
            }
        }
    });
</script>

about that…it’s been 6 years dude :sweat_smile:

I think tag group functionality these days, gives you a close experience.

You would tie a tag group to a bunch of categories and then disallow creation of new tags.

Not sure about pr-welcome here, removing it, desired change needs to be properly specified. This I guess is asking for a checkbox in the category settings, but even that needs a bunch of thinking, is it ticked by default, is the extra setting just plain confusing to lots of people?