Plugin for seamlessly embedding Discourse in a page as comments


(Dashamir Hoxha) #1

The only way that I have seen for embedding comments in a static site through Discourse is the one described in this blog: Embedding Discourse in Static Sites - Evil Trout’s Blog
However I find that approach a bit complicated, and having many assumptions/restrictions that don’t fit many users. At least it does not work for me, it does not work the way that I want.

A better approach in my opinion would be to build a plugin that works as described below.

On the page that embeds the comments we include code like this (not generated by the plugin):

<div id="discourse-comments"></div>
<script type="text/javascript">
var discourseUrl = "http://discuss.btranslator.org/";
function showDiscourseTopic(topic) {
  var comments = document.getElementById('discourse-comments');
  var iframe = document.getElementById('discourse-embed-frame');
  if (iframe) { iframe.remove(); }
  iframe = document.createElement('iframe');
  iframe.src = discourseUrl + '/t/' + topic + '/?embedded=true';
  iframe.id = 'discourse-embed-frame';
  iframe.width = '100%';
  iframe.height = '500px';
  iframe.frameBorder = '0';
  iframe.scrolling = 'yes';
  comments.appendChild(iframe);
};
showDiscourseTopic('create-at-least-5-public-topics-and-30-public-posts-to-get-discussion-started');
</script>
  1. One of the problems with the code above is that it does not set the height of the iFrame to match the height of the content. I think that iFrame Resizer can be used to fix it. This requires the script iframeResizer.contentWindow.min.js to be included in the page contained within the iFrame. This can be done by the plugin, but only when the GET parameter ?embedded=true is passed to the url.

  2. Another problem is that it displays extra content, which are useful in a full page display but are useless in an embedded display. This can be fixed by adding extra CSS code, which are included by the plugin only when the GET parameter ?embedded=true is defined, and which hides the parts of the page that are irrelevant for the embedded case. As an example see the difference between https://btranslator.org/vocabulary/ICT_sq and https://btranslator.org/vocabulary/ICT_sq?display=iframe . The second case is more suitable to be displayed inside an iFrame.

  3. An extra functionality that is important for seamless comment integration (at least for my case), is that if the current page has no comments, the corresponding discourse topic should not exist and should not be created. Maybe the plugin can detect automatically that the requested topic does not exist and should just display a Reply/Comment input box. When the first comment is submitted, the topic should be created automatically and the first comment appended to it. Or maybe this issue can be solved by the javascript that is embedded on the page, using the API.

I could have tried to build this plugin myself, but I am not familiar with RoR and with the Discourse details, so I need some help. From what I have seen around (in other discussions) at least the first 2 steps should not be very difficult. But maybe the last step is not too difficult either.


(Dashamir Hoxha) #3

I have started to implement such a plugin:

But when I do ./launcher rebuild app I get this error message:

NameError: undefined local variable or method `params’ for #Plugin::Instance:0x007f9b25dd3278

Any idea on how to fix it?


(Dashamir Hoxha) #4

This plugin, as simple as it is, already solves the first two problems.
However I don’t know how to start with the third problem and I need some help.


(Tobias Eigen) #5

I have alot of sympathy for what you are trying to do and appreciate it! I am not a programmer though and could only help with testing. I use the @eviltrout method on kabissa.org now and it’s fine.


(Dashamir Hoxha) #6

Thanks. I am a programmer, but it is difficult for me because I am not familiar with Rails and with the implementation details of Discourse. For Discourse developers it may be very easy, like @riking, @sam, @codinghorror, @blake, etc.


(Kane York) #7

Have you read this?

Embedding Discourse in Static Sites - Evil Trout's Fishtank

Answer: “yes”


(Erlend Sogge Heggen) #8

This is a great resource if you haven’t bumped into it yet:

http://blog.discourse.org/2013/04/discourse-as-your-first-rails-app/

Improving the Discourse Embed story is always a worthy pursuit, so I hope you make some headway with this.

p.s. no need to directly mention the developers though. They keep an eye on all the threads here.

[quote=“riking, post:7, topic:28452”]
Have you read this?
[/quote]That’s the first link in this post :stuck_out_tongue:


(Dashamir Hoxha) #9

I am using the Docker installation, and I know how to develop with Docker (I am almost an expert with Docker). So, the only sentence worth taking from this article was:

Now go forth and hack — and please consider contributing any cool stuff you build back to the project as pull requests!

The problem is that I am lazy to learn Rails and Discourse internals, in order to fix a small issue.

I have already made some progress with it (see the plugin). But the remaining part seems difficult for me.


(Anonymous) #10

You have hit the Discourse wall. You’ll find many brethren there waiting for an truly extensible interface.


(Dashamir Hoxha) #11

Continuing the discussion here: Embedding Discourse in Static Sites - Evil Trout's Fishtank

I have started to build a plugin for implementing this, see: Plugin for seamlessly embedding Discourse in a page as comments
By the way, limitations that you have imposed on the forum are crippling the discussion, and I hate it. If you don’t know me, you cannot start by the assumption that I am evil. This is wrong.

I think that “lazy” topics can be implemented like this:

  1. If a topic does not exist, instead of displaying the message that topic does not exist, pretend that the topic does exist but is empty (it has no content, no comments, etc.)

  2. When a comment is submitted, check first whether the corresponding topic does exist, and if not, create it.

Which of these is impossible? Things like these can be implemented even on PHP, and I guess that Ruby and Rails are more flexible and powerful than PHP.

Of course, I can try to learn Rails, and try to implement this myself, or convince myself that this is indeed impossible. But this would take me a long time.


(Robin Ward) #12

All our settings to prevent spam and such are configurable on a forum by forum basis. You are free to turn them all off on your install. We have not found they are crippling any discussion.

I think there is a core misunderstanding how embedding topics works here. You cannot post while on the site that embeds the site. You have to go over to Discourse to the topic, then post there. There is nowhere that you can post that is not in a topic.


(Brian Adams) #13

Is it a requirement that both the blog and the discourse instance have to be using matching protocols if using the hosted instance of discourse? Both either http or https?

I’m running in to the X-Frame-Options=SAMEORIGIN permission error and from what I have read, those that have fixed it while using the hosted instance appear to have had to make the protocols match.


(Robin Ward) #14

Nope. You can have your forum on HTTPS and your comments as HTTP. If your embedding site is HTTPS and your forum isn’t, you might encounter some problem. I would double check your embeddable host setting.


(Dashamir Hoxha) #15

@badevguru I have tried this simple plugin, and it has solved the problem of X-Frame-Options=SAMEORIGIN for me: GitHub - B-Translator/discourse-allow-same-origin


(Dashamir Hoxha) #16

@eviltrout Have you tried this plugin: GitHub - B-Translator/discourse-embedded-comments: Plugin for embedding discourse inside a page as seamless comments. ? With this plugin enabled you can post while on the same page that embeds the comments.

Of course it is not perfect and needs some fixes and improvements, which are beyond my current level of Rails skills.

P.S. You also need to insert this JS code on the page that embeds the comments:

<div id="discourse-comments"></div>
<script type="text/javascript">
var discourseUrl = "http://discuss.btranslator.org/";
function showDiscourseTopic(topic) {
  var comments = document.getElementById('discourse-comments');
  var iframe = document.getElementById('discourse-embed-frame');
  if (iframe) { iframe.remove(); }
  iframe = document.createElement('iframe');
  iframe.src = discourseUrl + '/t/' + topic + '/?embedded=true';
  iframe.id = 'discourse-embed-frame';
  iframe.width = '100%';
  iframe.frameBorder = '0';
  iframe.scrolling = 'yes';
  comments.appendChild(iframe);
  iFrameResize({}, iframe);
};
showDiscourseTopic('create-at-least-5-public-topics-and-30-public-posts-to-get-discussion-started');
</script>

(Robin Ward) #17

Oops sorry, my bad I did not realize I was commenting about a different plugin to embed. My mistake!

I don’t think you will have much success with this approach. The existing iFrame embedding is custom tailored for this exact situation, and uses server side rendering rather than bootstrapping an entire ember application.


(Dashamir Hoxha) #18

I think that it already has some success (let’s say 50% success). At least you can test it and see whether you can help me complete it (right now I am stuck). It may not be so efficient due to loading the whole ember application, but some people may prefer it. For example, for my application (B-Translator) it is impossible to use your embedding solution (and this is why I am trying another path).


(Robin Ward) #19

I don’t need to test it to know that I don’t agree with the approach. It is a mistake to bootstrap the entire ember application in an iframe. You are going down a road with a world of pain. The better approach is the one currently used by the embedding, where there is a server side rendered version that is much smaller and faster to load on target sites.

I would rather extend my embedding solution to fix the things it’s missing than take this approach.


(Dashamir Hoxha) #20

I don’t know ember and I have to take your word for it. But what is wrong with it (beside any performance issues, I don’t care if loading it is delayed a bit)?

This one would be fine for me too, if you really can do it.
Than you already know what needs to be fixed, don’t you?

For my case I need something flexible like this:

showDiscourseTopic('name-of-the-topic');

where my page/application decides what is the name of the topic to be displayed. This is a blocking issue for my case. Without this I really cannot use your embedding solution or Discourse.

I also need seamless commenting, that is adding comments without having to go to the topic on Discourse. This is nice to have but not an absolute requirement.

And I need as well lazy and automatic topic creation. This is must, because the number of items that can have comments is huge, but only a few of them may actually have comments and discussions.


(Robin Ward) #21

Besides performance, it will want to load the entire site, and you only want a part of it. So you will end up spending a lot of effort making sure certain features don’t show up either via CSS or JS, and that will be an endless game of whack-a-mole.

Can you explain why this is blocking for you, when dozens of other people have not had a problem with this? Why can’t you derive a client side ID like everyone else?

Seamless commenting is not on our roadmap right now although I’d like to do it one day. Lazy topic creation is impossible without seamless commenting, as like I said you must make posts in topics.

It sounds to me like you might be happier another commenting solution if we are such a poor fit for all your requirements.