Hide subcategories without hiding their topics in topic list?

Hey guys

Is there any way to “hide” subcategories from topic lists and display the parent categories below the topic title instead?

My desired result is a root category with n subcategories. Those subcategories are not supposed to be displayed in the front end. They are only used to restrict access to the posts based on group membership.

In the topic list I would like to display the parent category below the topic title instead of the subcategory.

I thought about using tags, but unfortunately I can’t restrict access to the topics that way.

1 Like

The template for items in the topic list only shows the link to the topic’s category, like this:
{{category-link topic.category}}

So you would need to modify this template to show links to the parent category:

{{#if topic.category.parentCategory}}
  {{category-link topic.category.parentCategory}}
{{else}}
  {{category-link topic.category}}
{{/if}}

But if you only want this to happen for a specific parent category, you’d need to add more logic. I don’t know what would be the recommended way to do that, registering a handlebars helper?

Another approach could be to always show both category and parent links and then hide the ones you don’t want with CSS.

2 Likes

I haven’t looked, but I think you should be able to hide them with CSS.

1 Like

Do I need to modify the template for this approach as well? I could not find such a site setting in my admin.

The parent categories are not on the default template, so yes, I guess you have to modify the template. At least I’m not aware of a lighter approach to achieve that.

There’s no site setting to modify templates, I’ll send you the code to try it out by DM.

1 Like

In general, you should avoid full template overrides since they require maintenance - you have to run a diff and check what’s changed if a Discourse update breaks your theme.

What you can do, is take a step back and modify the data that gets passed to the template instead.

The topic-list-item is an ember component, so you can use api.modifyClass to make the changes you want

For example, here’s a snippet that will show the parent category badge in subcategory topics under the title. If the topic is in the main category, the code has no effect.

<script type="text/discourse-plugin" version="0.8">
  const { on } = require("discourse-common/utils/decorators");

  // parent category ids
  const targetCategoryIds = [9, 15, 50];

  const useParentCategory = function () {
    const parentCategory = this.attrs.topic.category.parentCategory;
    const switchToParent = parentCategory && targetCategoryIds.includes(parentCategory.id)

    if (switchToParent) {
      this.attrs.topic.set("category", parentCategory);
    }
  };

  api.modifyClass("component:topic-list-item", {
    @on("didReceiveAttrs")
    setCategory() {
      useParentCategory.call(this);
    }
  });

  api.modifyClass("component:latest-topic-list-item", {
    @on("didReceiveAttrs")
    setCategory() {
      useParentCategory.call(this);
    }
  });
</script>
4 Likes

This is awesome!

Is there any way to limit it to one or more specific categories?

Two different ways to address this based on what you’re trying to accomplish. What’s the desired result?

  1. all subcategories under parent category “foo” should have this behavior.
  2. some subcategories under different parent categories should have this behavior.

@Johani

This one is what we are looking for

I edited the snippet above to reflect that change. All you need to do is to add the parent category ids to the targetCategoryIds array. You can find the category id by visiting the category page and checking the URL .

 https://meta.discourse.org/c/support/6

“6” at the end of the URL above is the id for the support category here on Meta.

3 Likes

Thanks for sharing this @Johani ! Just getting started with ember… you guys are really helpful! :pray: :relaxed:

2 Likes

That’s amazing! Thx a lot for the quick help.

2 Likes

That’s great to hear!

Two Thumbs Up

It just takes a little bit of getting used to. If anything in the codebase is not clear, feel free to create a topic in the #dev category and tag me.

2 Likes

This is really awesome. Thanks for this and thanks to those who’re giving you the time to do it.

:+1:

2 Likes

@Johani Where exactly do I put this code snippet?
I tried putting it into the </head> and header part of my theme component where I store all my CSS. But then the topic list is cut off exactly where the first affected topic from the subcategory is supposed to be listed.

1 Like

Yeah, there was an issue with how the category was set that I missed locally. I edited the snippet above, and it should work now.

The snippet above allows you to set the categories you want this to work on. If you want it to work on all categories, you’d use something like this.

<script type="text/discourse-plugin" version="0.8">
  const { on } = require("discourse-common/utils/decorators");

  const useParentCategory = function () {
    const parentCategory = this.attrs.topic.category.parentCategory;

    if (parentCategory) {
     this.attrs.topic.set("category", parentCategory);
    }
  };

  api.modifyClass("component:topic-list-item", {
    @on("didReceiveAttrs")
    setCategory() {
      useParentCategory.call(this);
    }
  });

  api.modifyClass("component:latest-topic-list-item", {
    @on("didReceiveAttrs")
    setCategory() {
      useParentCategory.call(this);
    }
  });
</script>
2 Likes

Thx @Johani for your help, reallu appreciate it!

1 Like