# Embed widget within text in a topic

**URL:** https://meta.discourse.org/t/embed-widget-within-text-in-a-topic/206919
**Category:** Support
**Created:** [October 24, 2021, 10:22pm UTC](https://meta.discourse.org/t/embed-widget-within-text-in-a-topic/206919 "2021-10-24T22:22:54Z")
**Posts on this page:** 1
**Showing post:** 2

<div class="post-metadata">

### Author: ![Johani](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/johani/32/176920_2.png) [@Johani](https://meta.discourse.org/u/Johani)
#### Post date: [October 25, 2021, 5:52pm UTC](https://meta.discourse.org/t/embed-widget-within-text-in-a-topic/206919/2 "2021-10-25T17:52:48Z")

</div>

Discourse is a single-page application. The issue you’re encountering happens because the script you’re using is not aware of that. When you visit the homepage - or any other page - in Discourse, you get something like this.

```xml
<html>
  <head>
    head content including your script
  </head>
  <body>
    <section id="main">
      page content
    </section>
  </body>
</html>

```

When you navigate to another page, the only thing that gets reloaded is the content inside

```plaintext
<section id="main">

```

So, the DOM has changed, and your custom script doesn’t fire again. If you try to visit the topic page directly, you’ll see that it loads fine.

 ![image](https://global.discourse-cdn.com/meta/original/3X/8/6/8612f70904b566085cd21cc47395b0c8de5919e6.jpeg).

So, now the question is how to get it to work with Discourse.

The plugin-api has a method that you can use to “decorate” posts.

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

You can use that to fire third-party scripts when a post is rendered.

Here’s the code you would need. Add this to the `common > header` tab of your theme.

```xml
<script type="text/discourse-plugin" version="0.8">
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

const loadScript = require("discourse/lib/load-script").default;
const { iconHTML } = require("discourse-common/lib/icon-library");

const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
  class: "woxo-preview-icon"
});

const previewMarkup = () => {
  const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
  return markup;
};

// create a post decorator
api.decorateCookedElement(
  post => {
    const woxoWidgets = post.querySelectorAll("div[data-mc-src]");

    if (woxoWidgets.length) {
      woxoWidgets.forEach(woxoWidget => {
        if (post.classList.contains("d-editor-preview")) {
          woxoWidget.innerHTML = previewMarkup();
          return;
        }

        loadScript(WOXO_SCRIPT_SRC).then(() => {
          const script = document.head.querySelector(
            `script[src*="cdn2.woxo.tech"]`
          );
          script.dataset.usrc = "";
          window.MC.Loader.init();
        });
      });
    }
  },
  { id: "render-woxo-widgets" }
);
</script>

```

You would then need to add a couple of domains for [CSP](https://meta.discourse.org/t/mitigate-xss-attacks-with-content-security-policy/104243). Add these to your

```plaintext
content_security_policy_script_src

```

site setting

```plaintext
https://*.woxo.tech/
https://us-central1-core-period-259421.cloudfunctions.net/availableComponentTracks

```

finally, you’d need to add a little bit of CSS for the static composer preview

This goes in the `common > CSS` tab of your theme.

```scss
.woxo-preview {
  height: 400px;
  width: 100%;
  background: var(--primary-low);
  display: flex;
  align-items: center;
  justify-content: center;
  .woxo-preview-icon {
    font-size: var(--font-up-4);
    color: var(--primary-high);
  }
}

```

Then you can just add

```xml
<div data-mc-src="f4b43a8f-c188-4f80-8206-36d9f7529f13#instagram"></div>

```

to any post, and the widgets will render and be fully functional.

 ![image](https://global.discourse-cdn.com/meta/original/3X/3/1/31abaa7518700a0812a8916fb6f47ab71805a69b.jpeg)

If you look at the JavaScript, you’ll notice that it has two options at the very top.

```javascript
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";

```

Change `WOXO_SCRIPT_SRC` to the src that woxo gives you. It should be the same for all the embeds you create.

Change `PREVIEW_ICON` to the name of the icon you want to use in the composer preview. Running this code in the composer is a bit expensive, so the composer has a static preview that looks like this.

 ![image](https://global.discourse-cdn.com/meta/original/3X/b/e/be04c2e6ec6bcf429f4ca544b37d6af8be5cef89.png)

The icon you pick will show in the middle.

Here’s a commented copy of the code if you want to follow along with what’s happening

> **commented code**
>
> ```javascript
> <script type="text/discourse-plugin" version="0.8">
> // options
> const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
> const PREVIEW_ICON = "heart";
> 
> // we use the Discourse Load script lib to ensure scripts are loaded
> // properly. Don't worry, this is smart enough to not duplicate the script
> // if it's already loaded
> const loadScript = require("discourse/lib/load-script").default;
> 
> // we load the Discourse Icon HTML function to get the svg for the icon
> // we want to use in the static composer preview
> const { iconHTML } = require("discourse-common/lib/icon-library");
> 
> // setup the composer preview icon
> const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
> class: "woxo-preview-icon"
> });
> 
> // create a helper function for the composer preview markup
> const previewMarkup = () => {
> const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
> 
> return markup;
> };
> 
> // create a post decorator
> api.decorateCookedElement(
> post => {
> // does this post have woxo widgets?
> const woxoWidgets = post.querySelectorAll("div[data-mc-src]");
> 
> // Yes, so let's do some work.
> if (woxoWidgets.length) {
> // for each woxo widget
> woxoWidgets.forEach(woxoWidget => {
> // if it's a composer widget, swap it out for a static preview and
> // quit early
> if (post.classList.contains("d-editor-preview")) {
> woxoWidget.innerHTML = previewMarkup();
> return;
> }
> 
> // if it's not in the composer, load the woxo script.
> loadScript(WOXO_SCRIPT_SRC).then(() => {
> // The woxo script is very strange. It won't work unless the script
> // tag has an empty data-usrc attribute. So, let's add it
> const script = document.head.querySelector(
> `script[src*="cdn2.woxo.tech"]`
> );
> script.dataset.usrc = "";
> 
> // everything is ready, let's call the init method in the woxo script
> window.MC.Loader.init();
> });
> });
> }
> },
> // add an id to the decorator to avoid memory leaks
> { id: "render-woxo-widgets" }
> );
> 
> </script>
> 
> ```

---

_[View the full topic](https://meta.discourse.org/t/embed-widget-within-text-in-a-topic/206919)._
