Beginner's Guide to Creating Discourse Plugins Part 1: Creating a basic plugin

That’s odd because the error reported for the Topic Ratings plugin was server side, not client side!

The issue is probably the load order of your initializer. You aren’t supplying one, so it’s up to Ember to decide when the initializer should be loaded, and you might be depending on something that isn’t initialized yet.

You might want to try adding after: 'inject-objects' or maybe after: 'message-bus' and try again.

If that doesn’t work I might have to install it locally and try myself :slight_smile:


Thanks. I tried those hooks, but neither worked.

By trial and error (i.e. successively checking out older commits), I’ve narrowed down my issue to this merge by @tgxworld:

Prior to that merge commit, the ComposerController.reopen function in my initialize function works fine in the initializers folder. After that commit my initialize function has to be in pre-initializers for the ComposerController.reopen function to work.

I’ll investigate this a bit more later today or tomorrow.


I actually ran into issues related to the same thing in my new ES6 branch.

The problem is that the details plugin and poll builder were calling lookup instead of lookupFactory, which was causing a new controller to be created after it was already decorated with new stuff.

In my branch I’ve fixed it by replacing with lookupFactory. It should be merged in on Monday. But if you want to before that, feel free to update to lookupFactory locally :slight_smile:


UPDATED - see bottom of post

Apologies in advance - n00b here.

I’m on a Mac and love the Docker deployment mechanism for Discourse. I was hoping I’d be able use this when developing a plugin. I tried using a “volume” to link my fledgling plugin from my Mac filesystem into the docker container like so:

## The Docker container is stateless; all data is stored in /shared
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log
  - volume:
      host: /Users/chris/Development/discourse-plugin-stripe
      guest: /var/www/discourse/plugins/discourse-plugin-stripe

I thought this might allow me to edit plugin code in an IDE on my Mac, while running Discourse in Docker to test it as I code.

However, when I tried ./launcher rebuild app I got a load of permissions errors which prevented the rebuild:

I, [2016-07-06T21:06:08.196890 #14]  INFO -- : > cd /var/www/discourse && chown -R discourse /var/www/discourse
chown: changing ownership of '/var/www/discourse/plugins/discourse-plugin-stripe/.git/objects/5e/1422c9c3f1ddaae47b5b1b597bc80748611993': Permission denied
chown: changing ownership of '/var/www/discourse/plugins/discourse-plugin-stripe/.git/objects/6c/4fb1c84c54a20a0d50facf10d4a18582956116': Permission denied

The perms for these files on my Mac are chris:staff -r--r--r--:

root:/var/discourse $ ls -la /Users/chris/Development/discourse-plugin-stripe/.git/objects/5e/1422c9c3f1ddaae47b5b1b597bc80748611993
-r--r--r--  1 chris  staff  614 Jul  6 12:47 /Users/chris/Development/discourse-plugin-stripe/.git/objects/5e/1422c9c3f1ddaae47b5b1b597bc80748611993

UPDATED: I changed the volume to:

  - volume:
      host: /Users/chris/Development/discourse-plugin-stripe
      guest: /var/discourse-plugins/discourse-plugin-stripe

Then I added a step to the plugin setup commands:

    - exec:
        cd: $home/plugins
          - git clone
          - git clone
          - ln -snf /var/discourse-plugins/discourse-plugin-stripe discourse-plugin-stripe

This has got me further - I’m now able to rebuild the app.

1 Like

I just made my first plugin and ./launcher rebuild app took a good 4-5 minutes to run. Is there any way I can edit the “live” plugin code (js/css) just to test things out without having to rebuild the whole thing?

You need to install development environment: Beginners Guide to Install Discourse on Ubuntu for Development


Cheers. solved here: Install Plugins in Discourse

Docker = Production. Vagrant = Dev.


I am able to create plugin in development, it works fine. Thanks.
But I don’t see a way to install other’s plugin in development
So first question is how can I fork someone’s plugin in development and then build on top of that(hope copy paste that repo is not the recommended way)?
Second question is, it seems my created plugin is part of my repo, is there a way to create a separate github repo for the plugin automatically which others can directly use to install?

I have a preferred method to do this. First, I have a ~/code directory where I have all my git projects. So I check out discourse and the plugin in that directory so it’s something like this:



Then, within the ~/code/discourse/plugins folder I create a symlink to the plugin:

$ cd ~/code/discourse/plugins
$ ln -s ~/code/discourse-some-plugin .

Then for good measure:

$ cd ~/code/discourse
$ rm -rf tmp
$ bundle exec rails server

Now you can fork the plugin in ~/code/discourse-some-plugin, make pull requests or whatever you want. It’ll be used by discourse.


I am really confused by your documentation. You have a new pluginapi great! but no real example. All I want is to load a an Javascript and I can’t find a working example anywhere. After following the old guide, assets are not importing. New guide, doesn’t exist. Perhaps someone would be kind enough to walk us through this. I have no problems doing this in rails myself but I dont want to break future updates.All I wanted to do is load a 3rd party script and execute it.

1 Like

Have you checked the source code from some of the existing plugins in the plugin category?

Wading through those plugins to figure out which one might include an appropriate example is not a trivial task. And you won’t necessarily know until you install a plugin whether it actually works with the new system.

For example my plugin needs to be moved to #plugin:broken-plugin.

It’d be really great if someone could fix Pirate Speak such that it’d work with the new plugin interface.

I pointed out that the plugin tutorial also doesn’t work, best I can tell and that the brand new plugin interface post from July 13 should be archived.

Hey, @erlend_sh, maybe you have some ideas here.


Fair point. Been there, done that. More times than I can count.

Not that it could be enforced or that any kind of formal “rules” could be established, but I guess if plugin authors included some kind of “summary” it might help those that have difficulty “reading” code.

rm -rf tmp
Bad idea. Never ask newbies to do that. You will just end up breaking running processes.

Actually, AFAIK rm -rf tmp (or at least rm -rf tmp/cache) can be necessary

Otherwise the cached server side assets will be used and sometimes changes to the plugin being developed will not take effect.

What alternative approach do you recommend?


Yes, exact files and directory or tmp must be specified. I am not sure what those are in this case but /tmp is shared by several system processes. I cam check today and post back with a list.

But you took the above out of context. It is telling you to delete tmp out of the ~/code/discourse folder. It didn’t say to delete /tmp.


+1 for the above concerns. IMO it’s not good enough to provide a collection of plugins in github as documentation. As a new Discourse plugin developer, I have no idea which of these plugins represents a good “canonical” example for doing things. And some of the plugins are really sophisticated - full of magic naming conventions and ES6 wiring that’s unfamilar to a traditional JS developer.

It’s so hard to identify magic naming conventions when all you have is a load of pre-made plugins to go on. Which words are keywords, and which words are arbitrary?

A few more canonical examples would go a long way.

For an experienced plugin developer these examples would take minutes to write.

For a brand new plugin developer these examples would save hours of frustrated clicking around.

A few questions I have in particular as a n00b discourse plugin developer:

  • Why are we using Vagrant for dev and Docker for prod?
  • How do I write a simple ES6 unit test? (not a whole acceptance test that requires a running Discourse instance). I got lost in a mire of gulp/grunt/phantomjs/babel etc. Surely there’s an easier way?
  • Is there a browser that I can run ES6 code in directly? If so, how? I know ES6 is still pretty new, but I can’t believe how little documentation exists on the web for this seemingly simple task
  • What’s the canonical way of writing a plugin that does a simple “replace this [keyword]params[/keyword] with something based on params”? I’ve tried a few different ways - none of them feel right

This does not need to be the case for development.

For example, I have a GitHub repository “test-plugin”
In my localhost Docker install I enter the app and edit the containers/app.yml file to install the plugin.

If all goes well the plugin doesn’t break the forum and I can then test it.

But before doing that, I test in my localhost Vagrant install to help ensure the plugin code is relatively bug free. I find it easier to work with Vagrant when my code causes a fatal error that I want to recover from.

1 Like

Platform: Windows10

  • As mentioned above, bundle exec rails s -b works instead of just bundle exec rails server.
  • rm -rf tmp appears to work for PC on Windows PowerShell too.
  • For my case, as far as the “basic-plugin” mentioned in this post is concerned, I was able to see the changes in the plugin without re-starting the server. Just reloaded the browser tab and the changes were visible. Tested this on Chrome v53.0.2785.101 (latest at the moment). However, the tab does become unresponsive the first time it is reloaded after the change to the plugin has been saved, and has to be “killed”. The only thing different that I have from the default Vagrant environment is that I am using an updated gems version (v2.6.6). Is this behaviour to not restart the server, normal for such cases?
1 Like