Making custom changes to a raw template

Currently on our topic list pages, the avatars of the main participants in each topic are shown, along with a link to the user’s profile page. This can be seen here:


When a user is not signed in, this link will not be clickable since it would otherwise return a redirect to the login page.

The issue is that our SEO consultant has determined that these are a problem for us, and wants that profile page link to not be visible to Google at all.

There are similar issues on things like topic posts, but these were all in widgets and have been relatively easy to resolve with api.reopenWidge() and the like.

Not so with the topic list pages, where we need to change the contents of raw-templates/list/posters-column.hbr!

I’ll now describe the things I’ve tried. Feel free to skip to the end if you like and already know the answer.

At first, I tried mounting a widget as per the Beginner’s guide instructions.

<script type="text/x-handlebars" data-template-name="list/posters-column">
    <td class='posters topic-list-data'>
        {{#each posters as |poster|}}
            {{#if poster.moreCount}}
                <a class="posters-more-count">{{poster.moreCount}}</a>
            {{else}}
              {{mount-widget widget="custom-list-avatar"}}
            {{/if}}
        {{/each}}
    </td>
</script>

None of this seemed to do anything at all. Eventually I found in a theme where someone was using a .raw extension in the data-template-name value, so I assume that the guide is just out of date. It didn’t say anything about raw templates! Using .raw allows the above changes to render, except my custom widget refused to load.

This is weird, because list/posters-column is only referenced by topic-list-item.hbr, which is also a raw template, and is specifically one of the templates used in that guide. But… again I guess it’s just out of date? I eventually read somewhere that you can’t mount widgets in raw templates, so it seems that this was never going to work.

Next, discovered partials and tried using those. I figured that I might have more luck, now that those parts are not a raw template.

<script type="text/x-handlebars" data-template-name="components/custom-avatar">
    <a href="{{poster.user.path}}" data-user-card="{{poster.user.username}}" class="{{poster.extraClasses}}">{{avatar poster avatarTemplatePath="user.avatar_template" usernamePath="user.username" namePath="user.name" imageSize="small"}}</a>
</script>

<script type="text/x-handlebars" data-template-name="list/posters-column.raw">
    <td class='posters topic-list-data'>
        {{#each posters as |poster|}}
            {{#if poster.moreCount}}
                <a class="posters-more-count">{{poster.moreCount}}</a>
            {{else}}
                {{partial 'components/custom-avatar'}}
            {{/if}}
        {{/each}}
    </td>
</script>

Unfortunately, it seems that you can’t use partials in raw templates either, so that approach was a no go.

Then, I found this thread which looked like it might contain what I needed. Based on that approach, and knowing that list/topic-list-item (that calls list/posters-column) is used by the topic-list-item component, I came up with the following:

<script type="text/x-handlebars" data-template-name="list/posters-column.raw">
    <td class='posters topic-list-data'>
        {{#each posters as |poster|}}
            {{#if poster.moreCount}}
                <a class="posters-more-count">{{poster.moreCount}}</a>
            {{else}}
                {{#if hideFromAnonUser}}
                    <div data-user-card="{{poster.user.username}}" class="{{poster.extraClasses}}">{{avatar poster avatarTemplatePath="user.avatar_template" usernamePath="user.username" namePath="user.name" imageSize="small"}}</div>
                {{else}}
                    <a href="{{poster.user.path}}" data-user-card="{{poster.user.username}}" class="{{poster.extraClasses}}">{{avatar poster avatarTemplatePath="user.avatar_template" usernamePath="user.username" namePath="user.name" imageSize="small"}}</a>
                {{/if}}
            {{/if}}
        {{/each}}
    </td>
</script>

<script type="text/discourse-plugin" version="1.1.0">
    const settings = Discourse.SiteSettings;
    const user = api.getCurrentUser();
    const hideFromAnonUser = settings.hide_user_profiles_from_public && !user;
    const topicListItemComponent = require('discourse/components/topic-list-item').default;
    topicListItemComponent.reopen({
        hideFromAnonUser: function() {
            return hideFromAnonUser
        }.property()
    });
</script>

Sadly, hideFromAnonUser never appears to be visible to the raw template. Perhaps hideFromAnonUser needs to be calculated from inside the function assigned to hideFromAnonUser key? It doesn’t seem to matter. Even if I comment out the first three const assignments and just set it to return False, or add a console.log() call inside it before the return statement, I can see that the function is never executed by anything.

At this point I’m at a loss. Not having ever worked with any of this before, I feel that I’m in over my head. Maybe I’ve overlooked something, but it seems that a lot of the information is either misleading or out of date, or I’m looking in the wrong places, or otherwise just misunderstanding something.

How can I replace the <a></a> tags with <div></div> tags for avatars in the topic listing pages? Thanks.

1 Like

Hello @boltronics :wave:

This will override the list/posters-column template. It’s probably better than override the topic-list-item template.

<script type="text/x-handlebars" data-template-name="list/posters-column.hbr">
  <td class='posters topic-list-data'>
  {{#if currentUser}}
    {{#each posters as |poster|}}
      {{#if poster.moreCount}}
        <a class="posters-more-count">{{poster.moreCount}}</a>
      {{else}}
        <a href="{{poster.user.path}}" data-user-card="{{poster.user.username}}" class="{{poster.extraClasses}}">{{avatar poster avatarTemplatePath="user.avatar_template" usernamePath="user.username" namePath="user.name" imageSize="small"}}</a>
      {{/if}}
    {{/each}}
  {{else}}
    {{#each posters as |poster|}}
      <div data-user-card="{{poster.user.username}}" class="{{poster.extraClasses}}">{{avatar poster avatarTemplatePath="user.avatar_template" usernamePath="user.username" namePath="user.name" imageSize="small"}}</div>
    {{/each}}
  {{/if}}
  </td>
</script>

And you have to add some CSS too because it target a and we want it to div for anon.

Desktop / CSS

html.anon {
  .topic-list {
    .posters {
      width: 146px;
      > div {
        float: left;
        margin-right: 4px;
        &:last-of-type {
          margin-right: 0;
        }
      }
      div:first-child .avatar.latest:not(.single) {
        box-shadow: 0 0 3px 1px rgba(var(--tertiary-rgb), 0.35);
        border: 1px solid rgba(var(--tertiary-rgb), 0.5);
        position: relative;
        left: -2px;
      }
    }
  }
}
7 Likes

It’s worth noting the raw template (and the widget!) system is going away soon, but of course that doesn’t solve your immediate problem.

Just be prepared for a refactor, potentially with more tools at your disposal as Glimmer Components are likely to replace them:

6 Likes

@Don you’re amazing. I’ve tested it and it addresses my issue perfectly.

It is cheating a little by addressing the problem in a different way (I wasn’t aware of the currentUser variable being accessible from there) but I can’t argue with the results. :smile:

Thanks also @merefield for pointing out the upcoming refactor. I’ll set up a test to monitor our environment for potential regressions.

Thanks guys.

3 Likes

I am glad it works for you, however I made some correction on the post above. :slightly_smiling_face:
The posters-more-count is appears on private message topic list so it is unnecessary for anon. I removed these from template and CSS too.

3 Likes

Thanks Don. I had initially suspected that might have been the case, as per my original attempts, but I hadn’t investigated it to confirm. Good to know.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.