# Using Plugin Outlet Connectors from a Theme or Plugin

**URL:** https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727
**Category:** Developer Guides
**Tags:** how-to, code
**Created:** [August 31, 2015, 7:35am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727 "2015-08-31T07:35:05Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [August 31, 2015, 7:35am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/1 "2015-08-31T07:35:05Z")

</div>

Discourse includes hundreds of Plugin Outlets which can be used to inject new content or replace existing contend in the Discourse UI. ‘Outlet arguments’ are made available so that content can be customized based on the context.

# Choosing an outlet

To find the name of a plugin outlet, search Discourse core for “`<PluginOutlet`”, or use the [plugin outlet locations](https://meta.discourse.org/t/plugin-outlet-locations-theme-component/100673) theme component. (e.g. `topic-above-posts`).

# Wrapper outlets

Some outlets in core look like `<PluginOutlet @name="foo" />`. These allow you to inject new content. Other outlets will ‘wrap’ an existing core implementation like this

```hbs
<PluginOutlet @name="foo">
  core implementation
</PluginOutlet>

```

Defining a connector for this kind of ‘wrapper’ outlet will replace the core implementation. Only one active theme/plugin can contribute a connector for a wrapper plugin outlet.

For wrapper plugin outlets, you can render the original core implementation using the `{{yield}}` keyword. This can be helpful if you only want to replace the core implementation under certain conditions, or if you would like to wrap it in something.

# Defining the connector

Once you’ve chosen an outlet, decide on a name for your connector. This needs to be unique across all themes / plugins installed on a given community. e.g. `brand-official-topics`

In your theme / plugin, define a new `.gjs` connector with a path formatted like this:

> 🎨 `{theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs`
> 
> 🔌 `{plugin}/assets/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs`

The content of these files will be rendered as an Ember Component. For general information on Ember and the `.gjs` format, check out [the Ember guides](https://guides.emberjs.com/release/components/).

For our hypothetical “brand official topics” connector, the file might look like

```gjs
<template>
  <div class="alert alert-info">
    This topic was created by a member of the
    <a href="https://discourse.org/team">Discourse Team</a>
  </div>
</template>

```

> [@](#):
>
> > **ℹ️ Legacy wrapper elements**
> >
> > In the past, connectors were authored using `.hbs` files. When these files are used, the plugin outlet may automatically introduce a wrapper element. The element type is defined by `@connectorTagName` on the `<PluginOutlet />`.
> > 
> > Modern `.gjs`-based connectors have full control of their DOM. No automatic wrapper element will be introduced.

# Using outlet arguments

Plugin Outlets provide information about the surrounding context via `@outletArgs`. The arguments passed to each outlet vary. An easy way to view the arguments is to add this to your template:

```hbs
{{log @outletArgs}}

```

This will log the arguments to your browser’s developer console. They will appear as a `Proxy` object - to explore the list of arguments, expand the `[[Target]]` of the proxy.

In our `topic-above-posts` example, the rendered topic is available under `@outletArgs.model`. So we can add the username of the team member like this:

```gjs
<template>
  <div class="alert alert-info">
    This topic was created by
    {{@outletArgs.model.details.created_by.username}}
    (a member of the
    <a href="https://discourse.org/team">Discourse Team</a>)
  </div>
</template>

```

> [@](#):
>
> > **ℹ️ Legacy ways to access arguments**
> >
> > In many Plugin Outlets, by default it is possible to access arguments using `{{argName}}` or `{{this.argName}}`. For now, this still works in existing outlets.
> > 
> > New plugin outlets (with `@defaultGlimmer={{true}}`) render connectors as ‘template only glimmer components’, which do not have a `this` context. Eventually, existing Plugin Outlets will also be migrated to this pattern. The `@outletArgs` technique is best because it will work consistently in both classic and glimmer plugin outlets.

# Adding more complex logic

Sometimes, a simple template is not enough. To add Javascript logic to your connector, upgrade your `.gjs` file to export a class-based component. This functions just the same as any other component definition, and can include service injections.

In our `topic-above-posts` example, we may want to render the user differently based on the ‘prioritize username in ux’ site setting. The `.gjs` file might look something like this:

`.../connectors/topic-above-posts/brand-official-topic.gjs`:

```gjs
import Component from "@glimmer/component";
import { service } from "@ember/service";

export default class BrandOfficialTopics extends Component {
  @service siteSettings;

  get displayName() {
    const user = this.args.outletArgs.model.details.created_by;
    if (this.siteSettings.prioritize_username_in_ux) {
      return user.username;
    } else {
      return user.name;
    }
  }

  <template>
    <div class="alert alert-info">
      This topic was created by
      {{this.displayName}}
      (a member of the
      <a href="https://discourse.org/team">Discourse Team</a>)
    </div>
  </template>
}

```

> [@](#):
>
> > **ℹ️ Legacy ways to define complex logic**
> >
> > In older versions of Discourse, connectors were defined as a `.hbs` template plus an adjacent `.js` file, and it wasn’t possible to export a custom component definition. Instead, you could export an object with `setupComponent(args, component)` and `teardownComponent(component)` functions. These older techniques are not officially deprecated yet, but we recommend switching to a single `.gjs` file with a class-based component going forwards.

# Conditional rendering

If you only want your content to be rendered under certain conditions, it’s often enough to wrap your template with a handlebars `{{#if}}` block. If that’s not enough, you may want to use the `shouldRender` hook to control whether your connector template is rendered at all.

Firstly, ensure you have a class-based `.gjs` connector as described above. Then, add a `static shouldRender()` function. Extending our example:

```gjs
import Component from "@glimmer/component";

export default class BrandOfficialTopics extends Component {
  static shouldRender(outletArgs, helper) {
    const firstPost = outletArgs.model.postStream.posts[0];
    return firstPost.primary_group_name === "team";
  }
  // ... (any other logic)

  <template>
    {{! ... }}
  </template>
}

```

Now the connector will only be rendered when the first post of the topic was created by a team member.

`shouldRender` is evaluated in a Glimmer autotracking context. Future changes to any referenced properties (e.g. `outletArgs`) will cause the function to be re-evaluated.

> [@](#):
>
> > **ℹ️ Legacy shouldRender implementations**
> >
> > **Autotracking:** Before Discourse 3.1, `shouldRender` would only be evaluated during initial render. Changes to referenced properties would not cause the function to be re-evaluated.
> > 
> > **Non-class syntax:** For now, defining a `shouldRender` function in a plain (non-class) javascript object is still supported, but we recommend moving towards a class-based or templateOnly-based syntax going forward.

# Introducing new outlets

If you need an outlet that doesn’t yet exist, please feel free to make a pull request, or open a topic in #Development.

* * *

This document is version controlled - suggest changes [on github](https://github.com/discourse/discourse/blob/main/docs/developer-guides/docs/03-code-internals/14-plugin-outlet-connectors.md).

---

<div class="post-metadata">

### Author: ![Firepup650](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/firepup650/32/465200_2.png) [@Firepup650](https://meta.discourse.org/u/Firepup650)
#### Post date: [December 7, 2023, 8:31pm UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/33 "2023-12-07T20:31:30Z")

</div>

> [@Discourse](#):
>
> In older versions of Discourse, it wasn’t possible to export a custom component definition. Instead, you could export an object with `setupComponent(args, component)` and `teardownComponent(component)` functions. This older technique is not officially deprecated yet, but we recommend switching to the new component-export approach going forwards.

This _is_ now depreciated, right?  
`Deprecation notice: Defining connector classes via registerConnectorClass is deprecated. See https://meta.discourse.org/t/32727 for more modern patterns. [deprecation id: discourse.register-connector-class-legacy]`

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [December 7, 2023, 8:51pm UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/34 "2023-12-07T20:51:42Z")

</div>

That’s right; you can use [`api.renderInOutlet`](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L982-L1008) instead. 🙂

[https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L982-L1008](https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L982-L1008)

---

<div class="post-metadata">

### Author: ![Firepup650](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/firepup650/32/465200_2.png) [@Firepup650](https://meta.discourse.org/u/Firepup650)
#### Post date: [December 8, 2023, 2:48am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/35 "2023-12-08T02:48:33Z")

</div>

Except a bit more complicated than that I think 😅  
[https://github.com/Firepup6500/discourse-custom-profile-link/blob/master/common/head\_tag.html](https://github.com/Firepup6500/discourse-custom-profile-link/blob/master/common/head_tag.html)

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [December 8, 2023, 3:34am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/36 "2023-12-08T03:34:02Z")

</div>

Don’t worry; I will see what I can do to help you later (I need to sleep right now). 😄

---

<div class="post-metadata">

### Author: ![Firepup650](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/firepup650/32/465200_2.png) [@Firepup650](https://meta.discourse.org/u/Firepup650)
#### Post date: [December 8, 2023, 3:35am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/37 "2023-12-08T03:35:09Z")

</div>

Thanks! (Sorry about the code being an mess, I just wanted it to work when I last touched it 😅)

---

<div class="post-metadata">

### Author: ![cogdog](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/cogdog/32/116536_2.png) [@cogdog](https://meta.discourse.org/u/cogdog)
#### Post date: [January 11, 2024, 5:16pm UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/40 "2024-01-11T17:16:41Z")

</div>

I’m in a bit over my head here, I got a notice for my component used in my theme’s HEAD file. I’m not sure how to rewrite with `api.renderInOutlet`.

```plaintext
  const ajax = require('discourse/lib/ajax').ajax;
  const Topic = require('discourse/models/topic').default;
  // We're using ajax and the Topic model from Discourse

  api.registerConnectorClass('above-main-container', 'featured-topics', {
    // above-main-container is the plugin outlet,
    // featured-topics is your custom component name

    setupComponent(args, component) {

   // rest of code follows

```

I guess tried replacing `api.registerConnectorClass` with `api.renderInOutlet` but it borked. I’m not really expert in theme coding here. Thanks for any help.

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [January 11, 2024, 6:14pm UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/41 "2024-01-11T18:14:04Z")

</div>

You can see an example here:

> <https://github.com/discourse/discourse-stat-banner/blob/main/javascripts/discourse/initializers/stat-banner.js#L5>

`StatBanner` is a native class defined in `components` directory:

> <https://github.com/discourse/discourse-stat-banner/blob/main/javascripts/discourse/components/stat-banner.gjs>

In your case, that would be `api.renderInOutlet("above-main-container", YourClass)`

I don’t think you can do it in the HEAD file. You should [split your code into multiple files](https://meta.discourse.org/t/split-up-theme-javascript-into-multiple-files/119369).

I encourage you to use [Discourse Theme CLI](https://meta.discourse.org/t/install-the-discourse-theme-cli-console-app-to-help-you-build-themes/82950) as it will be much easier to develop a Theme component!

Is your Theme Component public?

---

<div class="post-metadata">

### Author: ![NateDhaliwal](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/natedhaliwal/32/313494_2.png) [@NateDhaliwal](https://meta.discourse.org/u/NateDhaliwal)
#### Post date: [October 13, 2024, 4:19am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/42 "2024-10-13T04:19:47Z")

</div>

Is there a way to get the current outlet in my `.js` file?

---

<div class="post-metadata">

### Author: ![merefield](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/merefield/32/176214_2.png) [@merefield](https://meta.discourse.org/u/merefield)
#### Post date: [October 13, 2024, 7:46am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/43 "2024-10-13T07:46:14Z")

</div>

I don’t think that’s possible.

It used to be possible to inspect `parentView` in Classic Components.

But that property has been deprecated.

[Get glimmer component access to stuff from the parent - #5 by david](https://meta.discourse.org/t/get-glimmer-component-access-to-stuff-from-the-parent/316898/5)

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [October 14, 2024, 10:03am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/44 "2024-10-14T10:03:36Z")

</div>

What do you mean by “get the current outlet”? You want the name of the outlet? Or something else?

---

<div class="post-metadata">

### Author: ![NateDhaliwal](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/natedhaliwal/32/313494_2.png) [@NateDhaliwal](https://meta.discourse.org/u/NateDhaliwal)
#### Post date: [October 14, 2024, 10:28am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/45 "2024-10-14T10:28:51Z")

</div>

I found a solution for my problem ([here](https://meta.discourse.org/t/cannot-put-the-template-in-the-desired-outlet/330650/6)), but it was something like this:

- Create `.hbs` and `.js` files for 3 different outlets.
- In each JS file, check if the outlet it is using is the setting `banner_location` value.
- If it is, show the banner. If not, hide the banner.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [October 14, 2024, 10:37am UTC](https://meta.discourse.org/t/using-plugin-outlet-connectors-from-a-theme-or-plugin/32727/46 "2024-10-14T10:37:16Z")

</div>

Cool! It looks like you settled on using the `api.renderInOutlet`, with a dynamic value for the outlet name :chefs_kiss:
