Creating Discourse based documentation pages

Our standard model for community built documentation is for the documentation pages to exist as topics in a Discourse forum, and then to make use of our discourse-docs Flask module to display the content pulled from Discourse within our websites.

This model is explained in more detail here.

An example of this model can be seen at https://docs.snapcraft.io (soon to be moved to https://snapcraft.io/docs).

Creating the Discourse topics

First, decide which Discourse installation this documentation should live in. This may be a dedicated Discourse for your project’s community, or it may be e.g. https://discourse.ubuntu.com/ or https://discuss.kubernetes.io/.

The category

First, create a category in a public Discourse installation somewhere. This category is usually called “docs”, but if that’s too generic it can be something else, e.g. “microk8s-docs”.

The index topic

Now edit the main topic of the category that should have been created automatically. We’ll refer to this as the “index topic”. The contents of this topic should have the following structure:

{{ homepage content }}

# Navigation

{{ navigation content - e.g.:

## Heading 1

- [Installation guide](/t/installation-guide/747)
}}

# URLs

{{ pretty URL mapping table - e.g.:

[details=Mapping table]
| Topic | Path |
| ----- | ---- |
| /t/installation-guide/747 | /docs/installation |
[/details]
}}

# Redirects

{{ redirects table - probably empty initially, e.g.:

[details=Mapping table]
| Path | Location |
| ---- | -------- |
[/details]
}}

So it should contain the following top-level headings:

  • “Navigation” - This should be a list of links to topic pages, and will form the left-hand navigation on the website, for navigating between topics.
  • “URLs” - This is a mapping table to provide prettier URLs for topics. In the example used above, the “/t/installation-guide/747” topic would be displayed at /docs/installation on the actual documentation site
  • “Redirects” - A similar mapping table for allowing some URLs to redirect elsewhere. If a URL used in the “URLs” mapping table changes, the old URL should be redirected to the new one using this table.

Creating topics

Now go ahead and create your documentation pages as topics in the same category as the index topic. The topics should link to each other using internal Discourse links of the form /t/{slug}/{id} like normal.

Importing topics

If you have existing documentation in a Markdown format that was parsed with our legacy documentation-builder tool, then our Discoursifier tool can help to import these pages into a Discourse topic.

Downloading topic content

If you need to download documentation from Discourse, either one-by-one or the entire category, @howbazaar has created a basic tool to help with this called discli. E.g., to download all topics in a topic:

$ wget https://raw.githubusercontent.com/howbazaar/discli/master/discli
$ chmod +x discli
$ ./discli init https://discourse.EXAMPLE.COM MY_USERNAME MY_API_KEY
Values set: {'api-key': 'MY_API_KEY', 'url': 'https://discourse.EXAMPLE.COM', 'username': 'MY_USERNAME'}

$ ./discli get_posts_in_category docs
Getting page 1 of results...
Saving 747-installation-guide.md
...

Displaying Discourse documentation on a website

To display the documentation on a Flask-based website, you should add our canonicalwebteam.discouse-docs module.

You’ll first need the IDs of your docs category and your index topic. You can get the ID of the category by visiting /categories.json - e.g. https://discourse.example.com/categories.json in your browser. The index topic ID is the number after the slug in the topic’s URL - e.g. if the URL is https://discourse.example.com/t/product-documentation/25 then the topic ID is 25.

First, add it to requirements.txt, and then add the following to your app.py - assuming your Discourse URL is https://discourse.example.com, you category ID is 5 and your topic ID is 25, and you want it hosted under /docs:

from canonicalwebteam.discourse_docs import DiscourseDocs, DiscourseAPI

app = Flask("myapp")

DiscourseDocs(
    api=DiscourseAPI(base_url=https://discourse.example.com),
    index_topic_id=25,
    category_id=5,
    document_template="document.html",  # optional
    url_prefix="/docs"  # optional
).init_app(app)

You should then build the documentation template in templates/document.html similarly to how it’s been built for https://docs.snapcraft.io/ - see template here. Important features of this implementation:

  • It uses the same wrapping templates (header and footer) as the main site
  • It includes a search box at the top specifically for the docs
  • It includes JavaScript to highlight the active page in the left navigation