# Insert a glimmer component after first post

**URL:** https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282
**Category:** Development
**Created:** [April 10, 2024, 6:19pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282 "2024-04-10T18:19:56Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 10, 2024, 6:19pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/1 "2024-04-10T18:19:56Z")

</div>

I’ve got a glimmer component. It’s working. But I need it to go after the first post in a topic. There’s no plugin outlet there.

I did figure out how to insert some text in the `innerHTML` of the `<article>` tag, and that puts that text where I want, but there doesn’t seem to be a way to do that with a component.

Am I missing something?

I looked at how the adplugin inserts ads between posts, but I couldn’t quite make sense of it.

```plaintext
export default {
  name: "initialize-ad-plugin",
  initialize(container) {
    registerWidgetShim(
      "after-post-ad",
      "div.widget-connector",
      hbs`<PostBottomAd @model={{@data}} />`
    );

    withPluginApi("0.1", (api) => {
      api.decorateWidget("post:after", (helper) => {
        return helper.attach("after-post-ad", helper.widget.model);
      });
    });

....

```

---

<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: [April 10, 2024, 6:31pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/2 "2024-04-10T18:31:08Z")

</div>

> [@pfaffman](#):
>
> There’s no plugin outlet there.

Let’s add one! Where would you like it?

(there are legacy ways to accomplish what you’re doing, but the’ll break when we modernise the topic view. If we add a plugin outlet, it’ll be much more future-proof)

---

<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: [April 10, 2024, 7:06pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/3 "2024-04-10T19:06:10Z")

</div>

This outlet would match the functionality of `decorateWidget("post:after`, which is what the adplugin uses:

[https://github.com/discourse/discourse/pull/26592](https://github.com/discourse/discourse/pull/26592)

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 10, 2024, 7:24pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/4 "2024-04-10T19:24:54Z")

</div>

That’s awesome! Whine and you shall receive!

Actually, I “know” that it’s “easy” to add plugin outlets, but when I have sort-of known how to add them, it was in an `hbs` file.

Is that going to be after _every_ post? So I’ll need to figure out some magic to make it be after only the first one?

`article:after` is what I had contrived at some point in my previous attempts.

---

<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: [April 10, 2024, 7:30pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/5 "2024-04-10T19:30:32Z")

</div>

> [@pfaffman](#):
>
> I’ll need to figure out some magic

The post is passed as one of the outlet arguments, so you can check post.post\_number == 1

> [@pfaffman](#):
>
> Whine and you shall receive!

Haha! Always happy to help with these kinds of questions. Much better for everyone if we can get themes and plugins using standard APIs like this rather than widget workarounds (which will be deprecated in the not-too-distant future).

> [@pfaffman](#):
>
> when I have sort-of known how to add them, it was in an `hbs` file.

Yeah that’s fair. Adding them inside widgets is a headache on the core side. But from the theme/plugin side it should be super clean 🤞

* * *

I’ll try and figure out those test failures and get the PR merged tomorrow. (Looks like the extra html element is messing with some fragile selectors in the qunit tests)

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 10, 2024, 7:33pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/6 "2024-04-10T19:33:28Z")

</div>

> [@david](#):
>
> The post is passed as one of the outlet arguments, so you can check post.post\_number == 1

Aha! `@outletArgs={{hash post=@data.post}}`. There’s a reasonable chance I can figure out how to do that. 🙂

Thanks again!

---

<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: [April 15, 2024, 1:08pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/7 "2024-04-15T13:08:51Z")

</div>

I’m afraid I may have been a bit over-optimistic here @pfaffman, sorry! The PR I made would introduce a new wrapper `<div>` between every single post, even if the outlet was not being used. That’s not really something we want to do.

There may be ways to avoid the wrapper… but nothing simple which we can do immediately.

So I think the best immediate solution for you is going to be copying the adplugin implementation which you referenced in the OP.

> [@pfaffman](#):
>
> but I couldn’t quite make sense of it

Essentially:

1. Create a component (Glimmer or classic, doesn’t matter) which renders whatever you want

2. Use `registerWidgetShim` to make that component available as a widget. The adplugin example is creating a widget called “after-post-ad”, which renders the `PostBottomAd` component. It is passing all of the widget attributes `(@data)` into the `@model` argument of the component.

3. Use `api.decorateWidget` to render your new widget shim in the `post:after` position. In your case, since you only want it on the first post, you could do something like

When we eventually glimmer-ify the topic page, you’ll need to remove the widget shim/decoration, and replace it with a plugin outlet. That should be pretty easy, since all your display logic in the component will be reusable in the plugin outlet.

Let us know how you get on! Happy to help with any follow-up questions - I know there are a lot of moving parts here.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 16, 2024, 3:20pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/8 "2024-04-16T15:20:31Z")

</div>

I’m so very close!

The only issue is that the component needs `currentUser` and I can’t figure out how to pass it. Here’s what doesn’t work.

```plaintext
import { hbs } from "ember-cli-htmlbars";
import { withPluginApi } from "discourse/lib/plugin-api";
import Site from "discourse/models/site";
import { registerWidgetShim } from "discourse/widgets/render-glimmer";
import Banner from "../components/banner";

export default {
  name: "initialize-banner-widget",
  initialize(container) {
    registerWidgetShim(
      "geo-banner-widget",
      "div.widget-connector",
      hbs`<Banner @currentUser={{currentUser}} />`
    );

    // withPluginApi("0.1", (api) => {
    // console.log("doing plugin");
    // api.decorateWidget("post:after", (helper) => {
    // return helper.attach("geo-banner-widget", helper.widget.model);
    // });
    // });

    withPluginApi("0.1", (api) => {
      const currentUser = container.lookup("service:current-user");
      api.decorateWidget("post:after", (helper) => {
        console.log(`decorate widget ${currentUser.username}`, );
        if(helper.widget.model.post_number === 1){
          return helper.attach("geo-banner-widget", { currentUser });
        }
      });
    });
  },
};

```

---

<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: [April 16, 2024, 3:38pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/9 "2024-04-16T15:38:05Z")

</div>

In your `Banner` component, you can inject the `currentUser` service like this:

```javascript
class Banner extends Component {
  @service currentUser;
}

```

then you won’t need to pass it through from the widget.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 16, 2024, 4:09pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/10 "2024-04-16T16:09:30Z")

</div>

I knew it was stupid to pass the `currentUser`, but I couldn’t figure that out!

The other bit, in the unlikely event that anyone else finds this useful, is

```plaintext
import Service, { inject as service } from "@ember/service";

```

```javascript
import { hbs } from "ember-cli-htmlbars";
import { withPluginApi } from "discourse/lib/plugin-api";
import { registerWidgetShim } from "discourse/widgets/render-glimmer";

export default {
  name: "initialize-banner-widget",
  initialize(container) {
    registerWidgetShim(
      "geo-banner-widget",
      "div.widget-connector",
      hbs`<Banner/>`
    );

    withPluginApi("0.1", (api) => {
      api.decorateWidget("post:after", (helper) => {
        const currentUser = container.lookup("service:current-user");
        if(helper.widget.model.post_number === 1){
          return helper.attach("geo-banner-widget");
        }
      });
    });
  },
};

```

---

<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: [April 16, 2024, 4:54pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/12 "2024-04-16T16:54:48Z")

</div>

> [@pfaffman](#):
>
> The other bit, in the unlikely event that anyone else finds this useful, is
> 
> ```plaintext
> import Service, { inject as service } from "@ember/service";
> 
> ```

Yup!

In this case, I don’t think you’ll need to import the `Service` class. That would only be needed if you were creating your own Service. You just need the `service` injection decorator.

And in the latest version of Discourse/Ember, it can be simplified even further to avoid needing the ‘inject as’ alias. Ember now make the injection decorator available directly as `service`.

```plaintext
import { service } from "@ember/service";

```

(but the old `{ inject as service }` still works, and I’m not aware of any plans to deprecate it in Ember)

EDIT: But maybe I can use decorateWidget instead of a plugin outlet. . .

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [April 16, 2024, 6:03pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/13 "2024-04-16T18:03:07Z")

</div>

> [@david](#):
>
> , I don’t think you’ll need to import the `Service` class.

That’s what the linter thinks too 🙂

> [@david](#):
>
> ```plaintext
> import { service } from "@ember/service";
> 
> ```

I like that better. The house ads plugin still does it the old way. 🙂

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [May 16, 2024, 6:03pm UTC](https://meta.discourse.org/t/insert-a-glimmer-component-after-first-post/303282/14 "2024-05-16T18:03:27Z")

</div>

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