Adding plugin-outlets using a theme

themes

(Sam Saffron) #1

In Plugin System Upgrades @eviltrout introduced a system for extending Discourse HTML using plugin outlets.

Plugin outlets are tagged areas in our application that allow you to inject a template. The template has access to the backing controller so it can be dynamic.

Our customization system in /admin/customize/css_html allows you to define custom CSS and HTML.

When injecting HTML into your page you can also inject templates, this gives you a very simple mechanism for injecting content into various plugin outlets.

To inject into an outlet

  1. Find out the outlet name, you can do so by digging through our source or using the plugin outlet location plugin.

  2. Define a handlebars template in the </head> section.

An example of this is:

<script type='text/x-handlebars' data-template-name='/connectors/header-after-home-logo/add-header-links'>
  {{#unless showExtraInfo}}
       <a class="nav-link " href="http://google.com" target="_blank">My Site</a>
  {{/unless}}
</script>

This will result in adding a navigation link in the header that only exists when the header is not in extra info mode (which happens when you scroll down a topic)

:mega: Naming is critical

Your template must have the data-template-name attribute identify the outlet. It is named like so:

/connectors/OUTLET-NAME/UNIQUE-ID

If you stray from that naming your template will not be picked up or injected.

TODO (add screenshots)

Using this technique even business and standard customers can heavily extend Discourse without needing plugins.

:warning: When possible always prefer solutions that inject into a plugin outlet, over solutions that override an entire template, that allows your customisation to be far more robust and “future proof”.


How to add header menu links
What is the best way to integrate member applications?
Group Semantics
How do I add a message to the Categories page?
Add HTML (Link) Next To Logo
Custom header navigation?
How to modify the header HTML, but still remaining the default founctions
Adding a billing section in the member section
Adding a billing section in the member section
Why can't I modify the topic list template?
Native theme support
Add link to external SSO profile to profile page
Discourse view file update does not reflect in browser
Discourse view file update does not reflect in browser
Add likes and views to search display
Most “traditional” or classic forum Category listing
(Adam Capriola) #2

This is awesome. Here’s a small bit to add an icon to your home page in the navigation block. I’ve been wanting to try this out for a while.

In </head>:

<script type='text/x-handlebars' data-template-name='/connectors/header-before-notifications/home-page-link'>
    <a class="icon" href="http://example.com/" title="visit our home page"><i class="fa fa-home"></i></a>
</script>

In CSS:

.home-page-link {
    float: left;
}
.home-page-link .fa-home {
    padding: 0;
}
.d-header .icons .unread-private-messages {
    left: 122px;
}
.d-header .icons .flagged-posts {
    left: 80px;
}

Icon for chat Discord
(Daniela) #3

Perfect, but how do you do with users without login?


(Adam Capriola) #4

Good point. I’m not sure. Here’s the file where the plugin outlet being utilized located:

https://github.com/discourse/discourse/blob/tests-passed/app/assets/javascripts/discourse/templates/header.hbs

header-after-home-logo could possibly be used instead but I’m not sure what’s possible with CSS, whether you’d be able to get the icon positioned as desired. Another outlet might be needed.


(Tom Newsom) #5

I was playing with this last night and found that an element with float:right inserted at header-after-home-logo would end up on the right of the existing icons. Not ideal, but if it’s a Home icon you’re inserting, that might be the best place for it. (I haven’t tested, but because this outlet is outside of the #if currentUser statement, it should appear for everyone)

CSS:

.home-page-link {
    float: right;
}
.home-page-link .fa-home {
    padding: 5px;
    color: #999999;
}

/head

<script type='text/x-handlebars' data-template-name='/connectors/header-after-home-logo/home-page-link'>
  <a class="icon" href="http://www.yourdomaingoeshere.org/" title="visit our home page"><i class="fa fa-home"></i></a>
</script>

(Krischan) #6

Perfect, thanks! Is there a way to show stuff at such an outlet, if the user is not logged in only? And vice versa: Only if the user is logged in? Thanks!


(Alan Tan) #7

you can use Discourse.User.current() in your conditions. :smile_cat:


(Marco) #8

How can insert two icons?


(Krischan) #9

Thanks a lot! Could you show me how an example code would look like with this condition? My programming skills are very modest. Cheers!


(Alan Tan) #10

Here you go :smile:


(Krischan) #11

Sorry, I meant in the </head> section context. Is there something like

<script type='text/x-handlebars' data-template-name='/connectors/header-after-home-logo/add-header-links'>
  if user logged in
       <a class="nav-link " href="http://google.com" target="_blank">My Site</a>
  if user not logged in
       <a class="nav-link " href="http://google.com" target="_blank">Your Site</a>
</script>

Thanks so much!


(Alan Tan) #12
<script type='text/x-handlebars' data-template-name='/connectors/header-after-home-logo/add-header-links'>
  {{#if currentUser}}
     <a class="nav-link " href="http://google.com" target="_blank">My Site</a>
  {{else}}
     <a class="nav-link " href="http://google.com" target="_blank">Your Site</a>
  {{/if}}
</script>

Try this :smile:


Conditions in custom HTML
Hiding a custom HTML element when user is logged in
(Krischan) #13

Sorry to bother you again: Ist there a way to differentiate between members of groups, as in “A member of group X sees HTML 1, member of group Y sees HTML 2 …”?


(Steven Greco) #14

Does anyone know how I would pull a custom user field? Tried using the following code from the user.hbs template but cant seem to pull the custom user fields.

<script type='text/x-handlebars' data-template-name='/connectors/user-card-post-names/gamertags'>
            {{#if publicUserFields}}
              <div class="public-user-fields">
                {{#each uf in publicUserFields}}
                  {{#if uf.value}}
                    <div class="public-user-field">
                      <span class="user-field-name">{{uf.field.name}}</span>:
                      <span class="user-field-value">{{uf.value}}</span>
                    </div>
                  {{/if}}
                {{/each}}
              </div>
            {{/if}}
</script>

I have also tried using custom.user_field_1 at the field name as well. No Dice.

Edit: I know there is data here, as I am setting them with SSO and they do show up on the users profile. Trying to get them to show on the usercard as well.


(Thomas Davis) #15

I have this same question.

Does anyone know how to validate group membership in a template condition?


(Steven Greco) #16

If the data I want to pull is in another controller (UserController) from the one I want the data to display (UserCardController). Can I do this all within the site customization screen, or would I need to create a plugin and extend the UserCardController to include the data from UserController? What would would be the best way to pull it?

Thanks


(Robin Ward) #17

What if the user had never visited the UserController? The card can be shown in many places.

What is the piece of data you want to pull?


(Steven Greco) #18

I want to pull the publicUserField array that is created in userController. I am guessing if they never visited userController then I would need to create the array myself.


(Robin Ward) #19

Yeah part of that field can be generated anywhere (the information about custom fields is in our Site object) but the other part requires the user_fields values which you’d have to make sure are available on the card somehow. I am not sure off the top of my head when the user card loads in the data that such fields are present.


(Pad Pors) #20

does anyone know how to put an icon next to the search button?