How to manually add contents to pluginOutlet after ajax call? And how to rerender or refresh a pluginOutlet?

Correct. There are two ways to go about it…

  1. You can make your customization a widget, and then mount the widget in the plugin outlet like this:

    {{mount-widget widget="widget-name"}}

    You can see an example of how a widget is created in Discourse, for example the home logo: discourse/home-logo.js at 2dbcea9eeeb816dda347027497b3a49634ef851f · discourse/discourse · GitHub

    In a theme you’d add your widget-name.js file to a javascripts/discourse/widgets directory

    There’s more about widgets in A tour of how the Widget (Virtual DOM) code in Discourse works, but note that we’re going to gradually phase out widgets so anything you learn in this process won’t be useful long-term.

  2. Keep your widget decorator as-is, and create a separate Ember component that does what you want in the plugin outlet. We’ve been phasing out widgets in favor of Ember components (which is what most of Discourse is built on).

    This process would look like:

    1. Create a component JS and HBS (template) file in your theme’s javascripts/discourse/components directory.
    • component-name.js

    • component-name.hbs

    1. Build your Ember component… unfortunately this step is essentially “learn Ember” (Ember Guides) … but I think this might give you a rough idea to start:
    • In component-name.js:
    import Component from "@glimmer/component";
    import { tracked } from "@glimmer/tracking";
    import { action } from "@ember/object";
    const endpoint = settings.site_navigation_links_endpoint;
    export default class ComponentName extends Component {
      @tracked navLinks = null;
      async fetchNavLinks() {
       try {
          const response = await fetch(endpoint);
          const data = await response.json(); // assuming this is json
          this.navLinks = data;
        } catch (error) {
          console.error("Failed:", error);
    • In component-name.hbs:
    <div {{did-insert this.fetchNavLinks}}>
     {{#each this.navLinks as |link|}}
       <a href={{link.anchor}}>{{link.title}}</a>

    This will call the fetchNavLinks action whenever the component is inserted (in this case, when you visit the Discourse site and the app renders). Whenever navLinks is updated, the content of the component will update because it’s a tracked property.

    If you want to update the links more often than on component render you’ll need to add some more logic to the JS here… checking if the current route (page) meets certain conditions for example.

    1. This component would be added to a plugin outlet by adding it to the outlet in javascripts/discourse/connectors/below-site-header/my-component-connector.hbs:
    <ComponentName />