Change the default group pages to /messages


When accessing groups from the /g page, is there a way to have the group URL it points to be /g/group-slug/messages instead of /g/group-slug/members?

We’ve got several groups that are used for group messages. It would be helpful to give people one less click to reach the messages for their group. This is more important to us than the view of group members.

I know that I can do this by a direct link, but I want it to be from the /g?type=my page which is helpfully dynamic and user-centred.


They’re not regular links. They’re handled with a link-to Ember component, and there’s a little bit of routing involved.

The easiest way to do this is to hijack the click on that element and do your work there. This goes in the common > header of a theme


<script type="text/discourse-plugin" version="0.8">
  const DiscourseURL = require("discourse/lib/url").default;
  api.registerConnectorClass('group-index-box-after', 'link-to-group-inbox', {
    setupComponent(args) {
      const group = args.model;

       if (group.is_group_user && group.has_messages) {
         const groupLink = document.querySelector(`.group-box.${}`);
         const newHref = `/g/${}/messages`;

         // updates browser title and handle new tab
         groupLink.href = newHref;

         // redirect the link
         groupLink.addEventListener("click", (event) => {
         }, {once: true})

If the user is a member of the group and the group has messages, it will redirect to the inbox. Otherwise, it will fall back to the default /members page.


Wow - that is amazing!!! It works a treat. Thank you.


I’ve got a follow-on issue which I need a wee bit of help with sorry!

Several of my groups still display the /g/group-slug/messages despite not having any.

On closer inspection, they have had messages in the past, which have been converted to Topics or deleted. Data Explorer reveals that these groups have True in has_messages in the Groups table.

I’ve tried changing it for these groups via Rails but I can’t seem to achieve it:

[2] pry(main)> Group.find_by_name(“group-slug”).has_messages
=> true
[3] pry(main)> Group.find_by_name(“group-slug”).has_messages = false
=> false
[4] pry(main)> Group.find_by_name(“group-slug”).has_messages
=> true

Any suggestions short of deleting the groups and remaking them (which I’m not super keen to do)?


You only need to run this line in the rails console. It should update all the groups.

1 Like

That worked for all but two - thank you. Those last pesky two I think I’ll just have to delete and remake!

On doing this, I discovered the reason - which is a minor #bug.

When converting Group Private Messages to Topics, the invitee’s information is retained. While this is nice if the Topic is converted back, it does mean that they are counted erroneously when Group.refresh_has_messages! is run.


Is it possible to also hijack the links which you get when you click on a @mentioned group and then click through to the group? I think those are the only two ways to get to groups without resorting to URLs.

What I am now after (greedy aren’t I?) is actually to have all links to the groups behave the same as your code makes the /g page ones do.

1 Like

@Johani, is this doable? I’ve had a poke around, and it is clearly way above my pay grade.

Sure, you can try something like this in the header tab of your theme/component. I left some comments in the snippet if you want to follow along. You can delete those once you’re ready to use it.

The same rules apply. If the user is a member of the group and the group has messages, Discourse will navigate to the group inbox. Otherwise, the user will land on the member directory.

<script type="text/discourse-plugin" version="0.8">
  // Part 1: modify the path for the links in the group cards. This ensure that the link
  // title reflects where it leads and handles opening the link a new tab.
  const discourseComputed = require("discourse-common/utils/decorators").default;
  api.modifyClass("component:group-card-contents", {
    // The groupPath property is used to generate the href for the group links
    // in the group card. Let's modify it
    groupPath(group) {
      // get the default value from core
      let groupURL = this._super(...arguments);

      // if the user matches our requirment, modify the url so it goes to the inbox
      if (group.is_group_user && group.has_messages) {
        groupURL = `${groupURL}/messages/`;

      // return either the default or modified value
      return groupURL;

  // Part 2: modify in-app routing. This ensures that regular in-app navigation is 
  // handled correctly and takes the user to the group inbox if they meet the 
  // requirements
  const DiscourseURL = require("discourse/lib/url").default;
  const { groupPath } = require("discourse/lib/url");
  const { action } = require("@ember/object");

  api.modifyClass("controller:user-card", {

    // showGroup here is an action that belongs to the user-card controller. 
    // This is what gets called when you click on the group name / avatar inside group cards
    showGroup(group) {
      // call super to make sure code from core is loaded first

      // group path is a built-in Discourse url helper function
      let groupURL = groupPath(;

      // if the user matches the requirments, modify the url
      if (group.is_group_user && group.has_messages) {
        groupURL = `${groupURL}/messages/`;

      // call routeTo() with either the default or the modified groupURL 

1 Like

You are amazing! It works great for any case that uses the cards.

There is now one type of link that remains undirected: that of the group when in a Group Private Message. This is actually quite handy for navigating to the group (and thus the inbox) from a Group Message.

Screenshot 2022-01-06 15.25.38

Can we catch that in the net too do you reckon?

(BTW I’ll package this into a TC and do a topic for it once we are done so it is very accessible for others)

1 Like

Those links use a slightly different serializer - because not all the group data is needed there.

Still, you can store a filtered list of the current user’s groups on the initial page view and use those as a reference to check for membership. This information is already available in the initial payload, so there’s no overhead in terms of extra requests or anything like that. Something like this

<script type="text/discourse-plugin" version="0.8">
  const user = api.getCurrentUser();

  if (!user) {

  const userGroups = =>;

  api.reopenWidget("pm-map-user-group", {
    transform(attrs) {

      const group =;
      const isGroupUser = Object.values(userGroups).includes(;

      // {href: "/g/foo"};
      let groupURL = this._super(...arguments);

      if (isGroupUser && group.has_messages) {
        groupURL.href = `${groupURL.href}/messages/`;

      return groupURL;

Keep this snippet in its own script tags and add it to the header along with the other snippets. You keep it separate because it does a quick bail if the user is not logged in.

1 Like

:partying_face: we have arrived! It works a treat, also on mobile.

Thanks Joe for your amazing persistence. I’d better keep up my end of the bargain and get to work on that #theme-component, eh?

1 Like