How to create a new topic button with category and topic template


#1

I’m looking at the following theme as a reference.

My goal is to find a way to put up a secondary new topic button that shows up for members of a specific group. This group has access to a private area in the forum and I’d like to be able to have the button in question start a new topic in that area of the forum regardless of their current page. I’m also looking to use a topic template or similar boilerplate functionality with this button. I think I’ve figured out how to selectively add the button based off the primary group class on the body, but I’m not quite familiar enough at the moment to insert some boilerplate text(or topic template) into new topics started with this secondary button. Anyone have any pointers?


(Joe) #2

This is possible. You need to first prep your category with a topic template. Go the category you want to use and edit its topic template like so:


Then find out what the id of the category is. You can do this by going to your.site.com/categories.json

Here on meta it looks like this:

There’s probably a better way to find the categoryId but this works as needed here.

Now, let’s say I want to use the #bug category. The Id for it would be “1” based on /categories.json

For #feature, it would be “2” and so on.


Now that you have the id and the category has a topic template, you can copy the code from the theme, make a few modifications, and add it to a separate theme component.

I’v done the modifications here so you can just copy this and change the values as needed:

<script type="text/discourse-plugin" version="0.8.18">
api.decorateWidget("header-buttons:after", helper => {
  if (Discourse.User.current()) {
      
    // edit these two to your liking
    var $ntb_text = "button text",
      $ntb_icon = "plus",
      
      // no need to edit these
      $ntb_icon_class = ".fa-" + $ntb_icon,
      $ntb_button_class = "btn btn-default btn btn-icon-text",
      $ntb_button_helper = "button#new-create-topic-custom",
      $ntb_icon_helper =
        "i.fa" + $ntb_icon_class + ".d-icon .d-icon-" + $ntb_icon,
      $ntb_label_helper = "span.d-button-label";

    const createTopicCustom = function() {
      const container = Discourse.__container__;
      const Composer = require("discourse/models/composer").default;
      const controller = container.lookup("controller:navigation/category");
      const composerController = container.lookup("controller:composer");

      composerController.open({
        action: Composer.CREATE_TOPIC,
        draftKey: Composer.DRAFT,

        // set the category id below
        // see site.com/categories.json
        // for refrence
        categoryId: 3
      });
    };

    return helper.h(
      $ntb_button_helper,
      {
        className: $ntb_button_class,
        title: $ntb_text,
        onclick: createTopicCustom
      },
      [helper.h($ntb_icon_helper), helper.h($ntb_label_helper, $ntb_text)]
    );
  }
});

</script>

This goes into the </head> section under Common.


Once you’re done, you should have something like this: (I added margins with CSS)

Clicking the new button will open the composer with the category you selected and the topic template for the category will be present as well.

I’m assuming that would be all you need here based on:


(Biscuit) #3

Thanks Joe. I’ve already found a use for your instructions above. Very helpful.

Do you know how to create a PM, rather than posting into a category?

eg: Is there a CategoryID specifically for PM messages?


(Joe) #4

For a PM you’d need to set a few of the composer options differently.

Something like this:

(Same as above, in a theme component in the </head> section)

<script type="text/discourse-plugin" version="0.8.18">
api.decorateWidget("header-buttons:after", helper => {
  if (Discourse.User.current()) {
    
    // edit these two to your liking
    var $ntb_text = "New Personal Message",
      $ntb_icon = "heart",
        
      // no need to edit these
      $ntb_icon_class = ".fa-" + $ntb_icon,
      $ntb_button_class = "btn btn-default btn btn-icon-text",
      $ntb_button_helper = "button#new-create-topic-custom",
      $ntb_icon_helper =
        "i.fa" + $ntb_icon_class + ".d-icon .d-icon-" + $ntb_icon,
      $ntb_label_helper = "span.d-button-label";

    const createPM = function() {
      const container = Discourse.__container__,
        Composer = require("discourse/models/composer").default,
        composerController = container.lookup("controller:composer");

      composerController.open({
        action: Composer.PRIVATE_MESSAGE,

        // 1- set recipients (Case Sensitive) or comment the line below
        usernames: "discobot,john,mike",

        // 2- set title or comment the line below
        topicTitle: "Title",

        // 3- uncomment the line below to set a "template" for PM.
        // Not really recommended will
        // override any drafts everytime the 
        // button is pressed 
        
        // topicBody: "placeholder content",

        // no need to change these
        archetypeId: "private_message",
        draftKey: Composer.NEW_PRIVATE_MESSAGE_KEY,

      });
    };

    return helper.h(
      $ntb_button_helper,
      {
        className: $ntb_button_class,
        title: $ntb_text,
        onclick: createPM
      },
      [helper.h($ntb_icon_helper), helper.h($ntb_label_helper, $ntb_text)]
    );
  }
});
</script>

Obviously, if you plan on using all three buttons you can reduce the size of the code quite drastically because most of it is shared by all three, but I kept things separate because some might just want to use one and not all three.

What this will do is add a button to the header like so:

Clicking the button will open the composer and the fields will be pre-filled with whatever you chose:

I already left a comment in the code about setting any placeholder content in the body for PMs using this method. It’s not recommended unless you have a very specific template. This will override any previously saved PM drafts everytime you use the button.

That’s why it’s “off” by default in the code above.

I’ve tested this a bit and have not seen any problems. If you encounter anything let me know.


Toggle menu in Composer
(Biscuit) #5

Love it. Worked perfectly. Thanks Joe, you’re awesome!

I noticed the user names are case sensitive. If a username’s case is wrong, the name appears in the recipient list, but the PM won’t send. Suggest you add this to your comments: -

    // 1- set recipients (Case Sensitive) or comment the line below 
    usernames: "discobot,john,mike",

(Jerome Spaargaren) #6

Hi @Johani - thank you, I have implemented this, but a bit too successfully!

Would it be possible to make a new personal message header button appear only selectively for those who have access to personal messaging? New users by default don’t have access to PM so should not see this button…

We have set the site setting (for our TL0, TL1 and TL2 users (who therefor are restricted from personal messaging))

Thanks again,


(Joe) #7

Hi @jerry0

Yes, that is possible!

One way to do this is to look up the current user’s trust level and use that as a base to determine whether or not to create the PM button.

You would use something like this:

<script type="text/discourse-plugin" version="0.8.18">
// no need to edit these
const container = Discourse.__container__,
  controller = container.lookup("controller:application"),
  trust = controller.get("currentUser.trust_level");

api.decorateWidget("header-buttons:after", helper => {
  // change desired trust level here
  if (Discourse.User.current() && trust >= "2") {
    // edit these two to your liking
    var $ntb_text = "New Personal Message",
      $ntb_icon = "heart",
      // no need to edit these
      $ntb_icon_class = ".fa-" + $ntb_icon,
      $ntb_button_class = "btn btn-default btn btn-icon-text",
      $ntb_button_helper = "button#new-create-topic-custom",
      $ntb_icon_helper =
        "i.fa" + $ntb_icon_class + ".d-icon .d-icon-" + $ntb_icon,
      $ntb_label_helper = "span.d-button-label";

    const createPM = function() {
      const Composer = require("discourse/models/composer").default,
        composerController = container.lookup("controller:composer");

      composerController.open({
        action: Composer.PRIVATE_MESSAGE,

        // 1- set recipients (Case Sensitive) or comment the line below
        usernames: "discobot,john,mike",

        // 2- set title or comment the line below
        topicTitle: "Title",

        // 3- uncomment the line below to set a "template" for PM.
        // Not really recommended will
        // override any drafts everytime the
        // button is pressed

        // topicBody: "placeholder content",

        // no need to change these
        archetypeId: "private_message",
        draftKey: Composer.NEW_PRIVATE_MESSAGE_KEY
      });
    };

    return helper.h(
      $ntb_button_helper,
      {
        className: $ntb_button_class,
        title: $ntb_text,
        onclick: createPM
      },
      [helper.h($ntb_icon_helper), helper.h($ntb_label_helper, $ntb_text)]
    );
  }
});
</script>

How to make a theme component for TL-based banner
(Jerome Spaargaren) #8

Well that is fab. I will have to wait to get back from my travels tomorrow but will try it out then. Thanks!


(Jerome Spaargaren) #9

I’ve now tried it out and it works well. Many thanks.


(Mikhail Fortuin) #10

Is it only possible to do this if u are able to code?


(Jerome Spaargaren) #11

Um, no - I really can’t :grinning:… just followed the instructions above…


(Christoph) #12

Would it be possible to change the button text for the default + New Topic button based on which category you’re browsing?